From ab9e4d11c1a32269b2ceb962cd777ae78ed4a026 Mon Sep 17 00:00:00 2001 From: "C. Alexander Leigh" Date: Tue, 15 Jun 2021 21:06:54 +0000 Subject: [PATCH] Moved code to mk5 codeline, introduced mk4 from a6v purple --- mk4/CVS/Entries | 28 + mk4/CVS/Repository | 1 + mk4/CVS/Root | 1 + mk4/CVS/Tag | 1 + mk4/Makefile.in | 51 + mk4/buildconf | 4 + mk4/config.guess | 1284 +++ mk4/config.sub | 1324 +++ mk4/configure.in | 27 + mk4/continuity/.cvsignore | 5 + mk4/continuity/CVS/Entries | 15 + mk4/continuity/CVS/Repository | 1 + mk4/continuity/CVS/Root | 1 + mk4/continuity/CVS/Tag | 1 + mk4/continuity/ChangeLog | 659 ++ mk4/continuity/Makefile.in | 33 + mk4/continuity/TODO | 3 + mk4/continuity/bin/.cvsignore | 2 + mk4/continuity/bin/CVS/Entries | 13 + mk4/continuity/bin/CVS/Repository | 1 + mk4/continuity/bin/CVS/Root | 1 + mk4/continuity/bin/CVS/Tag | 1 + {example => mk4/continuity/bin}/base.xml | 0 {example => mk4/continuity/bin}/beacon.xml | 0 {example => mk4/continuity/bin}/config.xml | 0 .../continuity/bin}/config.xml-dist | 0 {example => mk4/continuity/bin}/dotnet.xml | 0 {example => mk4/continuity/bin}/dynamo.xml | 0 {example => mk4/continuity/bin}/harmony.xml | 0 {example => mk4/continuity/bin}/phpdev.xml | 0 {example => mk4/continuity/bin}/radius.xml | 0 {example => mk4/continuity/bin}/ssl.xml | 0 {example => mk4/continuity/bin}/winkfep.xml | 0 mk4/continuity/config.guess | 1284 +++ mk4/continuity/config.sub | 1324 +++ mk4/continuity/configure.in | 254 + mk4/continuity/cont/.cvsignore | 1 + mk4/continuity/cont/CVS/Entries | 10 + mk4/continuity/cont/CVS/Repository | 1 + mk4/continuity/cont/CVS/Root | 1 + mk4/continuity/cont/CVS/Tag | 1 + mk4/continuity/cont/Makefile.in | 60 + mk4/continuity/cont/cdog.c | 90 + mk4/continuity/cont/continuity.c | 382 + mk4/continuity/cont/dis.c | 445 + mk4/continuity/cont/dl.c | 702 ++ mk4/continuity/cont/mmc.c | 452 + mk4/continuity/cont/tas.c | 265 + mk4/continuity/cont/xfr.c | 146 + mk4/continuity/include/.cvsignore | 1 + mk4/continuity/include/CVS/Entries | 8 + mk4/continuity/include/CVS/Repository | 1 + mk4/continuity/include/CVS/Root | 1 + mk4/continuity/include/CVS/Tag | 1 + mk4/continuity/include/config.h.in | 151 + mk4/continuity/include/continuity.h | 144 + mk4/continuity/include/csys.h | 141 + mk4/continuity/include/cwin32.h | 41 + mk4/continuity/include/mecha.h | 586 ++ .../continuity/include}/mecha_dep.h | 0 mk4/continuity/install-sh | 251 + mk4/continuity/lib/.cvsignore | 1 + mk4/continuity/lib/CVS/Entries | 4 + mk4/continuity/lib/CVS/Repository | 1 + mk4/continuity/lib/CVS/Root | 1 + mk4/continuity/lib/CVS/Tag | 1 + mk4/continuity/lib/build.mk | 173 + mk4/continuity/lib/env.mk.in | 25 + mk4/continuity/mecha/CVS/Entries | 34 + mk4/continuity/mecha/CVS/Repository | 1 + mk4/continuity/mecha/CVS/Root | 1 + mk4/continuity/mecha/CVS/Tag | 1 + mk4/continuity/mecha/Makefile.in | 31 + mk4/continuity/mecha/ast.c | 431 + mk4/continuity/mecha/b64.c | 216 + mk4/continuity/mecha/bsp.c | 294 + mk4/continuity/mecha/bus.c | 135 + mk4/continuity/mecha/crc.c | 94 + mk4/continuity/mecha/cv.c | 381 + mk4/continuity/mecha/dic.c | 134 + mk4/continuity/mecha/dyn.c | 165 + mk4/continuity/mecha/dyn.h | 22 + mk4/continuity/mecha/exp.c | 312 + mk4/continuity/mecha/fle.c | 303 + mk4/continuity/mecha/hsh.c | 837 ++ mk4/continuity/mecha/hsh_dep.c | 267 + mk4/continuity/mecha/log.c | 254 + mk4/continuity/mecha/lst.c | 701 ++ mk4/continuity/mecha/lst.h | 30 + mk4/continuity/mecha/lst_void.c | 235 + mk4/continuity/mecha/mecha.c | 9 + mk4/continuity/mecha/mem.c | 35 + mk4/continuity/mecha/net.c | 559 ++ mk4/continuity/mecha/net.h | 28 + mk4/continuity/mecha/pat.c | 120 + mk4/continuity/mecha/qry.c | 90 + mk4/continuity/mecha/rnd.c | 69 + mk4/continuity/mecha/str.c | 322 + mk4/continuity/mecha/sys.c | 618 ++ mk4/continuity/mecha/thr.c | 533 + mk4/continuity/mecha/tls.c | 231 + mk4/continuity/mecha/uid.c | 148 + mk4/continuity/mecha/utl.c | 868 ++ mk4/continuity/mecha/w32.c | 102 + mk4/continuity/mecha/xml.c | 555 + mk4/continuity/pcre/.cvsignore | 15 + mk4/continuity/pcre/AUTHORS | 6 + mk4/continuity/pcre/COPYING | 54 + mk4/continuity/pcre/CVS/Entries | 37 + mk4/continuity/pcre/CVS/Repository | 1 + mk4/continuity/pcre/CVS/Root | 1 + mk4/continuity/pcre/CVS/Tag | 1 + mk4/continuity/pcre/ChangeLog | 1320 +++ mk4/continuity/pcre/INSTALL | 185 + mk4/continuity/pcre/LICENCE | 54 + mk4/continuity/pcre/Makefile.in | 282 + mk4/continuity/pcre/NEWS | 123 + mk4/continuity/pcre/NON-UNIX-USE | 113 + mk4/continuity/pcre/README | 357 + mk4/continuity/pcre/RunTest.in | 135 + mk4/continuity/pcre/config.guess | 1400 +++ mk4/continuity/pcre/config.in | 70 + mk4/continuity/pcre/config.sub | 1469 +++ mk4/continuity/pcre/configure | 8903 +++++++++++++++++ mk4/continuity/pcre/configure.in | 189 + mk4/continuity/pcre/dftables.c | 152 + mk4/continuity/pcre/get.c | 349 + mk4/continuity/pcre/install-sh | 251 + mk4/continuity/pcre/internal.h | 662 ++ mk4/continuity/pcre/ltmain.sh | 5069 ++++++++++ mk4/continuity/pcre/maketables.c | 136 + mk4/continuity/pcre/makevp.bat | 25 + mk4/continuity/pcre/mkinstalldirs | 40 + mk4/continuity/pcre/pcre-config.in | 59 + mk4/continuity/pcre/pcre.c | 7596 ++++++++++++++ mk4/continuity/pcre/pcre.def | 22 + mk4/continuity/pcre/pcre.in | 184 + mk4/continuity/pcre/pcredemo.c | 329 + mk4/continuity/pcre/pcregrep.c | 642 ++ mk4/continuity/pcre/pcreposix.c | 301 + mk4/continuity/pcre/pcreposix.h | 88 + mk4/continuity/pcre/pcretest.c | 1421 +++ mk4/continuity/pcre/perltest | 211 + mk4/continuity/pcre/printint.c | 360 + mk4/continuity/pcre/study.c | 438 + mk4/continuity/todoc | 48 + mk4/doc/CVS/Entries | 2 + mk4/doc/CVS/Repository | 1 + mk4/doc/CVS/Root | 1 + mk4/doc/CVS/Tag | 1 + mk4/doc/standards.txt | 77 + mk4/httpclient/CVS/Entries | 3 + mk4/httpclient/CVS/Repository | 1 + mk4/httpclient/CVS/Root | 1 + mk4/httpclient/CVS/Tag | 1 + mk4/httpclient/Makefile | 11 + mk4/httpclient/httpclient.c | 115 + mk4/install-sh | 251 + mk4/lib/CVS/Entries | 3 + mk4/lib/CVS/Repository | 1 + mk4/lib/CVS/Root | 1 + mk4/lib/CVS/Tag | 1 + mk4/lib/aura/CVS/Entries | 4 + mk4/lib/aura/CVS/Repository | 1 + mk4/lib/aura/CVS/Root | 1 + mk4/lib/aura/CVS/Tag | 1 + mk4/lib/aura/Makefile | 13 + mk4/lib/aura/include/CVS/Entries | 10 + mk4/lib/aura/include/CVS/Repository | 1 + mk4/lib/aura/include/CVS/Root | 1 + mk4/lib/aura/include/CVS/Tag | 1 + {aura => mk4/lib/aura/include}/basictypes.h | 0 {aura => mk4/lib/aura/include}/iterator.h | 0 .../lib/aura/include}/list_iterator.h | 0 {aura => mk4/lib/aura/include}/memutil.h | 0 mk4/lib/aura/include/serialization.h | 30 + mk4/lib/aura/include/serializationinfo.h | 18 + mk4/lib/aura/include/stringdictionary.h | 18 + mk4/lib/aura/include/type.h | 26 + {aura => mk4/lib/aura/include}/typelocator.h | 0 mk4/lib/aura/scripts/CVS/Entries | 2 + mk4/lib/aura/scripts/CVS/Repository | 1 + mk4/lib/aura/scripts/CVS/Root | 1 + mk4/lib/aura/scripts/CVS/Tag | 1 + mk4/lib/aura/scripts/create_aura_class.pl | 138 + mk4/lib/aura/src/.cvsignore | 1 + mk4/lib/aura/src/CVS/Entries | 10 + mk4/lib/aura/src/CVS/Repository | 1 + mk4/lib/aura/src/CVS/Root | 1 + mk4/lib/aura/src/CVS/Tag | 1 + {aura => mk4/lib/aura/src}/basictypes.c | 0 {aura => mk4/lib/aura/src}/iterator.c | 0 mk4/lib/aura/src/list_iterator.c | 86 + mk4/lib/aura/src/memutil.c | 37 + mk4/lib/aura/src/serialization.c | 355 + .../lib/aura/src}/serializationinfo.c | 0 mk4/lib/aura/src/stringdictionary.c | 233 + {aura => mk4/lib/aura/src}/typelocator.c | 0 mk4/lib/causality-client/CVS/Entries | 3 + mk4/lib/causality-client/CVS/Repository | 1 + mk4/lib/causality-client/CVS/Root | 1 + mk4/lib/causality-client/CVS/Tag | 1 + mk4/lib/causality-client/Makefile | 14 + mk4/lib/causality-client/include/CVS/Entries | 8 + .../causality-client/include/CVS/Repository | 1 + mk4/lib/causality-client/include/CVS/Root | 1 + mk4/lib/causality-client/include/CVS/Tag | 1 + mk4/lib/causality-client/include/client.h | 34 + .../causality-client/include/http_request.h | 57 + .../include/http_request_handler.h | 12 + .../include/http_request_list.h | 30 + .../include/http_request_list_entry.h | 16 + .../include/http_request_queue.h | 15 + .../causality-client/include/http_response.h | 12 + mk4/lib/causality-client/src/CVS/Entries | 8 + mk4/lib/causality-client/src/CVS/Repository | 1 + mk4/lib/causality-client/src/CVS/Root | 1 + mk4/lib/causality-client/src/CVS/Tag | 1 + mk4/lib/causality-client/src/client.c | 141 + mk4/lib/causality-client/src/http_request.c | 463 + .../src/http_request_handler.c | 67 + .../causality-client/src/http_request_list.c | 133 + .../src/http_request_list_entry.c | 44 + .../causality-client/src/http_request_queue.c | 75 + mk4/lib/causality-client/src/http_response.c | 124 + mk4/lib/causality/CVS/Entries | 3 + mk4/lib/causality/CVS/Repository | 1 + mk4/lib/causality/CVS/Root | 1 + mk4/lib/causality/CVS/Tag | 1 + mk4/lib/causality/Makefile | 15 + mk4/lib/causality/include/CVS/Entries | 12 + mk4/lib/causality/include/CVS/Repository | 1 + mk4/lib/causality/include/CVS/Root | 1 + mk4/lib/causality/include/CVS/Tag | 1 + mk4/lib/causality/include/command.h | 18 + mk4/lib/causality/include/command_handlers.h | 21 + mk4/lib/causality/include/message.h | 43 + mk4/lib/causality/include/message_processor.h | 19 + mk4/lib/causality/include/processor.h | 22 + .../causality/include/request_dispatcher.h | 12 + .../causality/include/request_handler_entry.h | 17 + mk4/lib/causality/include/responseholder.h | 15 + .../causality/include/responseholderlist.h | 16 + mk4/lib/causality/include/sysvipc.h | 23 + mk4/lib/causality/include/threadpool.h | 15 + mk4/lib/causality/src/CVS/Entries | 12 + mk4/lib/causality/src/CVS/Repository | 1 + mk4/lib/causality/src/CVS/Root | 1 + mk4/lib/causality/src/CVS/Tag | 1 + mk4/lib/causality/src/command.c | 21 + mk4/lib/causality/src/command_handlers.c | 68 + mk4/lib/causality/src/message.c | 226 + mk4/lib/causality/src/message_processor.c | 71 + mk4/lib/causality/src/processor.c | 243 + mk4/lib/causality/src/request_dispatcher.c | 114 + mk4/lib/causality/src/request_handler_entry.c | 43 + mk4/lib/causality/src/responseholder.c | 84 + mk4/lib/causality/src/responseholderlist.c | 106 + mk4/lib/causality/src/sysvipc.c | 321 + mk4/lib/causality/src/threadpool.c | 96 + mk4/mobility-client/CVS/Entries | 3 + mk4/mobility-client/CVS/Repository | 1 + mk4/mobility-client/CVS/Root | 1 + mk4/mobility-client/CVS/Tag | 1 + mk4/mobility-client/Makefile.in | 12 + mk4/mobility-client/modcgi/.cvsignore | 14 + mk4/mobility-client/modcgi/CVS/Entries | 4 + mk4/mobility-client/modcgi/CVS/Repository | 1 + mk4/mobility-client/modcgi/CVS/Root | 1 + mk4/mobility-client/modcgi/CVS/Tag | 1 + mk4/mobility-client/modcgi/Makefile | 16 + mk4/mobility-client/modcgi/include/.cvsignore | 1 + .../modcgi/include/CVS/Entries | 10 + .../modcgi/include/CVS/Repository | 1 + mk4/mobility-client/modcgi/include/CVS/Root | 1 + mk4/mobility-client/modcgi/include/CVS/Tag | 1 + .../modcgi/include/cgi_request.h | 16 + .../modcgi/include/fd_reader.h | 15 + .../modcgi/include/fd_watcher.h | 21 + .../modcgi/include/fd_watcher_entry.h | 19 + .../modcgi/include/process_watcher.h | 19 + .../modcgi/include/process_watcher_entry.h | 16 + .../modcgi/include/remote_process.h | 27 + .../modcgi/include/string_collection.h | 15 + mk4/mobility-client/modcgi/src/.cvsignore | 3 + mk4/mobility-client/modcgi/src/CVS/Entries | 11 + mk4/mobility-client/modcgi/src/CVS/Repository | 1 + mk4/mobility-client/modcgi/src/CVS/Root | 1 + mk4/mobility-client/modcgi/src/CVS/Tag | 1 + mk4/mobility-client/modcgi/src/cgi_request.c | 651 ++ mk4/mobility-client/modcgi/src/fd_reader.c | 229 + mk4/mobility-client/modcgi/src/fd_watcher.c | 172 + .../modcgi/src/fd_watcher_entry.c | 77 + mk4/mobility-client/modcgi/src/modcgi.c | 36 + .../modcgi/src/process_watcher.c | 253 + .../modcgi/src/process_watcher_entry.c | 58 + .../modcgi/src/remote_process.c | 491 + .../modcgi/src/string_collection.c | 108 + mk4/mobility-client/modmono/.cvsignore | 7 + mk4/mobility-client/modmono/CVS/Entries | 3 + mk4/mobility-client/modmono/CVS/Repository | 1 + mk4/mobility-client/modmono/CVS/Root | 1 + mk4/mobility-client/modmono/CVS/Tag | 1 + mk4/mobility-client/modmono/Makefile | 45 + mk4/mobility-client/modmono/src/.cvsignore | 1 + .../modmono/src/CThreadPool.cs | 296 + mk4/mobility-client/modmono/src/CVS/Entries | 10 + .../modmono/src/CVS/Repository | 1 + mk4/mobility-client/modmono/src/CVS/Root | 1 + mk4/mobility-client/modmono/src/CVS/Tag | 1 + .../modmono/src/CausalityClient.cs | 59 + .../modmono/src/CausalityRequest.cs | 137 + .../modmono/src/OxideApplicationHost.cs | 61 + .../modmono/src/OxideApplicationPool.cs | 54 + mk4/mobility-client/modmono/src/OxideMain.cs | 25 + .../modmono/src/OxideThreadPool.cs | 87 + .../modmono/src/OxideWorkerRequest.cs | 267 + mk4/modbeacon/CVS/Entries | 5 + mk4/modbeacon/CVS/Repository | 1 + mk4/modbeacon/CVS/Root | 1 + mk4/modbeacon/CVS/Tag | 1 + mk4/modbeacon/Makefile.in | 24 + mk4/modbeacon/beacon.c | 209 + mk4/modbeacon/beacon.xml | 4 + mk4/modbeacon/kstat.h | 23 + mk4/modcommand/CVS/Entries | 5 + mk4/modcommand/CVS/Repository | 1 + mk4/modcommand/CVS/Root | 1 + mk4/modcommand/CVS/Tag | 1 + mk4/modcommand/Makefile.in | 24 + mk4/modcommand/cmd.c | 430 + mk4/modcommand/cmd.h | 29 + mk4/modcommand/cmd.xml | 4 + mk4/moddb/CVS/Entries | 5 + mk4/moddb/CVS/Repository | 1 + mk4/moddb/CVS/Root | 1 + mk4/moddb/CVS/Tag | 1 + mk4/moddb/Makefile.in | 24 + mk4/moddb/db.c | 50 + mk4/moddb/db.h | 36 + mk4/moddb/db.xml | 3 + mk4/moddynamo/CMLDRP.c | 1485 +++ mk4/moddynamo/CMLDRP.h | 279 + mk4/moddynamo/CVS/Entries | 23 + mk4/moddynamo/CVS/Repository | 1 + mk4/moddynamo/CVS/Root | 1 + mk4/moddynamo/CVS/Tag | 1 + mk4/moddynamo/DRPClient.c | 3050 ++++++ mk4/moddynamo/DRPClient.h | 440 + mk4/moddynamo/DRPServerIO.c | 820 ++ mk4/moddynamo/DRPServerIO.h | 64 + mk4/moddynamo/DRPTypes.h | 241 + mk4/moddynamo/DynSock.c | 302 + mk4/moddynamo/DynSock.h | 87 + mk4/moddynamo/Makefile | 22 + mk4/moddynamo/cmVersion.h | 228 + mk4/moddynamo/hook.c | 570 ++ mk4/moddynamo/io.c | 1672 ++++ mk4/moddynamo/io.h | 341 + mk4/moddynamo/pageroute.c | 320 + mk4/moddynamo/pageroute.h | 31 + mk4/moddynamo/rwLocks.h | 75 + mk4/moddynamo/sockerrs.c | 220 + mk4/moddynamo/sockerrs.h | 29 + mk4/moddynamo/system.h | 52 + mk4/moddynamo/threadabstr.c | 94 + mk4/moddynamo/threadabstr.h | 28 + mk4/modexample/CVS/Entries | 5 + mk4/modexample/CVS/Repository | 1 + mk4/modexample/CVS/Root | 1 + mk4/modexample/CVS/Tag | 1 + mk4/modexample/Makefile | 23 + mk4/modexample/auth.c | 59 + mk4/modexample/example.c | 16 + mk4/modexample/hello.c | 19 + mk4/modharmony/CVS/Entries | 5 + mk4/modharmony/CVS/Repository | 1 + mk4/modharmony/CVS/Root | 1 + mk4/modharmony/CVS/Tag | 1 + mk4/modharmony/Makefile.in | 21 + mk4/modharmony/harmony.c | 140 + mk4/modharmony/harmony.h | 8 + mk4/modharmony/hproto.h | 15 + mk4/modhtaccess/CVS/Entries | 3 + mk4/modhtaccess/CVS/Repository | 1 + mk4/modhtaccess/CVS/Root | 1 + mk4/modhtaccess/CVS/Tag | 1 + mk4/modhtaccess/Makefile | 15 + mk4/modhtaccess/include/CVS/Entries | 5 + mk4/modhtaccess/include/CVS/Repository | 1 + mk4/modhtaccess/include/CVS/Root | 1 + mk4/modhtaccess/include/CVS/Tag | 1 + mk4/modhtaccess/include/htaccess_basic_auth.h | 10 + mk4/modhtaccess/include/htaccess_engine.h | 14 + mk4/modhtaccess/include/htaccess_parser.h | 16 + .../include/iauthentication_scheme.h | 33 + mk4/modhtaccess/src/CVS/Entries | 5 + mk4/modhtaccess/src/CVS/Repository | 1 + mk4/modhtaccess/src/CVS/Root | 1 + mk4/modhtaccess/src/CVS/Tag | 1 + mk4/modhtaccess/src/htaccess.c | 20 + mk4/modhtaccess/src/htaccess_basic_auth.c | 253 + mk4/modhtaccess/src/htaccess_engine.c | 260 + mk4/modhtaccess/src/htaccess_parser.c | 96 + mk4/modhttp/CVS/Entries | 5 + mk4/modhttp/CVS/Repository | 1 + mk4/modhttp/CVS/Root | 1 + mk4/modhttp/CVS/Tag | 1 + mk4/modhttp/Makefile.in | 24 + mk4/modhttp/http.c | 1030 ++ mk4/modhttp/http.h | 102 + mk4/modhttp/http.xml | 4 + mk4/modimage/CVS/Entries | 18 + mk4/modimage/CVS/Repository | 1 + mk4/modimage/CVS/Root | 1 + mk4/modimage/CVS/Tag | 1 + mk4/modimage/Makefile.in | 28 + mk4/modimage/cderror.h | 132 + mk4/modimage/cdjpeg.h | 184 + mk4/modimage/image.c | 29 + mk4/modimage/image.xml | 3 + mk4/modimage/jchuff.h | 47 + mk4/modimage/jconfig.h | 45 + mk4/modimage/jdct.h | 176 + mk4/modimage/jdhuff.h | 201 + mk4/modimage/jerror.h | 291 + mk4/modimage/jinclude.h | 91 + mk4/modimage/jmemsys.h | 198 + mk4/modimage/jmorecfg.h | 363 + mk4/modimage/jpeg-6b/.cvsignore | 9 + mk4/modimage/jpeg-6b/CVS/Entries | 141 + mk4/modimage/jpeg-6b/CVS/Repository | 1 + mk4/modimage/jpeg-6b/CVS/Root | 1 + mk4/modimage/jpeg-6b/CVS/Tag | 1 + mk4/modimage/jpeg-6b/README | 385 + mk4/modimage/jpeg-6b/ansi2knr.1 | 36 + mk4/modimage/jpeg-6b/ansi2knr.c | 693 ++ mk4/modimage/jpeg-6b/cderror.h | 132 + mk4/modimage/jpeg-6b/cdjpeg.c | 181 + mk4/modimage/jpeg-6b/cdjpeg.h | 184 + mk4/modimage/jpeg-6b/change.log | 217 + mk4/modimage/jpeg-6b/cjpeg.1 | 292 + mk4/modimage/jpeg-6b/cjpeg.c | 606 ++ mk4/modimage/jpeg-6b/ckconfig.c | 402 + mk4/modimage/jpeg-6b/coderules.doc | 118 + mk4/modimage/jpeg-6b/config.guess | 883 ++ mk4/modimage/jpeg-6b/config.sub | 954 ++ mk4/modimage/jpeg-6b/configure | 2011 ++++ mk4/modimage/jpeg-6b/djpeg.1 | 253 + mk4/modimage/jpeg-6b/djpeg.c | 616 ++ mk4/modimage/jpeg-6b/example.c | 433 + mk4/modimage/jpeg-6b/filelist.doc | 210 + mk4/modimage/jpeg-6b/install-sh | 250 + mk4/modimage/jpeg-6b/install.doc | 1063 ++ mk4/modimage/jpeg-6b/jcapimin.c | 280 + mk4/modimage/jpeg-6b/jcapistd.c | 161 + mk4/modimage/jpeg-6b/jccoefct.c | 449 + mk4/modimage/jpeg-6b/jccolor.c | 459 + mk4/modimage/jpeg-6b/jcdctmgr.c | 387 + mk4/modimage/jpeg-6b/jchuff.c | 909 ++ mk4/modimage/jpeg-6b/jchuff.h | 47 + mk4/modimage/jpeg-6b/jcinit.c | 72 + mk4/modimage/jpeg-6b/jcmainct.c | 293 + mk4/modimage/jpeg-6b/jcmarker.c | 664 ++ mk4/modimage/jpeg-6b/jcmaster.c | 590 ++ mk4/modimage/jpeg-6b/jcomapi.c | 106 + mk4/modimage/jpeg-6b/jconfig.bcc | 48 + mk4/modimage/jpeg-6b/jconfig.cfg | 44 + mk4/modimage/jpeg-6b/jconfig.dj | 38 + mk4/modimage/jpeg-6b/jconfig.doc | 155 + mk4/modimage/jpeg-6b/jconfig.mac | 43 + mk4/modimage/jpeg-6b/jconfig.manx | 43 + mk4/modimage/jpeg-6b/jconfig.mc6 | 52 + mk4/modimage/jpeg-6b/jconfig.sas | 43 + mk4/modimage/jpeg-6b/jconfig.st | 42 + mk4/modimage/jpeg-6b/jconfig.vc | 45 + mk4/modimage/jpeg-6b/jconfig.vms | 37 + mk4/modimage/jpeg-6b/jconfig.wat | 38 + mk4/modimage/jpeg-6b/jcparam.c | 610 ++ mk4/modimage/jpeg-6b/jcphuff.c | 833 ++ mk4/modimage/jpeg-6b/jcprepct.c | 354 + mk4/modimage/jpeg-6b/jcsample.c | 519 + mk4/modimage/jpeg-6b/jctrans.c | 388 + mk4/modimage/jpeg-6b/jdapimin.c | 395 + mk4/modimage/jpeg-6b/jdapistd.c | 275 + mk4/modimage/jpeg-6b/jdatadst.c | 151 + mk4/modimage/jpeg-6b/jdatasrc.c | 212 + mk4/modimage/jpeg-6b/jdcoefct.c | 736 ++ mk4/modimage/jpeg-6b/jdcolor.c | 396 + mk4/modimage/jpeg-6b/jdct.h | 176 + mk4/modimage/jpeg-6b/jddctmgr.c | 269 + mk4/modimage/jpeg-6b/jdhuff.c | 651 ++ mk4/modimage/jpeg-6b/jdhuff.h | 201 + mk4/modimage/jpeg-6b/jdinput.c | 381 + mk4/modimage/jpeg-6b/jdmainct.c | 512 + mk4/modimage/jpeg-6b/jdmarker.c | 1360 +++ mk4/modimage/jpeg-6b/jdmaster.c | 557 ++ mk4/modimage/jpeg-6b/jdmerge.c | 400 + mk4/modimage/jpeg-6b/jdphuff.c | 668 ++ mk4/modimage/jpeg-6b/jdpostct.c | 290 + mk4/modimage/jpeg-6b/jdsample.c | 478 + mk4/modimage/jpeg-6b/jdtrans.c | 143 + mk4/modimage/jpeg-6b/jerror.c | 252 + mk4/modimage/jpeg-6b/jerror.h | 291 + mk4/modimage/jpeg-6b/jfdctflt.c | 168 + mk4/modimage/jpeg-6b/jfdctfst.c | 224 + mk4/modimage/jpeg-6b/jfdctint.c | 283 + mk4/modimage/jpeg-6b/jidctflt.c | 242 + mk4/modimage/jpeg-6b/jidctfst.c | 368 + mk4/modimage/jpeg-6b/jidctint.c | 389 + mk4/modimage/jpeg-6b/jidctred.c | 398 + mk4/modimage/jpeg-6b/jinclude.h | 91 + mk4/modimage/jpeg-6b/jmemansi.c | 167 + mk4/modimage/jpeg-6b/jmemdos.c | 638 ++ mk4/modimage/jpeg-6b/jmemdosa.asm | 379 + mk4/modimage/jpeg-6b/jmemmac.c | 289 + mk4/modimage/jpeg-6b/jmemmgr.c | 1118 +++ mk4/modimage/jpeg-6b/jmemname.c | 276 + mk4/modimage/jpeg-6b/jmemnobs.c | 109 + mk4/modimage/jpeg-6b/jmemsys.h | 198 + mk4/modimage/jpeg-6b/jmorecfg.h | 363 + mk4/modimage/jpeg-6b/jpegint.h | 392 + mk4/modimage/jpeg-6b/jpeglib.h | 1096 ++ mk4/modimage/jpeg-6b/jpegtran.1 | 238 + mk4/modimage/jpeg-6b/jpegtran.c | 504 + mk4/modimage/jpeg-6b/jquant1.c | 856 ++ mk4/modimage/jpeg-6b/jquant2.c | 1310 +++ mk4/modimage/jpeg-6b/jutils.c | 179 + mk4/modimage/jpeg-6b/jversion.h | 14 + mk4/modimage/jpeg-6b/libjpeg.doc | 3006 ++++++ mk4/modimage/jpeg-6b/ltconfig | 1512 +++ mk4/modimage/jpeg-6b/ltmain.sh | 2453 +++++ mk4/modimage/jpeg-6b/makcjpeg.st | 38 + mk4/modimage/jpeg-6b/makdjpeg.st | 38 + mk4/modimage/jpeg-6b/makeapps.ds | 828 ++ mk4/modimage/jpeg-6b/makefile.ansi | 214 + mk4/modimage/jpeg-6b/makefile.bcc | 285 + mk4/modimage/jpeg-6b/makefile.cfg | 319 + mk4/modimage/jpeg-6b/makefile.dj | 220 + mk4/modimage/jpeg-6b/makefile.manx | 214 + mk4/modimage/jpeg-6b/makefile.mc6 | 249 + mk4/modimage/jpeg-6b/makefile.mms | 218 + mk4/modimage/jpeg-6b/makefile.sas | 252 + mk4/modimage/jpeg-6b/makefile.unix | 228 + mk4/modimage/jpeg-6b/makefile.vc | 211 + mk4/modimage/jpeg-6b/makefile.vms | 142 + mk4/modimage/jpeg-6b/makefile.wat | 233 + mk4/modimage/jpeg-6b/makelib.ds | 1046 ++ mk4/modimage/jpeg-6b/makeproj.mac | 213 + mk4/modimage/jpeg-6b/makljpeg.st | 70 + mk4/modimage/jpeg-6b/maktjpeg.st | 32 + mk4/modimage/jpeg-6b/makvms.opt | 4 + mk4/modimage/jpeg-6b/rdbmp.c | 439 + mk4/modimage/jpeg-6b/rdcolmap.c | 253 + mk4/modimage/jpeg-6b/rdgif.c | 38 + mk4/modimage/jpeg-6b/rdjpgcom.1 | 54 + mk4/modimage/jpeg-6b/rdjpgcom.c | 496 + mk4/modimage/jpeg-6b/rdppm.c | 458 + mk4/modimage/jpeg-6b/rdrle.c | 387 + mk4/modimage/jpeg-6b/rdswitch.c | 332 + mk4/modimage/jpeg-6b/rdtarga.c | 500 + mk4/modimage/jpeg-6b/structure.doc | 948 ++ mk4/modimage/jpeg-6b/transupp.c | 928 ++ mk4/modimage/jpeg-6b/transupp.h | 135 + mk4/modimage/jpeg-6b/usage.doc | 562 ++ mk4/modimage/jpeg-6b/wizard.doc | 211 + mk4/modimage/jpeg-6b/wrbmp.c | 442 + mk4/modimage/jpeg-6b/wrgif.c | 399 + mk4/modimage/jpeg-6b/wrjpgcom.1 | 103 + mk4/modimage/jpeg-6b/wrjpgcom.c | 583 ++ mk4/modimage/jpeg-6b/wrppm.c | 268 + mk4/modimage/jpeg-6b/wrrle.c | 305 + mk4/modimage/jpeg-6b/wrtarga.c | 253 + mk4/modimage/jpegint.h | 392 + mk4/modimage/jpeglib.h | 1096 ++ mk4/modimage/jversion.h | 14 + mk4/modimage/transupp.h | 135 + mk4/modjava/CVS/Entries | 6 + mk4/modjava/CVS/Repository | 1 + mk4/modjava/CVS/Root | 1 + mk4/modjava/CVS/Tag | 1 + mk4/modjava/Makefile.in | 37 + mk4/modjava/Prog.java | 45 + mk4/modjava/com/CVS/Entries | 1 + mk4/modjava/com/CVS/Repository | 1 + mk4/modjava/com/CVS/Root | 1 + mk4/modjava/com/CVS/Tag | 1 + mk4/modjava/com/ashpool/CVS/Entries | 1 + mk4/modjava/com/ashpool/CVS/Repository | 1 + mk4/modjava/com/ashpool/CVS/Root | 1 + mk4/modjava/com/ashpool/CVS/Tag | 1 + .../com/ashpool/continuity/CVS/Entries | 4 + .../com/ashpool/continuity/CVS/Repository | 1 + mk4/modjava/com/ashpool/continuity/CVS/Root | 1 + mk4/modjava/com/ashpool/continuity/CVS/Tag | 1 + .../ashpool/continuity/CatalinaConnector.java | 307 + .../ashpool/continuity/ContHttpRequest.java | 82 + .../com/ashpool/continuity/ContRequest.java | 33 + mk4/modjava/entrance.c | 277 + mk4/modjava/modjava.c | 164 + mk4/modjava/module.cfg | 10 + mk4/modm3/.rev | 1 + mk4/modm3/CVS/Entries | 4 + mk4/modm3/CVS/Repository | 1 + mk4/modm3/CVS/Root | 1 + mk4/modm3/CVS/Tag | 1 + mk4/modm3/Makefile.in | 22 + mk4/modm3/include/CVS/Entries | 24 + mk4/modm3/include/CVS/Repository | 1 + mk4/modm3/include/CVS/Root | 1 + mk4/modm3/include/CVS/Tag | 1 + {modm3 => mk4/modm3/include}/_build.h | 0 {modm3 => mk4/modm3/include}/file_catalog.h | 0 {modm3 => mk4/modm3/include}/file_entry.h | 0 {modm3 => mk4/modm3/include}/file_reader.h | 0 {modm3 => mk4/modm3/include}/idata_reader.h | 0 mk4/modm3/include/iplaylist.h | 25 + {modm3 => mk4/modm3/include}/ixtime.h | 0 mk4/modm3/include/m3.h | 14 + mk4/modm3/include/m3_client.h | 23 + mk4/modm3/include/m3_server.h | 32 + .../modm3/include}/m3_server_factory.h | 0 {modm3 => mk4/modm3/include}/m3_tcl.h | 0 {modm3 => mk4/modm3/include}/mp3_frame.h | 0 mk4/modm3/include/mp3_reader.h | 17 + mk4/modm3/include/music_packet.h | 25 + .../modm3/include}/order_playlist_engine.h | 0 mk4/modm3/include/playlist.h | 61 + .../modm3/include}/playlist_engine_factory.h | 0 mk4/modm3/include/playlist_manager.h | 19 + .../modm3/include}/queue_playlist_engine.h | 0 .../include}/randomlist_playlist_engine.h | 0 .../include}/shoutcast_metadata_writer.h | 0 {modm3 => mk4/modm3/include}/support.h | 0 mk4/modm3/src/.cvsignore | 1 + mk4/modm3/src/CVS/Entries | 22 + mk4/modm3/src/CVS/Repository | 1 + mk4/modm3/src/CVS/Root | 1 + mk4/modm3/src/CVS/Tag | 1 + mk4/modm3/src/file_catalog.c | 63 + mk4/modm3/src/file_entry.c | 111 + mk4/modm3/src/file_reader.c | 395 + {modm3 => mk4/modm3/src}/ixtime.c | 0 mk4/modm3/src/m3.c | 275 + mk4/modm3/src/m3_client.c | 134 + mk4/modm3/src/m3_server.c | 481 + mk4/modm3/src/m3_server_factory.c | 109 + mk4/modm3/src/m3_tcl.c | 131 + {modm3 => mk4/modm3/src}/mp3_frame.c | 0 mk4/modm3/src/mp3_reader.c | 313 + mk4/modm3/src/music_packet.c | 83 + mk4/modm3/src/order_playlist_engine.c | 81 + mk4/modm3/src/playlist.c | 311 + mk4/modm3/src/playlist_engine_factory.c | 69 + mk4/modm3/src/playlist_manager.c | 204 + mk4/modm3/src/queue_playlist_engine.c | 148 + .../modm3/src}/randomlist_playlist_engine.c | 0 mk4/modm3/src/shoutcast_metadata_writer.c | 191 + {modm3 => mk4/modm3/src}/support.c | 0 mk4/modmobility/CVS/Entries | 3 + mk4/modmobility/CVS/Repository | 1 + mk4/modmobility/CVS/Root | 1 + mk4/modmobility/CVS/Tag | 1 + mk4/modmobility/Makefile | 13 + mk4/modmobility/include/CVS/Entries | 6 + mk4/modmobility/include/CVS/Repository | 1 + mk4/modmobility/include/CVS/Root | 1 + mk4/modmobility/include/CVS/Tag | 1 + .../include/http_message_handler.h | 13 + mk4/modmobility/include/http_request.h | 27 + mk4/modmobility/include/http_request_list.h | 20 + mk4/modmobility/include/mobility.h | 20 + mk4/modmobility/include/mobilitytable.h | 17 + mk4/modmobility/src/CVS/Entries | 7 + mk4/modmobility/src/CVS/Repository | 1 + mk4/modmobility/src/CVS/Root | 1 + mk4/modmobility/src/CVS/Tag | 1 + mk4/modmobility/src/handler.c | 54 + mk4/modmobility/src/http_message_handler.c | 253 + mk4/modmobility/src/http_request.c | 361 + mk4/modmobility/src/http_request_list.c | 94 + mk4/modmobility/src/mobility.c | 266 + mk4/modmobility/src/mobilitytable.c | 122 + mk4/modoracle/CVS/Entries | 6 + mk4/modoracle/CVS/Repository | 1 + mk4/modoracle/CVS/Root | 1 + mk4/modoracle/CVS/Tag | 1 + mk4/modoracle/Makefile.blackwell | 60 + mk4/modoracle/Makefile.chiba | 60 + mk4/modoracle/Makefile.gorecki | 60 + mk4/modoracle/ora.c | 895 ++ mk4/modoracle/oracle.xml | 7 + mk4/modradius/CVS/Entries | 5 + mk4/modradius/CVS/Repository | 1 + mk4/modradius/CVS/Root | 1 + mk4/modradius/CVS/Tag | 1 + mk4/modradius/Makefile.in | 24 + mk4/modradius/radius.c | 526 + mk4/modradius/radius.h | 21 + mk4/modradius/radius.xml | 4 + mk4/modsite/CVS/Entries | 7 + mk4/modsite/CVS/Repository | 1 + mk4/modsite/CVS/Root | 1 + mk4/modsite/CVS/Tag | 1 + mk4/modsite/Makefile.in | 24 + mk4/modsite/log.c | 433 + mk4/modsite/site.c | 1347 +++ mk4/modsite/site.h | 56 + mk4/modsite/site.xml | 8 + {modsite => mk4/modsite}/siteerror.h | 0 mk4/modssl/CVS/Entries | 10 + mk4/modssl/CVS/Repository | 1 + mk4/modssl/CVS/Root | 1 + mk4/modssl/CVS/Tag | 1 + mk4/modssl/LICENSE | 5 + mk4/modssl/Makefile | 23 + mk4/modssl/Makefile.osx | 23 + mk4/modssl/client.pem | 32 + mk4/modssl/dh1024.pem | 5 + mk4/modssl/root.pem | 14 + mk4/modssl/server.pem | 32 + mk4/modssl/ssl.c | 196 + mk4/modssl/ssl.h | 30 + mk4/modtcl/CVS/Entries | 3 + mk4/modtcl/CVS/Repository | 1 + mk4/modtcl/CVS/Root | 1 + mk4/modtcl/CVS/Tag | 1 + mk4/modtcl/Makefile.in | 17 + mk4/modtcl/src/CVS/Entries | 6 + mk4/modtcl/src/CVS/Repository | 1 + mk4/modtcl/src/CVS/Root | 1 + mk4/modtcl/src/CVS/Tag | 1 + mk4/modtcl/src/Makefile | 22 + mk4/modtcl/src/cmds.c | 764 ++ mk4/modtcl/src/modtcl.c | 432 + mk4/modtcl/src/modtcl.h | 73 + {modtcl => mk4/modtcl/src}/modtcl.xml | 0 mk4/modtcl/tcl8.3.4/CVS/Entries | 13 + mk4/modtcl/tcl8.3.4/CVS/Repository | 1 + mk4/modtcl/tcl8.3.4/CVS/Root | 1 + mk4/modtcl/tcl8.3.4/CVS/Tag | 1 + mk4/modtcl/tcl8.3.4/ChangeLog | 5515 ++++++++++ mk4/modtcl/tcl8.3.4/README | 185 + mk4/modtcl/tcl8.3.4/changes | 5075 ++++++++++ mk4/modtcl/tcl8.3.4/compat/CVS/Entries | 24 + mk4/modtcl/tcl8.3.4/compat/CVS/Repository | 1 + mk4/modtcl/tcl8.3.4/compat/CVS/Root | 1 + mk4/modtcl/tcl8.3.4/compat/CVS/Tag | 1 + mk4/modtcl/tcl8.3.4/compat/README | 8 + mk4/modtcl/tcl8.3.4/compat/dirent.h | 23 + mk4/modtcl/tcl8.3.4/compat/dirent2.h | 59 + mk4/modtcl/tcl8.3.4/compat/dlfcn.h | 65 + mk4/modtcl/tcl8.3.4/compat/fixstrtod.c | 38 + mk4/modtcl/tcl8.3.4/compat/float.h | 16 + mk4/modtcl/tcl8.3.4/compat/gettod.c | 32 + mk4/modtcl/tcl8.3.4/compat/license.terms | 39 + mk4/modtcl/tcl8.3.4/compat/limits.h | 24 + mk4/modtcl/tcl8.3.4/compat/memcmp.c | 61 + mk4/modtcl/tcl8.3.4/compat/opendir.c | 108 + mk4/modtcl/tcl8.3.4/compat/stdlib.h | 45 + mk4/modtcl/tcl8.3.4/compat/strftime.c | 393 + mk4/modtcl/tcl8.3.4/compat/string.h | 71 + mk4/modtcl/tcl8.3.4/compat/strncasecmp.c | 142 + mk4/modtcl/tcl8.3.4/compat/strstr.c | 68 + mk4/modtcl/tcl8.3.4/compat/strtod.c | 263 + mk4/modtcl/tcl8.3.4/compat/strtol.c | 83 + mk4/modtcl/tcl8.3.4/compat/strtoul.c | 183 + mk4/modtcl/tcl8.3.4/compat/tclErrno.h | 100 + mk4/modtcl/tcl8.3.4/compat/tmpnam.c | 42 + mk4/modtcl/tcl8.3.4/compat/unistd.h | 84 + mk4/modtcl/tcl8.3.4/compat/waitpid.c | 174 + mk4/modtcl/tcl8.3.4/doc/Access.3 | 71 + mk4/modtcl/tcl8.3.4/doc/AddErrInfo.3 | 191 + mk4/modtcl/tcl8.3.4/doc/Alloc.3 | 52 + mk4/modtcl/tcl8.3.4/doc/AllowExc.3 | 42 + mk4/modtcl/tcl8.3.4/doc/AppInit.3 | 73 + mk4/modtcl/tcl8.3.4/doc/AssocData.3 | 89 + mk4/modtcl/tcl8.3.4/doc/Async.3 | 163 + mk4/modtcl/tcl8.3.4/doc/BackgdErr.3 | 58 + mk4/modtcl/tcl8.3.4/doc/Backslash.3 | 53 + mk4/modtcl/tcl8.3.4/doc/BoolObj.3 | 83 + mk4/modtcl/tcl8.3.4/doc/ByteArrObj.3 | 91 + mk4/modtcl/tcl8.3.4/doc/CVS/Entries | 184 + mk4/modtcl/tcl8.3.4/doc/CVS/Repository | 1 + mk4/modtcl/tcl8.3.4/doc/CVS/Root | 1 + mk4/modtcl/tcl8.3.4/doc/CVS/Tag | 1 + mk4/modtcl/tcl8.3.4/doc/CallDel.3 | 63 + mk4/modtcl/tcl8.3.4/doc/ChnlStack.3 | 90 + mk4/modtcl/tcl8.3.4/doc/CmdCmplt.3 | 36 + mk4/modtcl/tcl8.3.4/doc/Concat.3 | 55 + mk4/modtcl/tcl8.3.4/doc/CrtChannel.3 | 760 ++ mk4/modtcl/tcl8.3.4/doc/CrtChnlHdlr.3 | 92 + mk4/modtcl/tcl8.3.4/doc/CrtCloseHdlr.3 | 59 + mk4/modtcl/tcl8.3.4/doc/CrtCommand.3 | 143 + mk4/modtcl/tcl8.3.4/doc/CrtFileHdlr.3 | 100 + mk4/modtcl/tcl8.3.4/doc/CrtInterp.3 | 131 + mk4/modtcl/tcl8.3.4/doc/CrtMathFnc.3 | 93 + mk4/modtcl/tcl8.3.4/doc/CrtObjCmd.3 | 260 + mk4/modtcl/tcl8.3.4/doc/CrtSlave.3 | 231 + mk4/modtcl/tcl8.3.4/doc/CrtTimerHdlr.3 | 76 + mk4/modtcl/tcl8.3.4/doc/CrtTrace.3 | 106 + mk4/modtcl/tcl8.3.4/doc/DString.3 | 151 + mk4/modtcl/tcl8.3.4/doc/DetachPids.3 | 77 + mk4/modtcl/tcl8.3.4/doc/DoOneEvent.3 | 108 + mk4/modtcl/tcl8.3.4/doc/DoWhenIdle.3 | 86 + mk4/modtcl/tcl8.3.4/doc/DoubleObj.3 | 79 + mk4/modtcl/tcl8.3.4/doc/DumpActiveMemory.3 | 68 + mk4/modtcl/tcl8.3.4/doc/Encoding.3 | 523 + mk4/modtcl/tcl8.3.4/doc/Eval.3 | 199 + mk4/modtcl/tcl8.3.4/doc/Exit.3 | 131 + mk4/modtcl/tcl8.3.4/doc/ExprLong.3 | 112 + mk4/modtcl/tcl8.3.4/doc/ExprLongObj.3 | 104 + mk4/modtcl/tcl8.3.4/doc/FindExec.3 | 58 + mk4/modtcl/tcl8.3.4/doc/GetCwd.3 | 54 + mk4/modtcl/tcl8.3.4/doc/GetHostName.3 | 28 + mk4/modtcl/tcl8.3.4/doc/GetIndex.3 | 102 + mk4/modtcl/tcl8.3.4/doc/GetInt.3 | 81 + mk4/modtcl/tcl8.3.4/doc/GetOpnFl.3 | 61 + mk4/modtcl/tcl8.3.4/doc/GetStdChan.3 | 73 + mk4/modtcl/tcl8.3.4/doc/GetVersion.3 | 49 + mk4/modtcl/tcl8.3.4/doc/Hash.3 | 208 + mk4/modtcl/tcl8.3.4/doc/Init.3 | 37 + mk4/modtcl/tcl8.3.4/doc/InitStubs.3 | 91 + mk4/modtcl/tcl8.3.4/doc/IntObj.3 | 104 + mk4/modtcl/tcl8.3.4/doc/Interp.3 | 126 + mk4/modtcl/tcl8.3.4/doc/LinkVar.3 | 115 + mk4/modtcl/tcl8.3.4/doc/ListObj.3 | 247 + mk4/modtcl/tcl8.3.4/doc/Notifier.3 | 602 ++ mk4/modtcl/tcl8.3.4/doc/Object.3 | 337 + mk4/modtcl/tcl8.3.4/doc/ObjectType.3 | 198 + mk4/modtcl/tcl8.3.4/doc/OpenFileChnl.3 | 607 ++ mk4/modtcl/tcl8.3.4/doc/OpenTcp.3 | 179 + mk4/modtcl/tcl8.3.4/doc/ParseCmd.3 | 438 + mk4/modtcl/tcl8.3.4/doc/PkgRequire.3 | 87 + mk4/modtcl/tcl8.3.4/doc/Preserve.3 | 103 + mk4/modtcl/tcl8.3.4/doc/PrintDbl.3 | 47 + mk4/modtcl/tcl8.3.4/doc/RecEvalObj.3 | 55 + mk4/modtcl/tcl8.3.4/doc/RecordEval.3 | 57 + mk4/modtcl/tcl8.3.4/doc/RegExp.3 | 346 + mk4/modtcl/tcl8.3.4/doc/SaveResult.3 | 65 + mk4/modtcl/tcl8.3.4/doc/SetErrno.3 | 61 + mk4/modtcl/tcl8.3.4/doc/SetRecLmt.3 | 55 + mk4/modtcl/tcl8.3.4/doc/SetResult.3 | 225 + mk4/modtcl/tcl8.3.4/doc/SetVar.3 | 261 + mk4/modtcl/tcl8.3.4/doc/Sleep.3 | 37 + mk4/modtcl/tcl8.3.4/doc/SourceRCFile.3 | 38 + mk4/modtcl/tcl8.3.4/doc/SplitList.3 | 175 + mk4/modtcl/tcl8.3.4/doc/SplitPath.3 | 93 + mk4/modtcl/tcl8.3.4/doc/StaticPkg.3 | 69 + mk4/modtcl/tcl8.3.4/doc/StrMatch.3 | 52 + mk4/modtcl/tcl8.3.4/doc/StringObj.3 | 246 + mk4/modtcl/tcl8.3.4/doc/TCL_MEM_DEBUG.3 | 82 + mk4/modtcl/tcl8.3.4/doc/Tcl.n | 195 + mk4/modtcl/tcl8.3.4/doc/Tcl_Main.3 | 81 + mk4/modtcl/tcl8.3.4/doc/Thread.3 | 194 + mk4/modtcl/tcl8.3.4/doc/ToUpper.3 | 90 + mk4/modtcl/tcl8.3.4/doc/TraceVar.3 | 366 + mk4/modtcl/tcl8.3.4/doc/Translate.3 | 66 + mk4/modtcl/tcl8.3.4/doc/UpVar.3 | 75 + mk4/modtcl/tcl8.3.4/doc/Utf.3 | 232 + mk4/modtcl/tcl8.3.4/doc/WrongNumArgs.3 | 78 + mk4/modtcl/tcl8.3.4/doc/after.n | 109 + mk4/modtcl/tcl8.3.4/doc/append.n | 35 + mk4/modtcl/tcl8.3.4/doc/array.n | 125 + mk4/modtcl/tcl8.3.4/doc/bgerror.n | 79 + mk4/modtcl/tcl8.3.4/doc/binary.n | 548 + mk4/modtcl/tcl8.3.4/doc/break.n | 37 + mk4/modtcl/tcl8.3.4/doc/case.n | 62 + mk4/modtcl/tcl8.3.4/doc/catch.n | 66 + mk4/modtcl/tcl8.3.4/doc/cd.n | 31 + mk4/modtcl/tcl8.3.4/doc/clock.n | 214 + mk4/modtcl/tcl8.3.4/doc/close.n | 62 + mk4/modtcl/tcl8.3.4/doc/concat.n | 43 + mk4/modtcl/tcl8.3.4/doc/continue.n | 37 + mk4/modtcl/tcl8.3.4/doc/dde.n | 136 + mk4/modtcl/tcl8.3.4/doc/encoding.n | 79 + mk4/modtcl/tcl8.3.4/doc/eof.n | 30 + mk4/modtcl/tcl8.3.4/doc/error.n | 61 + mk4/modtcl/tcl8.3.4/doc/eval.n | 33 + mk4/modtcl/tcl8.3.4/doc/exec.n | 307 + mk4/modtcl/tcl8.3.4/doc/exit.n | 31 + mk4/modtcl/tcl8.3.4/doc/expr.n | 387 + mk4/modtcl/tcl8.3.4/doc/fblocked.n | 33 + mk4/modtcl/tcl8.3.4/doc/fconfigure.n | 201 + mk4/modtcl/tcl8.3.4/doc/fcopy.n | 127 + mk4/modtcl/tcl8.3.4/doc/file.n | 344 + mk4/modtcl/tcl8.3.4/doc/fileevent.n | 109 + mk4/modtcl/tcl8.3.4/doc/filename.n | 200 + mk4/modtcl/tcl8.3.4/doc/flush.n | 35 + mk4/modtcl/tcl8.3.4/doc/for.n | 63 + mk4/modtcl/tcl8.3.4/doc/foreach.n | 90 + mk4/modtcl/tcl8.3.4/doc/format.n | 217 + mk4/modtcl/tcl8.3.4/doc/gets.n | 50 + mk4/modtcl/tcl8.3.4/doc/glob.n | 161 + mk4/modtcl/tcl8.3.4/doc/global.n | 39 + mk4/modtcl/tcl8.3.4/doc/history.n | 104 + mk4/modtcl/tcl8.3.4/doc/http.n | 526 + mk4/modtcl/tcl8.3.4/doc/if.n | 46 + mk4/modtcl/tcl8.3.4/doc/incr.n | 34 + mk4/modtcl/tcl8.3.4/doc/info.n | 185 + mk4/modtcl/tcl8.3.4/doc/interp.n | 542 + mk4/modtcl/tcl8.3.4/doc/join.n | 32 + mk4/modtcl/tcl8.3.4/doc/lappend.n | 38 + mk4/modtcl/tcl8.3.4/doc/library.n | 311 + mk4/modtcl/tcl8.3.4/doc/license.terms | 39 + mk4/modtcl/tcl8.3.4/doc/lindex.n | 40 + mk4/modtcl/tcl8.3.4/doc/linsert.n | 36 + mk4/modtcl/tcl8.3.4/doc/list.n | 49 + mk4/modtcl/tcl8.3.4/doc/llength.n | 29 + mk4/modtcl/tcl8.3.4/doc/load.n | 135 + mk4/modtcl/tcl8.3.4/doc/lrange.n | 42 + mk4/modtcl/tcl8.3.4/doc/lreplace.n | 51 + mk4/modtcl/tcl8.3.4/doc/lsearch.n | 46 + mk4/modtcl/tcl8.3.4/doc/lsort.n | 191 + mk4/modtcl/tcl8.3.4/doc/man.macros | 236 + mk4/modtcl/tcl8.3.4/doc/memory.n | 80 + mk4/modtcl/tcl8.3.4/doc/msgcat.n | 244 + mk4/modtcl/tcl8.3.4/doc/namespace.n | 566 ++ mk4/modtcl/tcl8.3.4/doc/open.n | 273 + mk4/modtcl/tcl8.3.4/doc/package.n | 196 + mk4/modtcl/tcl8.3.4/doc/packagens.n | 55 + mk4/modtcl/tcl8.3.4/doc/pid.n | 37 + mk4/modtcl/tcl8.3.4/doc/pkgMkIndex.n | 243 + mk4/modtcl/tcl8.3.4/doc/proc.n | 77 + mk4/modtcl/tcl8.3.4/doc/puts.n | 69 + mk4/modtcl/tcl8.3.4/doc/pwd.n | 28 + mk4/modtcl/tcl8.3.4/doc/re_syntax.n | 932 ++ mk4/modtcl/tcl8.3.4/doc/read.n | 58 + mk4/modtcl/tcl8.3.4/doc/regexp.n | 133 + mk4/modtcl/tcl8.3.4/doc/registry.n | 168 + mk4/modtcl/tcl8.3.4/doc/regsub.n | 112 + mk4/modtcl/tcl8.3.4/doc/rename.n | 35 + mk4/modtcl/tcl8.3.4/doc/resource.n | 155 + mk4/modtcl/tcl8.3.4/doc/return.n | 92 + mk4/modtcl/tcl8.3.4/doc/safe.n | 350 + mk4/modtcl/tcl8.3.4/doc/scan.n | 195 + mk4/modtcl/tcl8.3.4/doc/seek.n | 64 + mk4/modtcl/tcl8.3.4/doc/set.n | 51 + mk4/modtcl/tcl8.3.4/doc/socket.n | 134 + mk4/modtcl/tcl8.3.4/doc/source.n | 44 + mk4/modtcl/tcl8.3.4/doc/split.n | 47 + mk4/modtcl/tcl8.3.4/doc/string.n | 341 + mk4/modtcl/tcl8.3.4/doc/subst.n | 51 + mk4/modtcl/tcl8.3.4/doc/switch.n | 117 + mk4/modtcl/tcl8.3.4/doc/tclsh.1 | 127 + mk4/modtcl/tcl8.3.4/doc/tcltest.n | 759 ++ mk4/modtcl/tcl8.3.4/doc/tclvars.n | 401 + mk4/modtcl/tcl8.3.4/doc/tell.n | 35 + mk4/modtcl/tcl8.3.4/doc/time.n | 36 + mk4/modtcl/tcl8.3.4/doc/trace.n | 160 + mk4/modtcl/tcl8.3.4/doc/unknown.n | 78 + mk4/modtcl/tcl8.3.4/doc/unset.n | 34 + mk4/modtcl/tcl8.3.4/doc/update.n | 51 + mk4/modtcl/tcl8.3.4/doc/uplevel.n | 80 + mk4/modtcl/tcl8.3.4/doc/upvar.n | 112 + mk4/modtcl/tcl8.3.4/doc/variable.n | 66 + mk4/modtcl/tcl8.3.4/doc/vwait.n | 43 + mk4/modtcl/tcl8.3.4/doc/while.n | 58 + mk4/modtcl/tcl8.3.4/generic/CVS/Entries | 95 + mk4/modtcl/tcl8.3.4/generic/CVS/Repository | 1 + mk4/modtcl/tcl8.3.4/generic/CVS/Root | 1 + mk4/modtcl/tcl8.3.4/generic/CVS/Tag | 1 + mk4/modtcl/tcl8.3.4/generic/README | 5 + mk4/modtcl/tcl8.3.4/generic/regc_color.c | 778 ++ mk4/modtcl/tcl8.3.4/generic/regc_cvec.c | 198 + mk4/modtcl/tcl8.3.4/generic/regc_lex.c | 1061 ++ mk4/modtcl/tcl8.3.4/generic/regc_locale.c | 930 ++ mk4/modtcl/tcl8.3.4/generic/regc_nfa.c | 1575 +++ mk4/modtcl/tcl8.3.4/generic/regcomp.c | 2175 ++++ mk4/modtcl/tcl8.3.4/generic/regcustom.h | 114 + mk4/modtcl/tcl8.3.4/generic/rege_dfa.c | 677 ++ mk4/modtcl/tcl8.3.4/generic/regerror.c | 109 + mk4/modtcl/tcl8.3.4/generic/regerrs.h | 18 + mk4/modtcl/tcl8.3.4/generic/regex.h | 341 + mk4/modtcl/tcl8.3.4/generic/regexec.c | 1038 ++ mk4/modtcl/tcl8.3.4/generic/regfree.c | 53 + mk4/modtcl/tcl8.3.4/generic/regfronts.c | 83 + mk4/modtcl/tcl8.3.4/generic/regguts.h | 418 + mk4/modtcl/tcl8.3.4/generic/tcl.decls | 1722 ++++ mk4/modtcl/tcl8.3.4/generic/tcl.h | 1709 ++++ mk4/modtcl/tcl8.3.4/generic/tclAlloc.c | 722 ++ mk4/modtcl/tcl8.3.4/generic/tclAsync.c | 333 + mk4/modtcl/tcl8.3.4/generic/tclBasic.c | 4254 ++++++++ mk4/modtcl/tcl8.3.4/generic/tclBinary.c | 1551 +++ mk4/modtcl/tcl8.3.4/generic/tclCkalloc.c | 1028 ++ mk4/modtcl/tcl8.3.4/generic/tclClock.c | 376 + mk4/modtcl/tcl8.3.4/generic/tclCmdAH.c | 2407 +++++ mk4/modtcl/tcl8.3.4/generic/tclCmdIL.c | 3082 ++++++ mk4/modtcl/tcl8.3.4/generic/tclCmdMZ.c | 2892 ++++++ mk4/modtcl/tcl8.3.4/generic/tclCompCmds.c | 2023 ++++ mk4/modtcl/tcl8.3.4/generic/tclCompExpr.c | 1048 ++ mk4/modtcl/tcl8.3.4/generic/tclCompile.c | 3399 +++++++ mk4/modtcl/tcl8.3.4/generic/tclCompile.h | 977 ++ mk4/modtcl/tcl8.3.4/generic/tclDate.c | 1872 ++++ mk4/modtcl/tcl8.3.4/generic/tclDecls.h | 3465 +++++++ mk4/modtcl/tcl8.3.4/generic/tclEncoding.c | 2783 ++++++ mk4/modtcl/tcl8.3.4/generic/tclEnv.c | 679 ++ mk4/modtcl/tcl8.3.4/generic/tclEvent.c | 1087 ++ mk4/modtcl/tcl8.3.4/generic/tclExecute.c | 5177 ++++++++++ mk4/modtcl/tcl8.3.4/generic/tclFCmd.c | 841 ++ mk4/modtcl/tcl8.3.4/generic/tclFileName.c | 2132 ++++ mk4/modtcl/tcl8.3.4/generic/tclGet.c | 323 + mk4/modtcl/tcl8.3.4/generic/tclGetDate.y | 1156 +++ mk4/modtcl/tcl8.3.4/generic/tclHash.c | 926 ++ mk4/modtcl/tcl8.3.4/generic/tclHistory.c | 145 + mk4/modtcl/tcl8.3.4/generic/tclIO.c | 8263 +++++++++++++++ mk4/modtcl/tcl8.3.4/generic/tclIO.h | 390 + mk4/modtcl/tcl8.3.4/generic/tclIOCmd.c | 1543 +++ mk4/modtcl/tcl8.3.4/generic/tclIOGT.c | 1359 +++ mk4/modtcl/tcl8.3.4/generic/tclIOSock.c | 112 + mk4/modtcl/tcl8.3.4/generic/tclIOUtil.c | 876 ++ mk4/modtcl/tcl8.3.4/generic/tclIndexObj.c | 362 + mk4/modtcl/tcl8.3.4/generic/tclInitScript.h | 112 + mk4/modtcl/tcl8.3.4/generic/tclInt.decls | 899 ++ mk4/modtcl/tcl8.3.4/generic/tclInt.h | 2222 ++++ mk4/modtcl/tcl8.3.4/generic/tclIntDecls.h | 1407 +++ mk4/modtcl/tcl8.3.4/generic/tclIntPlatDecls.h | 542 + mk4/modtcl/tcl8.3.4/generic/tclInterp.c | 2368 +++++ mk4/modtcl/tcl8.3.4/generic/tclLink.c | 430 + mk4/modtcl/tcl8.3.4/generic/tclListObj.c | 1060 ++ mk4/modtcl/tcl8.3.4/generic/tclLiteral.c | 1054 ++ mk4/modtcl/tcl8.3.4/generic/tclLoad.c | 663 ++ mk4/modtcl/tcl8.3.4/generic/tclLoadNone.c | 112 + mk4/modtcl/tcl8.3.4/generic/tclMain.c | 581 ++ mk4/modtcl/tcl8.3.4/generic/tclMath.h | 27 + mk4/modtcl/tcl8.3.4/generic/tclNamesp.c | 3884 +++++++ mk4/modtcl/tcl8.3.4/generic/tclNotify.c | 1080 ++ mk4/modtcl/tcl8.3.4/generic/tclObj.c | 2073 ++++ mk4/modtcl/tcl8.3.4/generic/tclPanic.c | 123 + mk4/modtcl/tcl8.3.4/generic/tclParse.c | 2328 +++++ mk4/modtcl/tcl8.3.4/generic/tclParseExpr.c | 1852 ++++ mk4/modtcl/tcl8.3.4/generic/tclPipe.c | 1061 ++ mk4/modtcl/tcl8.3.4/generic/tclPkg.c | 979 ++ mk4/modtcl/tcl8.3.4/generic/tclPlatDecls.h | 161 + mk4/modtcl/tcl8.3.4/generic/tclPort.h | 31 + mk4/modtcl/tcl8.3.4/generic/tclPosixStr.c | 1174 +++ mk4/modtcl/tcl8.3.4/generic/tclPreserve.c | 490 + mk4/modtcl/tcl8.3.4/generic/tclProc.c | 1571 +++ mk4/modtcl/tcl8.3.4/generic/tclRegexp.c | 1029 ++ mk4/modtcl/tcl8.3.4/generic/tclRegexp.h | 51 + mk4/modtcl/tcl8.3.4/generic/tclResolve.c | 418 + mk4/modtcl/tcl8.3.4/generic/tclResult.c | 1052 ++ mk4/modtcl/tcl8.3.4/generic/tclScan.c | 1138 +++ mk4/modtcl/tcl8.3.4/generic/tclStringObj.c | 1620 +++ mk4/modtcl/tcl8.3.4/generic/tclStubInit.c | 819 ++ mk4/modtcl/tcl8.3.4/generic/tclStubLib.c | 117 + mk4/modtcl/tcl8.3.4/generic/tclTest.c | 4825 +++++++++ mk4/modtcl/tcl8.3.4/generic/tclTestObj.c | 1158 +++ .../tcl8.3.4/generic/tclTestProcBodyObj.c | 319 + mk4/modtcl/tcl8.3.4/generic/tclThread.c | 579 ++ mk4/modtcl/tcl8.3.4/generic/tclThreadTest.c | 966 ++ mk4/modtcl/tcl8.3.4/generic/tclTimer.c | 1128 +++ mk4/modtcl/tcl8.3.4/generic/tclUniData.c | 586 ++ mk4/modtcl/tcl8.3.4/generic/tclUtf.c | 1594 +++ mk4/modtcl/tcl8.3.4/generic/tclUtil.c | 2471 +++++ mk4/modtcl/tcl8.3.4/generic/tclVar.c | 4813 +++++++++ mk4/modtcl/tcl8.3.4/library/CVS/Entries | 18 + mk4/modtcl/tcl8.3.4/library/CVS/Repository | 1 + mk4/modtcl/tcl8.3.4/library/CVS/Root | 1 + mk4/modtcl/tcl8.3.4/library/CVS/Tag | 1 + mk4/modtcl/tcl8.3.4/library/auto.tcl | 569 ++ .../tcl8.3.4/library/dde1.1/CVS/Entries | 2 + .../tcl8.3.4/library/dde1.1/CVS/Repository | 1 + mk4/modtcl/tcl8.3.4/library/dde1.1/CVS/Root | 1 + mk4/modtcl/tcl8.3.4/library/dde1.1/CVS/Tag | 1 + .../tcl8.3.4/library/dde1.1/pkgIndex.tcl | 6 + .../tcl8.3.4/library/encoding/CVS/Entries | 78 + .../tcl8.3.4/library/encoding/CVS/Repository | 1 + mk4/modtcl/tcl8.3.4/library/encoding/CVS/Root | 1 + mk4/modtcl/tcl8.3.4/library/encoding/CVS/Tag | 1 + .../tcl8.3.4/library/encoding/ascii.enc | 20 + mk4/modtcl/tcl8.3.4/library/encoding/big5.enc | 1516 +++ .../tcl8.3.4/library/encoding/cp1250.enc | 20 + .../tcl8.3.4/library/encoding/cp1251.enc | 20 + .../tcl8.3.4/library/encoding/cp1252.enc | 20 + .../tcl8.3.4/library/encoding/cp1253.enc | 20 + .../tcl8.3.4/library/encoding/cp1254.enc | 20 + .../tcl8.3.4/library/encoding/cp1255.enc | 20 + .../tcl8.3.4/library/encoding/cp1256.enc | 20 + .../tcl8.3.4/library/encoding/cp1257.enc | 20 + .../tcl8.3.4/library/encoding/cp1258.enc | 20 + .../tcl8.3.4/library/encoding/cp437.enc | 20 + .../tcl8.3.4/library/encoding/cp737.enc | 20 + .../tcl8.3.4/library/encoding/cp775.enc | 20 + .../tcl8.3.4/library/encoding/cp850.enc | 20 + .../tcl8.3.4/library/encoding/cp852.enc | 20 + .../tcl8.3.4/library/encoding/cp855.enc | 20 + .../tcl8.3.4/library/encoding/cp857.enc | 20 + .../tcl8.3.4/library/encoding/cp860.enc | 20 + .../tcl8.3.4/library/encoding/cp861.enc | 20 + .../tcl8.3.4/library/encoding/cp862.enc | 20 + .../tcl8.3.4/library/encoding/cp863.enc | 20 + .../tcl8.3.4/library/encoding/cp864.enc | 20 + .../tcl8.3.4/library/encoding/cp865.enc | 20 + .../tcl8.3.4/library/encoding/cp866.enc | 20 + .../tcl8.3.4/library/encoding/cp869.enc | 20 + .../tcl8.3.4/library/encoding/cp874.enc | 20 + .../tcl8.3.4/library/encoding/cp932.enc | 785 ++ .../tcl8.3.4/library/encoding/cp936.enc | 2162 ++++ .../tcl8.3.4/library/encoding/cp949.enc | 2128 ++++ .../tcl8.3.4/library/encoding/cp950.enc | 1499 +++ .../tcl8.3.4/library/encoding/dingbats.enc | 20 + .../tcl8.3.4/library/encoding/ebcdic.enc | 19 + .../tcl8.3.4/library/encoding/euc-cn.enc | 1397 +++ .../tcl8.3.4/library/encoding/euc-jp.enc | 1346 +++ .../tcl8.3.4/library/encoding/euc-kr.enc | 1533 +++ .../tcl8.3.4/library/encoding/gb12345.enc | 1414 +++ .../tcl8.3.4/library/encoding/gb1988.enc | 20 + .../tcl8.3.4/library/encoding/gb2312.enc | 1380 +++ .../tcl8.3.4/library/encoding/iso2022-jp.enc | 12 + .../tcl8.3.4/library/encoding/iso2022-kr.enc | 7 + .../tcl8.3.4/library/encoding/iso2022.enc | 16 + .../tcl8.3.4/library/encoding/iso8859-1.enc | 20 + .../tcl8.3.4/library/encoding/iso8859-10.enc | 20 + .../tcl8.3.4/library/encoding/iso8859-13.enc | 20 + .../tcl8.3.4/library/encoding/iso8859-14.enc | 20 + .../tcl8.3.4/library/encoding/iso8859-15.enc | 20 + .../tcl8.3.4/library/encoding/iso8859-16.enc | 20 + .../tcl8.3.4/library/encoding/iso8859-2.enc | 20 + .../tcl8.3.4/library/encoding/iso8859-3.enc | 20 + .../tcl8.3.4/library/encoding/iso8859-4.enc | 20 + .../tcl8.3.4/library/encoding/iso8859-5.enc | 20 + .../tcl8.3.4/library/encoding/iso8859-6.enc | 20 + .../tcl8.3.4/library/encoding/iso8859-7.enc | 20 + .../tcl8.3.4/library/encoding/iso8859-8.enc | 20 + .../tcl8.3.4/library/encoding/iso8859-9.enc | 20 + .../tcl8.3.4/library/encoding/jis0201.enc | 20 + .../tcl8.3.4/library/encoding/jis0208.enc | 1312 +++ .../tcl8.3.4/library/encoding/jis0212.enc | 1159 +++ .../tcl8.3.4/library/encoding/koi8-r.enc | 20 + .../tcl8.3.4/library/encoding/koi8-u.enc | 20 + .../tcl8.3.4/library/encoding/ksc5601.enc | 1516 +++ .../tcl8.3.4/library/encoding/macCentEuro.enc | 20 + .../tcl8.3.4/library/encoding/macCroatian.enc | 20 + .../tcl8.3.4/library/encoding/macCyrillic.enc | 20 + .../tcl8.3.4/library/encoding/macDingbats.enc | 20 + .../tcl8.3.4/library/encoding/macGreek.enc | 20 + .../tcl8.3.4/library/encoding/macIceland.enc | 20 + .../tcl8.3.4/library/encoding/macJapan.enc | 785 ++ .../tcl8.3.4/library/encoding/macRoman.enc | 20 + .../tcl8.3.4/library/encoding/macRomania.enc | 20 + .../tcl8.3.4/library/encoding/macThai.enc | 20 + .../tcl8.3.4/library/encoding/macTurkish.enc | 20 + .../tcl8.3.4/library/encoding/macUkraine.enc | 20 + .../tcl8.3.4/library/encoding/shiftjis.enc | 683 ++ .../tcl8.3.4/library/encoding/symbol.enc | 20 + .../tcl8.3.4/library/encoding/tis-620.enc | 20 + mk4/modtcl/tcl8.3.4/library/history.tcl | 370 + mk4/modtcl/tcl8.3.4/library/http/CVS/Entries | 3 + .../tcl8.3.4/library/http/CVS/Repository | 1 + mk4/modtcl/tcl8.3.4/library/http/CVS/Root | 1 + mk4/modtcl/tcl8.3.4/library/http/CVS/Tag | 1 + mk4/modtcl/tcl8.3.4/library/http/http.tcl | 907 ++ mk4/modtcl/tcl8.3.4/library/http/pkgIndex.tcl | 12 + .../tcl8.3.4/library/http1.0/CVS/Entries | 3 + .../tcl8.3.4/library/http1.0/CVS/Repository | 1 + mk4/modtcl/tcl8.3.4/library/http1.0/CVS/Root | 1 + mk4/modtcl/tcl8.3.4/library/http1.0/CVS/Tag | 1 + mk4/modtcl/tcl8.3.4/library/http1.0/http.tcl | 379 + .../tcl8.3.4/library/http1.0/pkgIndex.tcl | 11 + mk4/modtcl/tcl8.3.4/library/init.tcl | 594 ++ mk4/modtcl/tcl8.3.4/library/ldAout.tcl | 233 + mk4/modtcl/tcl8.3.4/library/license.terms | 39 + .../tcl8.3.4/library/msgcat/CVS/Entries | 3 + .../tcl8.3.4/library/msgcat/CVS/Repository | 1 + mk4/modtcl/tcl8.3.4/library/msgcat/CVS/Root | 1 + mk4/modtcl/tcl8.3.4/library/msgcat/CVS/Tag | 1 + mk4/modtcl/tcl8.3.4/library/msgcat/msgcat.tcl | 205 + .../tcl8.3.4/library/msgcat/pkgIndex.tcl | 2 + mk4/modtcl/tcl8.3.4/library/opt/CVS/Entries | 3 + .../tcl8.3.4/library/opt/CVS/Repository | 1 + mk4/modtcl/tcl8.3.4/library/opt/CVS/Root | 1 + mk4/modtcl/tcl8.3.4/library/opt/CVS/Tag | 1 + mk4/modtcl/tcl8.3.4/library/opt/optparse.tcl | 1090 ++ mk4/modtcl/tcl8.3.4/library/opt/pkgIndex.tcl | 12 + mk4/modtcl/tcl8.3.4/library/package.tcl | 670 ++ mk4/modtcl/tcl8.3.4/library/parray.tcl | 29 + .../tcl8.3.4/library/reg1.0/CVS/Entries | 2 + .../tcl8.3.4/library/reg1.0/CVS/Repository | 1 + mk4/modtcl/tcl8.3.4/library/reg1.0/CVS/Root | 1 + mk4/modtcl/tcl8.3.4/library/reg1.0/CVS/Tag | 1 + .../tcl8.3.4/library/reg1.0/pkgIndex.tcl | 8 + mk4/modtcl/tcl8.3.4/library/safe.tcl | 922 ++ mk4/modtcl/tcl8.3.4/library/tclIndex | 82 + .../tcl8.3.4/library/tcltest1.0/CVS/Entries | 3 + .../library/tcltest1.0/CVS/Repository | 1 + .../tcl8.3.4/library/tcltest1.0/CVS/Root | 1 + .../tcl8.3.4/library/tcltest1.0/CVS/Tag | 1 + .../tcl8.3.4/library/tcltest1.0/pkgIndex.tcl | 19 + .../tcl8.3.4/library/tcltest1.0/tcltest.tcl | 1906 ++++ mk4/modtcl/tcl8.3.4/library/word.tcl | 132 + mk4/modtcl/tcl8.3.4/license.terms | 39 + mk4/modtcl/tcl8.3.4/mac/AppleScript.html | 298 + mk4/modtcl/tcl8.3.4/mac/Background.doc | 92 + mk4/modtcl/tcl8.3.4/mac/CVS/Entries | 57 + mk4/modtcl/tcl8.3.4/mac/CVS/Repository | 1 + mk4/modtcl/tcl8.3.4/mac/CVS/Root | 1 + mk4/modtcl/tcl8.3.4/mac/CVS/Tag | 1 + .../tcl8.3.4/mac/MW_TclAppleScriptHeader.h | 7 + .../tcl8.3.4/mac/MW_TclAppleScriptHeader.pch | 36 + .../tcl8.3.4/mac/MW_TclBuildLibHeader.h | 7 + .../tcl8.3.4/mac/MW_TclBuildLibHeader.pch | 35 + mk4/modtcl/tcl8.3.4/mac/MW_TclHeader.h | 7 + mk4/modtcl/tcl8.3.4/mac/MW_TclHeader.pch | 33 + mk4/modtcl/tcl8.3.4/mac/MW_TclHeaderCommon.h | 54 + mk4/modtcl/tcl8.3.4/mac/MW_TclStaticHeader.h | 7 + .../tcl8.3.4/mac/MW_TclStaticHeader.pch | 35 + mk4/modtcl/tcl8.3.4/mac/MW_TclTestHeader.h | 7 + mk4/modtcl/tcl8.3.4/mac/MW_TclTestHeader.pch | 41 + mk4/modtcl/tcl8.3.4/mac/README | 69 + mk4/modtcl/tcl8.3.4/mac/bugs.doc | 44 + mk4/modtcl/tcl8.3.4/mac/libmoto.doc | 39 + mk4/modtcl/tcl8.3.4/mac/license.terms | 39 + mk4/modtcl/tcl8.3.4/mac/morefiles.doc | 74 + mk4/modtcl/tcl8.3.4/mac/porting.notes | 23 + mk4/modtcl/tcl8.3.4/mac/tclMac.h | 28 + mk4/modtcl/tcl8.3.4/mac/tclMacAETE.r | 58 + mk4/modtcl/tcl8.3.4/mac/tclMacAlloc.c | 412 + mk4/modtcl/tcl8.3.4/mac/tclMacAppInit.c | 213 + mk4/modtcl/tcl8.3.4/mac/tclMacApplication.r | 113 + mk4/modtcl/tcl8.3.4/mac/tclMacBOAAppInit.c | 257 + mk4/modtcl/tcl8.3.4/mac/tclMacBOAMain.c | 361 + mk4/modtcl/tcl8.3.4/mac/tclMacChan.c | 1394 +++ mk4/modtcl/tcl8.3.4/mac/tclMacCommonPch.h | 71 + mk4/modtcl/tcl8.3.4/mac/tclMacDNR.c | 23 + mk4/modtcl/tcl8.3.4/mac/tclMacEnv.c | 536 + mk4/modtcl/tcl8.3.4/mac/tclMacExit.c | 333 + mk4/modtcl/tcl8.3.4/mac/tclMacFCmd.c | 1551 +++ mk4/modtcl/tcl8.3.4/mac/tclMacFile.c | 1040 ++ mk4/modtcl/tcl8.3.4/mac/tclMacInit.c | 752 ++ mk4/modtcl/tcl8.3.4/mac/tclMacInt.h | 77 + mk4/modtcl/tcl8.3.4/mac/tclMacInterupt.c | 289 + mk4/modtcl/tcl8.3.4/mac/tclMacLibrary.c | 248 + mk4/modtcl/tcl8.3.4/mac/tclMacLibrary.r | 207 + mk4/modtcl/tcl8.3.4/mac/tclMacLoad.c | 288 + mk4/modtcl/tcl8.3.4/mac/tclMacMath.h | 145 + mk4/modtcl/tcl8.3.4/mac/tclMacNotify.c | 580 ++ mk4/modtcl/tcl8.3.4/mac/tclMacOSA.c | 2949 ++++++ mk4/modtcl/tcl8.3.4/mac/tclMacOSA.r | 76 + mk4/modtcl/tcl8.3.4/mac/tclMacPanic.c | 236 + mk4/modtcl/tcl8.3.4/mac/tclMacPort.h | 320 + .../tcl8.3.4/mac/tclMacProjects.sea.hqx | 3854 +++++++ mk4/modtcl/tcl8.3.4/mac/tclMacResource.c | 2210 ++++ mk4/modtcl/tcl8.3.4/mac/tclMacResource.r | 57 + mk4/modtcl/tcl8.3.4/mac/tclMacSock.c | 2766 +++++ mk4/modtcl/tcl8.3.4/mac/tclMacTclCode.r | 37 + mk4/modtcl/tcl8.3.4/mac/tclMacTest.c | 213 + mk4/modtcl/tcl8.3.4/mac/tclMacThrd.c | 829 ++ mk4/modtcl/tcl8.3.4/mac/tclMacThrd.h | 20 + mk4/modtcl/tcl8.3.4/mac/tclMacTime.c | 432 + mk4/modtcl/tcl8.3.4/mac/tclMacUnix.c | 425 + mk4/modtcl/tcl8.3.4/mac/tclMacUtil.c | 463 + mk4/modtcl/tcl8.3.4/tests/CVS/Entries | 128 + mk4/modtcl/tcl8.3.4/tests/CVS/Repository | 1 + mk4/modtcl/tcl8.3.4/tests/CVS/Root | 1 + mk4/modtcl/tcl8.3.4/tests/CVS/Tag | 1 + mk4/modtcl/tcl8.3.4/tests/README | 147 + mk4/modtcl/tcl8.3.4/tests/all.tcl | 55 + mk4/modtcl/tcl8.3.4/tests/append.test | 195 + mk4/modtcl/tcl8.3.4/tests/assocd.test | 78 + mk4/modtcl/tcl8.3.4/tests/async.test | 151 + mk4/modtcl/tcl8.3.4/tests/autoMkindex.tcl | 82 + mk4/modtcl/tcl8.3.4/tests/autoMkindex.test | 232 + mk4/modtcl/tcl8.3.4/tests/basic.test | 546 + mk4/modtcl/tcl8.3.4/tests/binary.test | 1465 +++ mk4/modtcl/tcl8.3.4/tests/case.test | 103 + mk4/modtcl/tcl8.3.4/tests/clock.test | 433 + mk4/modtcl/tcl8.3.4/tests/cmdAH.test | 1594 +++ mk4/modtcl/tcl8.3.4/tests/cmdIL.test | 361 + mk4/modtcl/tcl8.3.4/tests/cmdInfo.test | 117 + mk4/modtcl/tcl8.3.4/tests/cmdMZ.test | 170 + mk4/modtcl/tcl8.3.4/tests/compExpr-old.test | 690 ++ mk4/modtcl/tcl8.3.4/tests/compExpr.test | 341 + mk4/modtcl/tcl8.3.4/tests/compile.test | 215 + mk4/modtcl/tcl8.3.4/tests/concat.test | 66 + mk4/modtcl/tcl8.3.4/tests/dcall.test | 61 + mk4/modtcl/tcl8.3.4/tests/dstring.test | 268 + mk4/modtcl/tcl8.3.4/tests/encoding.test | 317 + mk4/modtcl/tcl8.3.4/tests/env.test | 261 + mk4/modtcl/tcl8.3.4/tests/error.test | 181 + mk4/modtcl/tcl8.3.4/tests/eval.test | 75 + mk4/modtcl/tcl8.3.4/tests/event.test | 590 ++ mk4/modtcl/tcl8.3.4/tests/exec.test | 606 ++ mk4/modtcl/tcl8.3.4/tests/execute.test | 621 ++ mk4/modtcl/tcl8.3.4/tests/expr-old.test | 949 ++ mk4/modtcl/tcl8.3.4/tests/expr.test | 729 ++ mk4/modtcl/tcl8.3.4/tests/fCmd.test | 2171 ++++ mk4/modtcl/tcl8.3.4/tests/fileName.test | 1613 +++ mk4/modtcl/tcl8.3.4/tests/for-old.test | 85 + mk4/modtcl/tcl8.3.4/tests/for.test | 756 ++ mk4/modtcl/tcl8.3.4/tests/foreach.test | 252 + mk4/modtcl/tcl8.3.4/tests/format.test | 513 + mk4/modtcl/tcl8.3.4/tests/get.test | 111 + mk4/modtcl/tcl8.3.4/tests/history.test | 231 + mk4/modtcl/tcl8.3.4/tests/http.test | 490 + mk4/modtcl/tcl8.3.4/tests/httpd | 218 + mk4/modtcl/tcl8.3.4/tests/httpold.test | 303 + mk4/modtcl/tcl8.3.4/tests/if-old.test | 176 + mk4/modtcl/tcl8.3.4/tests/if.test | 1092 ++ mk4/modtcl/tcl8.3.4/tests/incr-old.test | 107 + mk4/modtcl/tcl8.3.4/tests/incr.test | 520 + mk4/modtcl/tcl8.3.4/tests/indexObj.test | 87 + mk4/modtcl/tcl8.3.4/tests/info.test | 596 ++ mk4/modtcl/tcl8.3.4/tests/init.test | 169 + mk4/modtcl/tcl8.3.4/tests/interp.test | 2382 +++++ mk4/modtcl/tcl8.3.4/tests/io.test | 6745 +++++++++++++ mk4/modtcl/tcl8.3.4/tests/ioCmd.test | 546 + mk4/modtcl/tcl8.3.4/tests/ioUtil.test | 322 + mk4/modtcl/tcl8.3.4/tests/iogt.test | 940 ++ mk4/modtcl/tcl8.3.4/tests/join.test | 66 + mk4/modtcl/tcl8.3.4/tests/license.terms | 39 + mk4/modtcl/tcl8.3.4/tests/lindex.test | 82 + mk4/modtcl/tcl8.3.4/tests/link.test | 256 + mk4/modtcl/tcl8.3.4/tests/linsert.test | 115 + mk4/modtcl/tcl8.3.4/tests/list.test | 127 + mk4/modtcl/tcl8.3.4/tests/listObj.test | 200 + mk4/modtcl/tcl8.3.4/tests/llength.test | 55 + mk4/modtcl/tcl8.3.4/tests/load.test | 195 + mk4/modtcl/tcl8.3.4/tests/lrange.test | 91 + mk4/modtcl/tcl8.3.4/tests/lreplace.test | 138 + mk4/modtcl/tcl8.3.4/tests/lsearch.test | 106 + mk4/modtcl/tcl8.3.4/tests/macFCmd.test | 209 + mk4/modtcl/tcl8.3.4/tests/misc.test | 76 + mk4/modtcl/tcl8.3.4/tests/msgcat.test | 412 + mk4/modtcl/tcl8.3.4/tests/namespace-old.test | 864 ++ mk4/modtcl/tcl8.3.4/tests/namespace.test | 1116 +++ mk4/modtcl/tcl8.3.4/tests/obj.test | 547 + mk4/modtcl/tcl8.3.4/tests/opt.test | 282 + mk4/modtcl/tcl8.3.4/tests/osa.test | 48 + mk4/modtcl/tcl8.3.4/tests/package.test | 71 + mk4/modtcl/tcl8.3.4/tests/parse.test | 751 ++ mk4/modtcl/tcl8.3.4/tests/parseExpr.test | 638 ++ mk4/modtcl/tcl8.3.4/tests/parseOld.test | 551 + mk4/modtcl/tcl8.3.4/tests/pid.test | 71 + mk4/modtcl/tcl8.3.4/tests/pkg.test | 665 ++ mk4/modtcl/tcl8.3.4/tests/pkg/CVS/Entries | 20 + mk4/modtcl/tcl8.3.4/tests/pkg/CVS/Repository | 1 + mk4/modtcl/tcl8.3.4/tests/pkg/CVS/Root | 1 + mk4/modtcl/tcl8.3.4/tests/pkg/CVS/Tag | 1 + mk4/modtcl/tcl8.3.4/tests/pkg/circ1.tcl | 34 + mk4/modtcl/tcl8.3.4/tests/pkg/circ2.tcl | 25 + mk4/modtcl/tcl8.3.4/tests/pkg/circ3.tcl | 25 + mk4/modtcl/tcl8.3.4/tests/pkg/global.tcl | 19 + mk4/modtcl/tcl8.3.4/tests/pkg/import.tcl | 16 + mk4/modtcl/tcl8.3.4/tests/pkg/license.terms | 39 + mk4/modtcl/tcl8.3.4/tests/pkg/magicchar.tcl | 6 + mk4/modtcl/tcl8.3.4/tests/pkg/magicchar2.tcl | 1 + mk4/modtcl/tcl8.3.4/tests/pkg/pkg1.tcl | 26 + mk4/modtcl/tcl8.3.4/tests/pkg/pkg2_a.tcl | 22 + mk4/modtcl/tcl8.3.4/tests/pkg/pkg2_b.tcl | 22 + mk4/modtcl/tcl8.3.4/tests/pkg/pkg3.tcl | 22 + mk4/modtcl/tcl8.3.4/tests/pkg/pkg4.tcl | 27 + mk4/modtcl/tcl8.3.4/tests/pkg/pkg5.tcl | 30 + mk4/modtcl/tcl8.3.4/tests/pkg/pkga.tcl | 15 + mk4/modtcl/tcl8.3.4/tests/pkg/samename.tcl | 25 + mk4/modtcl/tcl8.3.4/tests/pkg/simple.tcl | 23 + mk4/modtcl/tcl8.3.4/tests/pkg/spacename.tcl | 3 + mk4/modtcl/tcl8.3.4/tests/pkg/std.tcl | 28 + mk4/modtcl/tcl8.3.4/tests/pkgMkIndex.test | 391 + mk4/modtcl/tcl8.3.4/tests/platform.test | 41 + mk4/modtcl/tcl8.3.4/tests/proc-old.test | 524 + mk4/modtcl/tcl8.3.4/tests/proc.test | 313 + mk4/modtcl/tcl8.3.4/tests/pwd.test | 42 + mk4/modtcl/tcl8.3.4/tests/reg.test | 994 ++ mk4/modtcl/tcl8.3.4/tests/regexp.test | 540 + mk4/modtcl/tcl8.3.4/tests/registry.test | 602 ++ mk4/modtcl/tcl8.3.4/tests/remote.tcl | 172 + mk4/modtcl/tcl8.3.4/tests/rename.test | 180 + mk4/modtcl/tcl8.3.4/tests/resource.test | 365 + mk4/modtcl/tcl8.3.4/tests/result.test | 103 + mk4/modtcl/tcl8.3.4/tests/safe.test | 532 + mk4/modtcl/tcl8.3.4/tests/scan.test | 661 ++ mk4/modtcl/tcl8.3.4/tests/security.test | 54 + mk4/modtcl/tcl8.3.4/tests/set-old.test | 821 ++ mk4/modtcl/tcl8.3.4/tests/set.test | 520 + mk4/modtcl/tcl8.3.4/tests/socket.test | 1640 +++ mk4/modtcl/tcl8.3.4/tests/source.test | 198 + mk4/modtcl/tcl8.3.4/tests/split.test | 86 + mk4/modtcl/tcl8.3.4/tests/stack.test | 60 + mk4/modtcl/tcl8.3.4/tests/string.test | 1239 +++ mk4/modtcl/tcl8.3.4/tests/stringObj.test | 434 + mk4/modtcl/tcl8.3.4/tests/subst.test | 178 + mk4/modtcl/tcl8.3.4/tests/switch.test | 199 + mk4/modtcl/tcl8.3.4/tests/tcltest.test | 406 + mk4/modtcl/tcl8.3.4/tests/thread.test | 235 + mk4/modtcl/tcl8.3.4/tests/timer.test | 555 + mk4/modtcl/tcl8.3.4/tests/trace.test | 1001 ++ mk4/modtcl/tcl8.3.4/tests/unixFCmd.test | 328 + mk4/modtcl/tcl8.3.4/tests/unixFile.test | 78 + mk4/modtcl/tcl8.3.4/tests/unixInit.test | 283 + mk4/modtcl/tcl8.3.4/tests/unixNotfy.test | 106 + mk4/modtcl/tcl8.3.4/tests/unknown.test | 79 + mk4/modtcl/tcl8.3.4/tests/uplevel.test | 129 + mk4/modtcl/tcl8.3.4/tests/upvar.test | 417 + mk4/modtcl/tcl8.3.4/tests/utf.test | 293 + mk4/modtcl/tcl8.3.4/tests/util.test | 311 + mk4/modtcl/tcl8.3.4/tests/var.test | 665 ++ mk4/modtcl/tcl8.3.4/tests/while-old.test | 133 + mk4/modtcl/tcl8.3.4/tests/while.test | 634 ++ mk4/modtcl/tcl8.3.4/tests/winConsole.test | 52 + mk4/modtcl/tcl8.3.4/tests/winDde.test | 168 + mk4/modtcl/tcl8.3.4/tests/winFCmd.test | 1007 ++ mk4/modtcl/tcl8.3.4/tests/winFile.test | 79 + mk4/modtcl/tcl8.3.4/tests/winNotify.test | 174 + mk4/modtcl/tcl8.3.4/tests/winPipe.test | 306 + mk4/modtcl/tcl8.3.4/tests/winTime.test | 50 + mk4/modtcl/tcl8.3.4/tools/CVS/Entries | 24 + mk4/modtcl/tcl8.3.4/tools/CVS/Repository | 1 + mk4/modtcl/tcl8.3.4/tools/CVS/Root | 1 + mk4/modtcl/tcl8.3.4/tools/CVS/Tag | 1 + mk4/modtcl/tcl8.3.4/tools/Makefile.in | 69 + mk4/modtcl/tcl8.3.4/tools/README | 28 + mk4/modtcl/tcl8.3.4/tools/checkLibraryDoc.tcl | 296 + mk4/modtcl/tcl8.3.4/tools/configure | 817 ++ mk4/modtcl/tcl8.3.4/tools/configure.in | 33 + mk4/modtcl/tcl8.3.4/tools/cvtEOL.tcl | 35 + mk4/modtcl/tcl8.3.4/tools/genStubs.tcl | 896 ++ mk4/modtcl/tcl8.3.4/tools/genWinImage.tcl | 157 + mk4/modtcl/tcl8.3.4/tools/index.tcl | 202 + mk4/modtcl/tcl8.3.4/tools/man2help.tcl | 130 + mk4/modtcl/tcl8.3.4/tools/man2help2.tcl | 969 ++ mk4/modtcl/tcl8.3.4/tools/man2html.tcl | 181 + mk4/modtcl/tcl8.3.4/tools/man2html1.tcl | 269 + mk4/modtcl/tcl8.3.4/tools/man2html2.tcl | 871 ++ mk4/modtcl/tcl8.3.4/tools/man2tcl.c | 405 + mk4/modtcl/tcl8.3.4/tools/regexpTestLib.tcl | 266 + mk4/modtcl/tcl8.3.4/tools/tcl.hpj.in | 19 + mk4/modtcl/tcl8.3.4/tools/tcl.wse.in | 2333 +++++ mk4/modtcl/tcl8.3.4/tools/tclSplash.bmp | Bin 0 -> 162030 bytes mk4/modtcl/tcl8.3.4/tools/tcltk-man2html.tcl | 1675 ++++ mk4/modtcl/tcl8.3.4/tools/uniClass.tcl | 61 + mk4/modtcl/tcl8.3.4/tools/uniParse.tcl | 386 + mk4/modtcl/tcl8.3.4/tools/white.bmp | Bin 0 -> 20522 bytes mk4/modtcl/tcl8.3.4/unix/.cvsignore | 6 + mk4/modtcl/tcl8.3.4/unix/CVS/Entries | 38 + mk4/modtcl/tcl8.3.4/unix/CVS/Repository | 1 + mk4/modtcl/tcl8.3.4/unix/CVS/Root | 1 + mk4/modtcl/tcl8.3.4/unix/CVS/Tag | 1 + mk4/modtcl/tcl8.3.4/unix/Makefile.in | 1348 +++ mk4/modtcl/tcl8.3.4/unix/README | 135 + mk4/modtcl/tcl8.3.4/unix/aclocal.m4 | 1 + mk4/modtcl/tcl8.3.4/unix/configure | 6571 ++++++++++++ mk4/modtcl/tcl8.3.4/unix/configure.in | 548 + mk4/modtcl/tcl8.3.4/unix/dltest/CVS/Entries | 11 + .../tcl8.3.4/unix/dltest/CVS/Repository | 1 + mk4/modtcl/tcl8.3.4/unix/dltest/CVS/Root | 1 + mk4/modtcl/tcl8.3.4/unix/dltest/CVS/Tag | 1 + mk4/modtcl/tcl8.3.4/unix/dltest/Makefile.in | 47 + mk4/modtcl/tcl8.3.4/unix/dltest/README | 12 + mk4/modtcl/tcl8.3.4/unix/dltest/configure | 813 ++ mk4/modtcl/tcl8.3.4/unix/dltest/configure.in | 33 + mk4/modtcl/tcl8.3.4/unix/dltest/pkga.c | 130 + mk4/modtcl/tcl8.3.4/unix/dltest/pkgb.c | 164 + mk4/modtcl/tcl8.3.4/unix/dltest/pkgc.c | 164 + mk4/modtcl/tcl8.3.4/unix/dltest/pkgd.c | 165 + mk4/modtcl/tcl8.3.4/unix/dltest/pkge.c | 46 + mk4/modtcl/tcl8.3.4/unix/dltest/pkgf.c | 53 + mk4/modtcl/tcl8.3.4/unix/install-sh | 124 + mk4/modtcl/tcl8.3.4/unix/ldAix | 74 + mk4/modtcl/tcl8.3.4/unix/mkLinks | 1026 ++ mk4/modtcl/tcl8.3.4/unix/tcl.m4 | 1945 ++++ mk4/modtcl/tcl8.3.4/unix/tcl.spec | 53 + mk4/modtcl/tcl8.3.4/unix/tclAppInit.c | 182 + mk4/modtcl/tcl8.3.4/unix/tclConfig.sh.in | 172 + mk4/modtcl/tcl8.3.4/unix/tclLoadAix.c | 549 + mk4/modtcl/tcl8.3.4/unix/tclLoadAout.c | 511 + mk4/modtcl/tcl8.3.4/unix/tclLoadDl.c | 183 + mk4/modtcl/tcl8.3.4/unix/tclLoadDld.c | 162 + mk4/modtcl/tcl8.3.4/unix/tclLoadDyld.c | 162 + mk4/modtcl/tcl8.3.4/unix/tclLoadNext.c | 142 + mk4/modtcl/tcl8.3.4/unix/tclLoadOSF.c | 160 + mk4/modtcl/tcl8.3.4/unix/tclLoadShl.c | 174 + mk4/modtcl/tcl8.3.4/unix/tclMtherr.c | 80 + mk4/modtcl/tcl8.3.4/unix/tclUnixChan.c | 2747 +++++ mk4/modtcl/tcl8.3.4/unix/tclUnixEvent.c | 76 + mk4/modtcl/tcl8.3.4/unix/tclUnixFCmd.c | 1611 +++ mk4/modtcl/tcl8.3.4/unix/tclUnixFile.c | 696 ++ mk4/modtcl/tcl8.3.4/unix/tclUnixInit.c | 799 ++ mk4/modtcl/tcl8.3.4/unix/tclUnixNotfy.c | 1033 ++ mk4/modtcl/tcl8.3.4/unix/tclUnixPipe.c | 1199 +++ mk4/modtcl/tcl8.3.4/unix/tclUnixPort.h | 513 + mk4/modtcl/tcl8.3.4/unix/tclUnixSock.c | 135 + mk4/modtcl/tcl8.3.4/unix/tclUnixTest.c | 708 ++ mk4/modtcl/tcl8.3.4/unix/tclUnixThrd.c | 735 ++ mk4/modtcl/tcl8.3.4/unix/tclUnixThrd.h | 21 + mk4/modtcl/tcl8.3.4/unix/tclUnixTime.c | 310 + mk4/modtcl/tcl8.3.4/unix/tclXtNotify.c | 668 ++ mk4/modtcl/tcl8.3.4/unix/tclXtTest.c | 120 + mk4/modtcl/tcl8.3.4/win/CVS/Entries | 40 + mk4/modtcl/tcl8.3.4/win/CVS/Repository | 1 + mk4/modtcl/tcl8.3.4/win/CVS/Root | 1 + mk4/modtcl/tcl8.3.4/win/CVS/Tag | 1 + mk4/modtcl/tcl8.3.4/win/Makefile.in | 573 ++ mk4/modtcl/tcl8.3.4/win/README | 61 + mk4/modtcl/tcl8.3.4/win/aclocal.m4 | 1 + mk4/modtcl/tcl8.3.4/win/cat.c | 37 + mk4/modtcl/tcl8.3.4/win/configure | 2397 +++++ mk4/modtcl/tcl8.3.4/win/configure.in | 248 + mk4/modtcl/tcl8.3.4/win/license.terms | 39 + mk4/modtcl/tcl8.3.4/win/makefile.vc | 544 + mk4/modtcl/tcl8.3.4/win/mkd.bat | 20 + mk4/modtcl/tcl8.3.4/win/rmd.bat | 25 + mk4/modtcl/tcl8.3.4/win/stub16.c | 198 + mk4/modtcl/tcl8.3.4/win/tcl.hpj.in | 19 + mk4/modtcl/tcl8.3.4/win/tcl.m4 | 661 ++ mk4/modtcl/tcl8.3.4/win/tcl.rc | 61 + mk4/modtcl/tcl8.3.4/win/tclAppInit.c | 301 + mk4/modtcl/tcl8.3.4/win/tclConfig.sh.in | 174 + mk4/modtcl/tcl8.3.4/win/tclWin32Dll.c | 492 + mk4/modtcl/tcl8.3.4/win/tclWinChan.c | 1189 +++ mk4/modtcl/tcl8.3.4/win/tclWinConsole.c | 1269 +++ mk4/modtcl/tcl8.3.4/win/tclWinDde.c | 1350 +++ mk4/modtcl/tcl8.3.4/win/tclWinError.c | 392 + mk4/modtcl/tcl8.3.4/win/tclWinFCmd.c | 1664 +++ mk4/modtcl/tcl8.3.4/win/tclWinFile.c | 1058 ++ mk4/modtcl/tcl8.3.4/win/tclWinInit.c | 832 ++ mk4/modtcl/tcl8.3.4/win/tclWinInt.h | 108 + mk4/modtcl/tcl8.3.4/win/tclWinLoad.c | 195 + mk4/modtcl/tcl8.3.4/win/tclWinMtherr.c | 52 + mk4/modtcl/tcl8.3.4/win/tclWinNotify.c | 507 + mk4/modtcl/tcl8.3.4/win/tclWinPipe.c | 2875 ++++++ mk4/modtcl/tcl8.3.4/win/tclWinPort.h | 453 + mk4/modtcl/tcl8.3.4/win/tclWinReg.c | 1414 +++ mk4/modtcl/tcl8.3.4/win/tclWinSerial.c | 1206 +++ mk4/modtcl/tcl8.3.4/win/tclWinSock.c | 2456 +++++ mk4/modtcl/tcl8.3.4/win/tclWinTest.c | 190 + mk4/modtcl/tcl8.3.4/win/tclWinThrd.c | 911 ++ mk4/modtcl/tcl8.3.4/win/tclWinThrd.h | 21 + mk4/modtcl/tcl8.3.4/win/tclWinTime.c | 442 + mk4/modtcl/tcl8.3.4/win/tclsh.ico | Bin 0 -> 3630 bytes mk4/modtcl/tcl8.3.4/win/tclsh.rc | 73 + CMakeLists.txt => mk5/CMakeLists.txt | 0 README.md => mk5/README.md | 0 {aura => mk5/aura}/CMakeLists.txt | 0 mk5/aura/basictypes.c | 72 + mk5/aura/basictypes.h | 10 + mk5/aura/iterator.c | 52 + mk5/aura/iterator.h | 35 + {aura => mk5/aura}/list_iterator.c | 0 mk5/aura/list_iterator.h | 10 + {aura => mk5/aura}/memutil.c | 0 mk5/aura/memutil.h | 8 + {aura => mk5/aura}/serialization.c | 0 {aura => mk5/aura}/serialization.h | 0 mk5/aura/serializationinfo.c | 66 + {aura => mk5/aura}/serializationinfo.h | 0 {aura => mk5/aura}/stringdictionary.c | 0 {aura => mk5/aura}/stringdictionary.h | 0 {aura => mk5/aura}/type.h | 0 mk5/aura/typelocator.c | 146 + mk5/aura/typelocator.h | 10 + {continuity => mk5/continuity}/CMakeLists.txt | 0 {continuity => mk5/continuity}/continuity.c | 0 {continuity => mk5/continuity}/continuity.h | 0 {continuity => mk5/continuity}/dis.c | 0 {continuity => mk5/continuity}/dl.c | 0 mk5/continuity/mecha_dep.h | 47 + {continuity => mk5/continuity}/mmc.c | 0 {continuity => mk5/continuity}/tas.c | 0 {continuity => mk5/continuity}/xfr.c | 0 conventions.txt => mk5/conventions.txt | 0 mk5/example/base.xml | 236 + mk5/example/beacon.xml | 32 + mk5/example/config.xml | 240 + mk5/example/config.xml-dist | 228 + mk5/example/dotnet.xml | 246 + mk5/example/dynamo.xml | 239 + mk5/example/harmony.xml | 244 + mk5/example/phpdev.xml | 231 + mk5/example/radius.xml | 42 + mk5/example/ssl.xml | 235 + mk5/example/winkfep.xml | 305 + {mecha => mk5/mecha}/CMakeLists.txt | 0 {mecha => mk5/mecha}/ast.c | 0 {mecha => mk5/mecha}/b64.c | 0 {mecha => mk5/mecha}/bsp.c | 0 {mecha => mk5/mecha}/crc.c | 0 {mecha => mk5/mecha}/dic.c | 0 {mecha => mk5/mecha}/dyn.c | 0 {mecha => mk5/mecha}/dyn.h | 0 {mecha => mk5/mecha}/exp.c | 0 {mecha => mk5/mecha}/fle.c | 0 {mecha => mk5/mecha}/hsh.c | 0 {mecha => mk5/mecha}/log.c | 0 {mecha => mk5/mecha}/lst.c | 0 {mecha => mk5/mecha}/lst.h | 0 {mecha => mk5/mecha}/lst_void.c | 0 {mecha => mk5/mecha}/map.c | 0 {mecha => mk5/mecha}/mecha.c | 0 {mecha => mk5/mecha}/mecha.h | 0 {mecha => mk5/mecha}/mem.c | 0 {mecha => mk5/mecha}/net.c | 0 {mecha => mk5/mecha}/net.h | 0 {mecha => mk5/mecha}/pat.c | 0 {mecha => mk5/mecha}/qry.c | 0 {mecha => mk5/mecha}/rnd.c | 0 {mecha => mk5/mecha}/str.c | 0 {mecha => mk5/mecha}/thr.c | 0 {mecha => mk5/mecha}/tls.c | 0 {mecha => mk5/mecha}/uid.c | 0 {mecha => mk5/mecha}/utl.c | 0 {mecha => mk5/mecha}/xml.c | 0 {modhttp => mk5/modhttp}/CMakeLists.txt | 0 {modhttp => mk5/modhttp}/http.c | 0 {modhttp => mk5/modhttp}/http.cbp | 0 {modhttp => mk5/modhttp}/http.h | 0 {modm3 => mk5/modm3}/CMakeLists.txt | 0 mk5/modm3/_build.h | 1 + {modm3 => mk5/modm3}/file_catalog.c | 0 mk5/modm3/file_catalog.h | 15 + {modm3 => mk5/modm3}/file_entry.c | 0 mk5/modm3/file_entry.h | 18 + {modm3 => mk5/modm3}/file_reader.c | 0 mk5/modm3/file_reader.h | 10 + mk5/modm3/idata_reader.h | 21 + {modm3 => mk5/modm3}/iplaylist.h | 0 mk5/modm3/ixtime.c | 91 + mk5/modm3/ixtime.h | 12 + {modm3 => mk5/modm3}/m3.c | 0 {modm3 => mk5/modm3}/m3.h | 0 {modm3 => mk5/modm3}/m3_client.c | 0 {modm3 => mk5/modm3}/m3_client.h | 0 {modm3 => mk5/modm3}/m3_server.c | 0 {modm3 => mk5/modm3}/m3_server.h | 0 {modm3 => mk5/modm3}/m3_server_factory.c | 0 mk5/modm3/m3_server_factory.h | 14 + {modm3 => mk5/modm3}/m3_tcl.c | 0 mk5/modm3/m3_tcl.h | 6 + mk5/modm3/mp3_frame.c | 54 + mk5/modm3/mp3_frame.h | 28 + {modm3 => mk5/modm3}/mp3_reader.c | 0 {modm3 => mk5/modm3}/mp3_reader.h | 0 {modm3 => mk5/modm3}/music_packet.c | 0 {modm3 => mk5/modm3}/music_packet.h | 0 {modm3 => mk5/modm3}/order_playlist_engine.c | 0 mk5/modm3/order_playlist_engine.h | 6 + {modm3 => mk5/modm3}/playlist.c | 0 {modm3 => mk5/modm3}/playlist.h | 0 .../modm3}/playlist_engine_factory.c | 0 mk5/modm3/playlist_engine_factory.h | 14 + {modm3 => mk5/modm3}/playlist_manager.c | 0 {modm3 => mk5/modm3}/playlist_manager.h | 0 {modm3 => mk5/modm3}/queue_playlist_engine.c | 0 mk5/modm3/queue_playlist_engine.h | 8 + mk5/modm3/randomlist_playlist_engine.c | 377 + mk5/modm3/randomlist_playlist_engine.h | 8 + .../modm3}/shoutcast_metadata_writer.c | 0 mk5/modm3/shoutcast_metadata_writer.h | 13 + mk5/modm3/support.c | 57 + mk5/modm3/support.h | 12 + .../modsite}/CMakeFiles/progress.marks | 0 .../CMakeFiles/site.dir/C.includecache | 0 .../CMakeFiles/site.dir/DependInfo.cmake | 0 .../modsite}/CMakeFiles/site.dir/build.make | 0 .../CMakeFiles/site.dir/cmake_clean.cmake | 0 .../CMakeFiles/site.dir/depend.internal | 0 .../modsite}/CMakeFiles/site.dir/depend.make | 0 .../modsite}/CMakeFiles/site.dir/flags.make | 0 .../modsite}/CMakeFiles/site.dir/link.txt | 0 .../modsite}/CMakeFiles/site.dir/log.c.o | Bin .../CMakeFiles/site.dir/progress.make | 0 .../modsite}/CMakeFiles/site.dir/site.c.o | Bin {modsite => mk5/modsite}/CMakeLists.txt | 0 {modsite => mk5/modsite}/log.c | 0 {modsite => mk5/modsite}/site.c | 0 {modsite => mk5/modsite}/site.h | 0 mk5/modsite/siteerror.h | 36 + {modtcl => mk5/modtcl}/CMakeLists.txt | 0 {modtcl => mk5/modtcl}/cmds.c | 0 {modtcl => mk5/modtcl}/modtcl.c | 0 {modtcl => mk5/modtcl}/modtcl.h | 0 mk5/modtcl/modtcl.xml | 8 + {sandbox => mk5/sandbox}/CMakeLists.txt | 0 {sandbox => mk5/sandbox}/sandbox.c | 0 1674 files changed, 487770 insertions(+) create mode 100644 mk4/CVS/Entries create mode 100644 mk4/CVS/Repository create mode 100644 mk4/CVS/Root create mode 100644 mk4/CVS/Tag create mode 100644 mk4/Makefile.in create mode 100644 mk4/buildconf create mode 100644 mk4/config.guess create mode 100644 mk4/config.sub create mode 100644 mk4/configure.in create mode 100644 mk4/continuity/.cvsignore create mode 100644 mk4/continuity/CVS/Entries create mode 100644 mk4/continuity/CVS/Repository create mode 100644 mk4/continuity/CVS/Root create mode 100644 mk4/continuity/CVS/Tag create mode 100644 mk4/continuity/ChangeLog create mode 100644 mk4/continuity/Makefile.in create mode 100644 mk4/continuity/TODO create mode 100644 mk4/continuity/bin/.cvsignore create mode 100644 mk4/continuity/bin/CVS/Entries create mode 100644 mk4/continuity/bin/CVS/Repository create mode 100644 mk4/continuity/bin/CVS/Root create mode 100644 mk4/continuity/bin/CVS/Tag rename {example => mk4/continuity/bin}/base.xml (100%) rename {example => mk4/continuity/bin}/beacon.xml (100%) rename {example => mk4/continuity/bin}/config.xml (100%) rename {example => mk4/continuity/bin}/config.xml-dist (100%) rename {example => mk4/continuity/bin}/dotnet.xml (100%) rename {example => mk4/continuity/bin}/dynamo.xml (100%) rename {example => mk4/continuity/bin}/harmony.xml (100%) rename {example => mk4/continuity/bin}/phpdev.xml (100%) rename {example => mk4/continuity/bin}/radius.xml (100%) rename {example => mk4/continuity/bin}/ssl.xml (100%) rename {example => mk4/continuity/bin}/winkfep.xml (100%) create mode 100644 mk4/continuity/config.guess create mode 100644 mk4/continuity/config.sub create mode 100644 mk4/continuity/configure.in create mode 100644 mk4/continuity/cont/.cvsignore create mode 100644 mk4/continuity/cont/CVS/Entries create mode 100644 mk4/continuity/cont/CVS/Repository create mode 100644 mk4/continuity/cont/CVS/Root create mode 100644 mk4/continuity/cont/CVS/Tag create mode 100644 mk4/continuity/cont/Makefile.in create mode 100644 mk4/continuity/cont/cdog.c create mode 100644 mk4/continuity/cont/continuity.c create mode 100644 mk4/continuity/cont/dis.c create mode 100644 mk4/continuity/cont/dl.c create mode 100644 mk4/continuity/cont/mmc.c create mode 100644 mk4/continuity/cont/tas.c create mode 100644 mk4/continuity/cont/xfr.c create mode 100644 mk4/continuity/include/.cvsignore create mode 100644 mk4/continuity/include/CVS/Entries create mode 100644 mk4/continuity/include/CVS/Repository create mode 100644 mk4/continuity/include/CVS/Root create mode 100644 mk4/continuity/include/CVS/Tag create mode 100644 mk4/continuity/include/config.h.in create mode 100644 mk4/continuity/include/continuity.h create mode 100644 mk4/continuity/include/csys.h create mode 100644 mk4/continuity/include/cwin32.h create mode 100644 mk4/continuity/include/mecha.h rename {continuity => mk4/continuity/include}/mecha_dep.h (100%) create mode 100644 mk4/continuity/install-sh create mode 100644 mk4/continuity/lib/.cvsignore create mode 100644 mk4/continuity/lib/CVS/Entries create mode 100644 mk4/continuity/lib/CVS/Repository create mode 100644 mk4/continuity/lib/CVS/Root create mode 100644 mk4/continuity/lib/CVS/Tag create mode 100644 mk4/continuity/lib/build.mk create mode 100644 mk4/continuity/lib/env.mk.in create mode 100644 mk4/continuity/mecha/CVS/Entries create mode 100644 mk4/continuity/mecha/CVS/Repository create mode 100644 mk4/continuity/mecha/CVS/Root create mode 100644 mk4/continuity/mecha/CVS/Tag create mode 100644 mk4/continuity/mecha/Makefile.in create mode 100644 mk4/continuity/mecha/ast.c create mode 100644 mk4/continuity/mecha/b64.c create mode 100644 mk4/continuity/mecha/bsp.c create mode 100644 mk4/continuity/mecha/bus.c create mode 100644 mk4/continuity/mecha/crc.c create mode 100644 mk4/continuity/mecha/cv.c create mode 100644 mk4/continuity/mecha/dic.c create mode 100644 mk4/continuity/mecha/dyn.c create mode 100644 mk4/continuity/mecha/dyn.h create mode 100644 mk4/continuity/mecha/exp.c create mode 100644 mk4/continuity/mecha/fle.c create mode 100644 mk4/continuity/mecha/hsh.c create mode 100644 mk4/continuity/mecha/hsh_dep.c create mode 100644 mk4/continuity/mecha/log.c create mode 100644 mk4/continuity/mecha/lst.c create mode 100644 mk4/continuity/mecha/lst.h create mode 100644 mk4/continuity/mecha/lst_void.c create mode 100644 mk4/continuity/mecha/mecha.c create mode 100644 mk4/continuity/mecha/mem.c create mode 100644 mk4/continuity/mecha/net.c create mode 100644 mk4/continuity/mecha/net.h create mode 100644 mk4/continuity/mecha/pat.c create mode 100644 mk4/continuity/mecha/qry.c create mode 100644 mk4/continuity/mecha/rnd.c create mode 100644 mk4/continuity/mecha/str.c create mode 100644 mk4/continuity/mecha/sys.c create mode 100644 mk4/continuity/mecha/thr.c create mode 100644 mk4/continuity/mecha/tls.c create mode 100644 mk4/continuity/mecha/uid.c create mode 100644 mk4/continuity/mecha/utl.c create mode 100644 mk4/continuity/mecha/w32.c create mode 100644 mk4/continuity/mecha/xml.c create mode 100644 mk4/continuity/pcre/.cvsignore create mode 100644 mk4/continuity/pcre/AUTHORS create mode 100644 mk4/continuity/pcre/COPYING create mode 100644 mk4/continuity/pcre/CVS/Entries create mode 100644 mk4/continuity/pcre/CVS/Repository create mode 100644 mk4/continuity/pcre/CVS/Root create mode 100644 mk4/continuity/pcre/CVS/Tag create mode 100644 mk4/continuity/pcre/ChangeLog create mode 100644 mk4/continuity/pcre/INSTALL create mode 100644 mk4/continuity/pcre/LICENCE create mode 100644 mk4/continuity/pcre/Makefile.in create mode 100644 mk4/continuity/pcre/NEWS create mode 100644 mk4/continuity/pcre/NON-UNIX-USE create mode 100644 mk4/continuity/pcre/README create mode 100644 mk4/continuity/pcre/RunTest.in create mode 100644 mk4/continuity/pcre/config.guess create mode 100644 mk4/continuity/pcre/config.in create mode 100644 mk4/continuity/pcre/config.sub create mode 100644 mk4/continuity/pcre/configure create mode 100644 mk4/continuity/pcre/configure.in create mode 100644 mk4/continuity/pcre/dftables.c create mode 100644 mk4/continuity/pcre/get.c create mode 100644 mk4/continuity/pcre/install-sh create mode 100644 mk4/continuity/pcre/internal.h create mode 100644 mk4/continuity/pcre/ltmain.sh create mode 100644 mk4/continuity/pcre/maketables.c create mode 100644 mk4/continuity/pcre/makevp.bat create mode 100644 mk4/continuity/pcre/mkinstalldirs create mode 100644 mk4/continuity/pcre/pcre-config.in create mode 100644 mk4/continuity/pcre/pcre.c create mode 100644 mk4/continuity/pcre/pcre.def create mode 100644 mk4/continuity/pcre/pcre.in create mode 100644 mk4/continuity/pcre/pcredemo.c create mode 100644 mk4/continuity/pcre/pcregrep.c create mode 100644 mk4/continuity/pcre/pcreposix.c create mode 100644 mk4/continuity/pcre/pcreposix.h create mode 100644 mk4/continuity/pcre/pcretest.c create mode 100644 mk4/continuity/pcre/perltest create mode 100644 mk4/continuity/pcre/printint.c create mode 100644 mk4/continuity/pcre/study.c create mode 100644 mk4/continuity/todoc create mode 100644 mk4/doc/CVS/Entries create mode 100644 mk4/doc/CVS/Repository create mode 100644 mk4/doc/CVS/Root create mode 100644 mk4/doc/CVS/Tag create mode 100644 mk4/doc/standards.txt create mode 100644 mk4/httpclient/CVS/Entries create mode 100644 mk4/httpclient/CVS/Repository create mode 100644 mk4/httpclient/CVS/Root create mode 100644 mk4/httpclient/CVS/Tag create mode 100644 mk4/httpclient/Makefile create mode 100644 mk4/httpclient/httpclient.c create mode 100644 mk4/install-sh create mode 100644 mk4/lib/CVS/Entries create mode 100644 mk4/lib/CVS/Repository create mode 100644 mk4/lib/CVS/Root create mode 100644 mk4/lib/CVS/Tag create mode 100644 mk4/lib/aura/CVS/Entries create mode 100644 mk4/lib/aura/CVS/Repository create mode 100644 mk4/lib/aura/CVS/Root create mode 100644 mk4/lib/aura/CVS/Tag create mode 100644 mk4/lib/aura/Makefile create mode 100644 mk4/lib/aura/include/CVS/Entries create mode 100644 mk4/lib/aura/include/CVS/Repository create mode 100644 mk4/lib/aura/include/CVS/Root create mode 100644 mk4/lib/aura/include/CVS/Tag rename {aura => mk4/lib/aura/include}/basictypes.h (100%) rename {aura => mk4/lib/aura/include}/iterator.h (100%) rename {aura => mk4/lib/aura/include}/list_iterator.h (100%) rename {aura => mk4/lib/aura/include}/memutil.h (100%) create mode 100644 mk4/lib/aura/include/serialization.h create mode 100644 mk4/lib/aura/include/serializationinfo.h create mode 100644 mk4/lib/aura/include/stringdictionary.h create mode 100644 mk4/lib/aura/include/type.h rename {aura => mk4/lib/aura/include}/typelocator.h (100%) create mode 100644 mk4/lib/aura/scripts/CVS/Entries create mode 100644 mk4/lib/aura/scripts/CVS/Repository create mode 100644 mk4/lib/aura/scripts/CVS/Root create mode 100644 mk4/lib/aura/scripts/CVS/Tag create mode 100644 mk4/lib/aura/scripts/create_aura_class.pl create mode 100644 mk4/lib/aura/src/.cvsignore create mode 100644 mk4/lib/aura/src/CVS/Entries create mode 100644 mk4/lib/aura/src/CVS/Repository create mode 100644 mk4/lib/aura/src/CVS/Root create mode 100644 mk4/lib/aura/src/CVS/Tag rename {aura => mk4/lib/aura/src}/basictypes.c (100%) rename {aura => mk4/lib/aura/src}/iterator.c (100%) create mode 100644 mk4/lib/aura/src/list_iterator.c create mode 100644 mk4/lib/aura/src/memutil.c create mode 100644 mk4/lib/aura/src/serialization.c rename {aura => mk4/lib/aura/src}/serializationinfo.c (100%) create mode 100644 mk4/lib/aura/src/stringdictionary.c rename {aura => mk4/lib/aura/src}/typelocator.c (100%) create mode 100644 mk4/lib/causality-client/CVS/Entries create mode 100644 mk4/lib/causality-client/CVS/Repository create mode 100644 mk4/lib/causality-client/CVS/Root create mode 100644 mk4/lib/causality-client/CVS/Tag create mode 100644 mk4/lib/causality-client/Makefile create mode 100644 mk4/lib/causality-client/include/CVS/Entries create mode 100644 mk4/lib/causality-client/include/CVS/Repository create mode 100644 mk4/lib/causality-client/include/CVS/Root create mode 100644 mk4/lib/causality-client/include/CVS/Tag create mode 100644 mk4/lib/causality-client/include/client.h create mode 100644 mk4/lib/causality-client/include/http_request.h create mode 100644 mk4/lib/causality-client/include/http_request_handler.h create mode 100644 mk4/lib/causality-client/include/http_request_list.h create mode 100644 mk4/lib/causality-client/include/http_request_list_entry.h create mode 100644 mk4/lib/causality-client/include/http_request_queue.h create mode 100644 mk4/lib/causality-client/include/http_response.h create mode 100644 mk4/lib/causality-client/src/CVS/Entries create mode 100644 mk4/lib/causality-client/src/CVS/Repository create mode 100644 mk4/lib/causality-client/src/CVS/Root create mode 100644 mk4/lib/causality-client/src/CVS/Tag create mode 100644 mk4/lib/causality-client/src/client.c create mode 100644 mk4/lib/causality-client/src/http_request.c create mode 100644 mk4/lib/causality-client/src/http_request_handler.c create mode 100644 mk4/lib/causality-client/src/http_request_list.c create mode 100644 mk4/lib/causality-client/src/http_request_list_entry.c create mode 100644 mk4/lib/causality-client/src/http_request_queue.c create mode 100644 mk4/lib/causality-client/src/http_response.c create mode 100644 mk4/lib/causality/CVS/Entries create mode 100644 mk4/lib/causality/CVS/Repository create mode 100644 mk4/lib/causality/CVS/Root create mode 100644 mk4/lib/causality/CVS/Tag create mode 100644 mk4/lib/causality/Makefile create mode 100644 mk4/lib/causality/include/CVS/Entries create mode 100644 mk4/lib/causality/include/CVS/Repository create mode 100644 mk4/lib/causality/include/CVS/Root create mode 100644 mk4/lib/causality/include/CVS/Tag create mode 100644 mk4/lib/causality/include/command.h create mode 100644 mk4/lib/causality/include/command_handlers.h create mode 100644 mk4/lib/causality/include/message.h create mode 100644 mk4/lib/causality/include/message_processor.h create mode 100644 mk4/lib/causality/include/processor.h create mode 100644 mk4/lib/causality/include/request_dispatcher.h create mode 100644 mk4/lib/causality/include/request_handler_entry.h create mode 100644 mk4/lib/causality/include/responseholder.h create mode 100644 mk4/lib/causality/include/responseholderlist.h create mode 100644 mk4/lib/causality/include/sysvipc.h create mode 100644 mk4/lib/causality/include/threadpool.h create mode 100644 mk4/lib/causality/src/CVS/Entries create mode 100644 mk4/lib/causality/src/CVS/Repository create mode 100644 mk4/lib/causality/src/CVS/Root create mode 100644 mk4/lib/causality/src/CVS/Tag create mode 100644 mk4/lib/causality/src/command.c create mode 100644 mk4/lib/causality/src/command_handlers.c create mode 100644 mk4/lib/causality/src/message.c create mode 100644 mk4/lib/causality/src/message_processor.c create mode 100644 mk4/lib/causality/src/processor.c create mode 100644 mk4/lib/causality/src/request_dispatcher.c create mode 100644 mk4/lib/causality/src/request_handler_entry.c create mode 100644 mk4/lib/causality/src/responseholder.c create mode 100644 mk4/lib/causality/src/responseholderlist.c create mode 100644 mk4/lib/causality/src/sysvipc.c create mode 100644 mk4/lib/causality/src/threadpool.c create mode 100644 mk4/mobility-client/CVS/Entries create mode 100644 mk4/mobility-client/CVS/Repository create mode 100644 mk4/mobility-client/CVS/Root create mode 100644 mk4/mobility-client/CVS/Tag create mode 100644 mk4/mobility-client/Makefile.in create mode 100644 mk4/mobility-client/modcgi/.cvsignore create mode 100644 mk4/mobility-client/modcgi/CVS/Entries create mode 100644 mk4/mobility-client/modcgi/CVS/Repository create mode 100644 mk4/mobility-client/modcgi/CVS/Root create mode 100644 mk4/mobility-client/modcgi/CVS/Tag create mode 100644 mk4/mobility-client/modcgi/Makefile create mode 100644 mk4/mobility-client/modcgi/include/.cvsignore create mode 100644 mk4/mobility-client/modcgi/include/CVS/Entries create mode 100644 mk4/mobility-client/modcgi/include/CVS/Repository create mode 100644 mk4/mobility-client/modcgi/include/CVS/Root create mode 100644 mk4/mobility-client/modcgi/include/CVS/Tag create mode 100644 mk4/mobility-client/modcgi/include/cgi_request.h create mode 100644 mk4/mobility-client/modcgi/include/fd_reader.h create mode 100644 mk4/mobility-client/modcgi/include/fd_watcher.h create mode 100644 mk4/mobility-client/modcgi/include/fd_watcher_entry.h create mode 100644 mk4/mobility-client/modcgi/include/process_watcher.h create mode 100644 mk4/mobility-client/modcgi/include/process_watcher_entry.h create mode 100644 mk4/mobility-client/modcgi/include/remote_process.h create mode 100644 mk4/mobility-client/modcgi/include/string_collection.h create mode 100644 mk4/mobility-client/modcgi/src/.cvsignore create mode 100644 mk4/mobility-client/modcgi/src/CVS/Entries create mode 100644 mk4/mobility-client/modcgi/src/CVS/Repository create mode 100644 mk4/mobility-client/modcgi/src/CVS/Root create mode 100644 mk4/mobility-client/modcgi/src/CVS/Tag create mode 100644 mk4/mobility-client/modcgi/src/cgi_request.c create mode 100644 mk4/mobility-client/modcgi/src/fd_reader.c create mode 100644 mk4/mobility-client/modcgi/src/fd_watcher.c create mode 100644 mk4/mobility-client/modcgi/src/fd_watcher_entry.c create mode 100644 mk4/mobility-client/modcgi/src/modcgi.c create mode 100644 mk4/mobility-client/modcgi/src/process_watcher.c create mode 100644 mk4/mobility-client/modcgi/src/process_watcher_entry.c create mode 100644 mk4/mobility-client/modcgi/src/remote_process.c create mode 100644 mk4/mobility-client/modcgi/src/string_collection.c create mode 100644 mk4/mobility-client/modmono/.cvsignore create mode 100644 mk4/mobility-client/modmono/CVS/Entries create mode 100644 mk4/mobility-client/modmono/CVS/Repository create mode 100644 mk4/mobility-client/modmono/CVS/Root create mode 100644 mk4/mobility-client/modmono/CVS/Tag create mode 100644 mk4/mobility-client/modmono/Makefile create mode 100644 mk4/mobility-client/modmono/src/.cvsignore create mode 100644 mk4/mobility-client/modmono/src/CThreadPool.cs create mode 100644 mk4/mobility-client/modmono/src/CVS/Entries create mode 100644 mk4/mobility-client/modmono/src/CVS/Repository create mode 100644 mk4/mobility-client/modmono/src/CVS/Root create mode 100644 mk4/mobility-client/modmono/src/CVS/Tag create mode 100644 mk4/mobility-client/modmono/src/CausalityClient.cs create mode 100644 mk4/mobility-client/modmono/src/CausalityRequest.cs create mode 100644 mk4/mobility-client/modmono/src/OxideApplicationHost.cs create mode 100644 mk4/mobility-client/modmono/src/OxideApplicationPool.cs create mode 100644 mk4/mobility-client/modmono/src/OxideMain.cs create mode 100644 mk4/mobility-client/modmono/src/OxideThreadPool.cs create mode 100644 mk4/mobility-client/modmono/src/OxideWorkerRequest.cs create mode 100644 mk4/modbeacon/CVS/Entries create mode 100644 mk4/modbeacon/CVS/Repository create mode 100644 mk4/modbeacon/CVS/Root create mode 100644 mk4/modbeacon/CVS/Tag create mode 100644 mk4/modbeacon/Makefile.in create mode 100644 mk4/modbeacon/beacon.c create mode 100644 mk4/modbeacon/beacon.xml create mode 100644 mk4/modbeacon/kstat.h create mode 100644 mk4/modcommand/CVS/Entries create mode 100644 mk4/modcommand/CVS/Repository create mode 100644 mk4/modcommand/CVS/Root create mode 100644 mk4/modcommand/CVS/Tag create mode 100644 mk4/modcommand/Makefile.in create mode 100644 mk4/modcommand/cmd.c create mode 100644 mk4/modcommand/cmd.h create mode 100644 mk4/modcommand/cmd.xml create mode 100644 mk4/moddb/CVS/Entries create mode 100644 mk4/moddb/CVS/Repository create mode 100644 mk4/moddb/CVS/Root create mode 100644 mk4/moddb/CVS/Tag create mode 100644 mk4/moddb/Makefile.in create mode 100644 mk4/moddb/db.c create mode 100644 mk4/moddb/db.h create mode 100644 mk4/moddb/db.xml create mode 100644 mk4/moddynamo/CMLDRP.c create mode 100644 mk4/moddynamo/CMLDRP.h create mode 100644 mk4/moddynamo/CVS/Entries create mode 100644 mk4/moddynamo/CVS/Repository create mode 100644 mk4/moddynamo/CVS/Root create mode 100644 mk4/moddynamo/CVS/Tag create mode 100644 mk4/moddynamo/DRPClient.c create mode 100644 mk4/moddynamo/DRPClient.h create mode 100644 mk4/moddynamo/DRPServerIO.c create mode 100644 mk4/moddynamo/DRPServerIO.h create mode 100644 mk4/moddynamo/DRPTypes.h create mode 100644 mk4/moddynamo/DynSock.c create mode 100644 mk4/moddynamo/DynSock.h create mode 100644 mk4/moddynamo/Makefile create mode 100644 mk4/moddynamo/cmVersion.h create mode 100644 mk4/moddynamo/hook.c create mode 100644 mk4/moddynamo/io.c create mode 100644 mk4/moddynamo/io.h create mode 100644 mk4/moddynamo/pageroute.c create mode 100644 mk4/moddynamo/pageroute.h create mode 100644 mk4/moddynamo/rwLocks.h create mode 100644 mk4/moddynamo/sockerrs.c create mode 100644 mk4/moddynamo/sockerrs.h create mode 100644 mk4/moddynamo/system.h create mode 100644 mk4/moddynamo/threadabstr.c create mode 100644 mk4/moddynamo/threadabstr.h create mode 100644 mk4/modexample/CVS/Entries create mode 100644 mk4/modexample/CVS/Repository create mode 100644 mk4/modexample/CVS/Root create mode 100644 mk4/modexample/CVS/Tag create mode 100644 mk4/modexample/Makefile create mode 100644 mk4/modexample/auth.c create mode 100644 mk4/modexample/example.c create mode 100644 mk4/modexample/hello.c create mode 100644 mk4/modharmony/CVS/Entries create mode 100644 mk4/modharmony/CVS/Repository create mode 100644 mk4/modharmony/CVS/Root create mode 100644 mk4/modharmony/CVS/Tag create mode 100644 mk4/modharmony/Makefile.in create mode 100644 mk4/modharmony/harmony.c create mode 100644 mk4/modharmony/harmony.h create mode 100644 mk4/modharmony/hproto.h create mode 100644 mk4/modhtaccess/CVS/Entries create mode 100644 mk4/modhtaccess/CVS/Repository create mode 100644 mk4/modhtaccess/CVS/Root create mode 100644 mk4/modhtaccess/CVS/Tag create mode 100644 mk4/modhtaccess/Makefile create mode 100644 mk4/modhtaccess/include/CVS/Entries create mode 100644 mk4/modhtaccess/include/CVS/Repository create mode 100644 mk4/modhtaccess/include/CVS/Root create mode 100644 mk4/modhtaccess/include/CVS/Tag create mode 100644 mk4/modhtaccess/include/htaccess_basic_auth.h create mode 100644 mk4/modhtaccess/include/htaccess_engine.h create mode 100644 mk4/modhtaccess/include/htaccess_parser.h create mode 100644 mk4/modhtaccess/include/iauthentication_scheme.h create mode 100644 mk4/modhtaccess/src/CVS/Entries create mode 100644 mk4/modhtaccess/src/CVS/Repository create mode 100644 mk4/modhtaccess/src/CVS/Root create mode 100644 mk4/modhtaccess/src/CVS/Tag create mode 100644 mk4/modhtaccess/src/htaccess.c create mode 100644 mk4/modhtaccess/src/htaccess_basic_auth.c create mode 100644 mk4/modhtaccess/src/htaccess_engine.c create mode 100644 mk4/modhtaccess/src/htaccess_parser.c create mode 100644 mk4/modhttp/CVS/Entries create mode 100644 mk4/modhttp/CVS/Repository create mode 100644 mk4/modhttp/CVS/Root create mode 100644 mk4/modhttp/CVS/Tag create mode 100644 mk4/modhttp/Makefile.in create mode 100644 mk4/modhttp/http.c create mode 100644 mk4/modhttp/http.h create mode 100644 mk4/modhttp/http.xml create mode 100644 mk4/modimage/CVS/Entries create mode 100644 mk4/modimage/CVS/Repository create mode 100644 mk4/modimage/CVS/Root create mode 100644 mk4/modimage/CVS/Tag create mode 100644 mk4/modimage/Makefile.in create mode 100644 mk4/modimage/cderror.h create mode 100644 mk4/modimage/cdjpeg.h create mode 100644 mk4/modimage/image.c create mode 100644 mk4/modimage/image.xml create mode 100644 mk4/modimage/jchuff.h create mode 100644 mk4/modimage/jconfig.h create mode 100644 mk4/modimage/jdct.h create mode 100644 mk4/modimage/jdhuff.h create mode 100644 mk4/modimage/jerror.h create mode 100644 mk4/modimage/jinclude.h create mode 100644 mk4/modimage/jmemsys.h create mode 100644 mk4/modimage/jmorecfg.h create mode 100644 mk4/modimage/jpeg-6b/.cvsignore create mode 100644 mk4/modimage/jpeg-6b/CVS/Entries create mode 100644 mk4/modimage/jpeg-6b/CVS/Repository create mode 100644 mk4/modimage/jpeg-6b/CVS/Root create mode 100644 mk4/modimage/jpeg-6b/CVS/Tag create mode 100644 mk4/modimage/jpeg-6b/README create mode 100644 mk4/modimage/jpeg-6b/ansi2knr.1 create mode 100644 mk4/modimage/jpeg-6b/ansi2knr.c create mode 100644 mk4/modimage/jpeg-6b/cderror.h create mode 100644 mk4/modimage/jpeg-6b/cdjpeg.c create mode 100644 mk4/modimage/jpeg-6b/cdjpeg.h create mode 100644 mk4/modimage/jpeg-6b/change.log create mode 100644 mk4/modimage/jpeg-6b/cjpeg.1 create mode 100644 mk4/modimage/jpeg-6b/cjpeg.c create mode 100644 mk4/modimage/jpeg-6b/ckconfig.c create mode 100644 mk4/modimage/jpeg-6b/coderules.doc create mode 100644 mk4/modimage/jpeg-6b/config.guess create mode 100644 mk4/modimage/jpeg-6b/config.sub create mode 100644 mk4/modimage/jpeg-6b/configure create mode 100644 mk4/modimage/jpeg-6b/djpeg.1 create mode 100644 mk4/modimage/jpeg-6b/djpeg.c create mode 100644 mk4/modimage/jpeg-6b/example.c create mode 100644 mk4/modimage/jpeg-6b/filelist.doc create mode 100644 mk4/modimage/jpeg-6b/install-sh create mode 100644 mk4/modimage/jpeg-6b/install.doc create mode 100644 mk4/modimage/jpeg-6b/jcapimin.c create mode 100644 mk4/modimage/jpeg-6b/jcapistd.c create mode 100644 mk4/modimage/jpeg-6b/jccoefct.c create mode 100644 mk4/modimage/jpeg-6b/jccolor.c create mode 100644 mk4/modimage/jpeg-6b/jcdctmgr.c create mode 100644 mk4/modimage/jpeg-6b/jchuff.c create mode 100644 mk4/modimage/jpeg-6b/jchuff.h create mode 100644 mk4/modimage/jpeg-6b/jcinit.c create mode 100644 mk4/modimage/jpeg-6b/jcmainct.c create mode 100644 mk4/modimage/jpeg-6b/jcmarker.c create mode 100644 mk4/modimage/jpeg-6b/jcmaster.c create mode 100644 mk4/modimage/jpeg-6b/jcomapi.c create mode 100644 mk4/modimage/jpeg-6b/jconfig.bcc create mode 100644 mk4/modimage/jpeg-6b/jconfig.cfg create mode 100644 mk4/modimage/jpeg-6b/jconfig.dj create mode 100644 mk4/modimage/jpeg-6b/jconfig.doc create mode 100644 mk4/modimage/jpeg-6b/jconfig.mac create mode 100644 mk4/modimage/jpeg-6b/jconfig.manx create mode 100644 mk4/modimage/jpeg-6b/jconfig.mc6 create mode 100644 mk4/modimage/jpeg-6b/jconfig.sas create mode 100644 mk4/modimage/jpeg-6b/jconfig.st create mode 100644 mk4/modimage/jpeg-6b/jconfig.vc create mode 100644 mk4/modimage/jpeg-6b/jconfig.vms create mode 100644 mk4/modimage/jpeg-6b/jconfig.wat create mode 100644 mk4/modimage/jpeg-6b/jcparam.c create mode 100644 mk4/modimage/jpeg-6b/jcphuff.c create mode 100644 mk4/modimage/jpeg-6b/jcprepct.c create mode 100644 mk4/modimage/jpeg-6b/jcsample.c create mode 100644 mk4/modimage/jpeg-6b/jctrans.c create mode 100644 mk4/modimage/jpeg-6b/jdapimin.c create mode 100644 mk4/modimage/jpeg-6b/jdapistd.c create mode 100644 mk4/modimage/jpeg-6b/jdatadst.c create mode 100644 mk4/modimage/jpeg-6b/jdatasrc.c create mode 100644 mk4/modimage/jpeg-6b/jdcoefct.c create mode 100644 mk4/modimage/jpeg-6b/jdcolor.c create mode 100644 mk4/modimage/jpeg-6b/jdct.h create mode 100644 mk4/modimage/jpeg-6b/jddctmgr.c create mode 100644 mk4/modimage/jpeg-6b/jdhuff.c create mode 100644 mk4/modimage/jpeg-6b/jdhuff.h create mode 100644 mk4/modimage/jpeg-6b/jdinput.c create mode 100644 mk4/modimage/jpeg-6b/jdmainct.c create mode 100644 mk4/modimage/jpeg-6b/jdmarker.c create mode 100644 mk4/modimage/jpeg-6b/jdmaster.c create mode 100644 mk4/modimage/jpeg-6b/jdmerge.c create mode 100644 mk4/modimage/jpeg-6b/jdphuff.c create mode 100644 mk4/modimage/jpeg-6b/jdpostct.c create mode 100644 mk4/modimage/jpeg-6b/jdsample.c create mode 100644 mk4/modimage/jpeg-6b/jdtrans.c create mode 100644 mk4/modimage/jpeg-6b/jerror.c create mode 100644 mk4/modimage/jpeg-6b/jerror.h create mode 100644 mk4/modimage/jpeg-6b/jfdctflt.c create mode 100644 mk4/modimage/jpeg-6b/jfdctfst.c create mode 100644 mk4/modimage/jpeg-6b/jfdctint.c create mode 100644 mk4/modimage/jpeg-6b/jidctflt.c create mode 100644 mk4/modimage/jpeg-6b/jidctfst.c create mode 100644 mk4/modimage/jpeg-6b/jidctint.c create mode 100644 mk4/modimage/jpeg-6b/jidctred.c create mode 100644 mk4/modimage/jpeg-6b/jinclude.h create mode 100644 mk4/modimage/jpeg-6b/jmemansi.c create mode 100644 mk4/modimage/jpeg-6b/jmemdos.c create mode 100644 mk4/modimage/jpeg-6b/jmemdosa.asm create mode 100644 mk4/modimage/jpeg-6b/jmemmac.c create mode 100644 mk4/modimage/jpeg-6b/jmemmgr.c create mode 100644 mk4/modimage/jpeg-6b/jmemname.c create mode 100644 mk4/modimage/jpeg-6b/jmemnobs.c create mode 100644 mk4/modimage/jpeg-6b/jmemsys.h create mode 100644 mk4/modimage/jpeg-6b/jmorecfg.h create mode 100644 mk4/modimage/jpeg-6b/jpegint.h create mode 100644 mk4/modimage/jpeg-6b/jpeglib.h create mode 100644 mk4/modimage/jpeg-6b/jpegtran.1 create mode 100644 mk4/modimage/jpeg-6b/jpegtran.c create mode 100644 mk4/modimage/jpeg-6b/jquant1.c create mode 100644 mk4/modimage/jpeg-6b/jquant2.c create mode 100644 mk4/modimage/jpeg-6b/jutils.c create mode 100644 mk4/modimage/jpeg-6b/jversion.h create mode 100644 mk4/modimage/jpeg-6b/libjpeg.doc create mode 100644 mk4/modimage/jpeg-6b/ltconfig create mode 100644 mk4/modimage/jpeg-6b/ltmain.sh create mode 100644 mk4/modimage/jpeg-6b/makcjpeg.st create mode 100644 mk4/modimage/jpeg-6b/makdjpeg.st create mode 100644 mk4/modimage/jpeg-6b/makeapps.ds create mode 100644 mk4/modimage/jpeg-6b/makefile.ansi create mode 100644 mk4/modimage/jpeg-6b/makefile.bcc create mode 100644 mk4/modimage/jpeg-6b/makefile.cfg create mode 100644 mk4/modimage/jpeg-6b/makefile.dj create mode 100644 mk4/modimage/jpeg-6b/makefile.manx create mode 100644 mk4/modimage/jpeg-6b/makefile.mc6 create mode 100644 mk4/modimage/jpeg-6b/makefile.mms create mode 100644 mk4/modimage/jpeg-6b/makefile.sas create mode 100644 mk4/modimage/jpeg-6b/makefile.unix create mode 100644 mk4/modimage/jpeg-6b/makefile.vc create mode 100644 mk4/modimage/jpeg-6b/makefile.vms create mode 100644 mk4/modimage/jpeg-6b/makefile.wat create mode 100644 mk4/modimage/jpeg-6b/makelib.ds create mode 100644 mk4/modimage/jpeg-6b/makeproj.mac create mode 100644 mk4/modimage/jpeg-6b/makljpeg.st create mode 100644 mk4/modimage/jpeg-6b/maktjpeg.st create mode 100644 mk4/modimage/jpeg-6b/makvms.opt create mode 100644 mk4/modimage/jpeg-6b/rdbmp.c create mode 100644 mk4/modimage/jpeg-6b/rdcolmap.c create mode 100644 mk4/modimage/jpeg-6b/rdgif.c create mode 100644 mk4/modimage/jpeg-6b/rdjpgcom.1 create mode 100644 mk4/modimage/jpeg-6b/rdjpgcom.c create mode 100644 mk4/modimage/jpeg-6b/rdppm.c create mode 100644 mk4/modimage/jpeg-6b/rdrle.c create mode 100644 mk4/modimage/jpeg-6b/rdswitch.c create mode 100644 mk4/modimage/jpeg-6b/rdtarga.c create mode 100644 mk4/modimage/jpeg-6b/structure.doc create mode 100644 mk4/modimage/jpeg-6b/transupp.c create mode 100644 mk4/modimage/jpeg-6b/transupp.h create mode 100644 mk4/modimage/jpeg-6b/usage.doc create mode 100644 mk4/modimage/jpeg-6b/wizard.doc create mode 100644 mk4/modimage/jpeg-6b/wrbmp.c create mode 100644 mk4/modimage/jpeg-6b/wrgif.c create mode 100644 mk4/modimage/jpeg-6b/wrjpgcom.1 create mode 100644 mk4/modimage/jpeg-6b/wrjpgcom.c create mode 100644 mk4/modimage/jpeg-6b/wrppm.c create mode 100644 mk4/modimage/jpeg-6b/wrrle.c create mode 100644 mk4/modimage/jpeg-6b/wrtarga.c create mode 100644 mk4/modimage/jpegint.h create mode 100644 mk4/modimage/jpeglib.h create mode 100644 mk4/modimage/jversion.h create mode 100644 mk4/modimage/transupp.h create mode 100644 mk4/modjava/CVS/Entries create mode 100644 mk4/modjava/CVS/Repository create mode 100644 mk4/modjava/CVS/Root create mode 100644 mk4/modjava/CVS/Tag create mode 100644 mk4/modjava/Makefile.in create mode 100644 mk4/modjava/Prog.java create mode 100644 mk4/modjava/com/CVS/Entries create mode 100644 mk4/modjava/com/CVS/Repository create mode 100644 mk4/modjava/com/CVS/Root create mode 100644 mk4/modjava/com/CVS/Tag create mode 100644 mk4/modjava/com/ashpool/CVS/Entries create mode 100644 mk4/modjava/com/ashpool/CVS/Repository create mode 100644 mk4/modjava/com/ashpool/CVS/Root create mode 100644 mk4/modjava/com/ashpool/CVS/Tag create mode 100644 mk4/modjava/com/ashpool/continuity/CVS/Entries create mode 100644 mk4/modjava/com/ashpool/continuity/CVS/Repository create mode 100644 mk4/modjava/com/ashpool/continuity/CVS/Root create mode 100644 mk4/modjava/com/ashpool/continuity/CVS/Tag create mode 100644 mk4/modjava/com/ashpool/continuity/CatalinaConnector.java create mode 100644 mk4/modjava/com/ashpool/continuity/ContHttpRequest.java create mode 100644 mk4/modjava/com/ashpool/continuity/ContRequest.java create mode 100644 mk4/modjava/entrance.c create mode 100644 mk4/modjava/modjava.c create mode 100644 mk4/modjava/module.cfg create mode 100644 mk4/modm3/.rev create mode 100644 mk4/modm3/CVS/Entries create mode 100644 mk4/modm3/CVS/Repository create mode 100644 mk4/modm3/CVS/Root create mode 100644 mk4/modm3/CVS/Tag create mode 100644 mk4/modm3/Makefile.in create mode 100644 mk4/modm3/include/CVS/Entries create mode 100644 mk4/modm3/include/CVS/Repository create mode 100644 mk4/modm3/include/CVS/Root create mode 100644 mk4/modm3/include/CVS/Tag rename {modm3 => mk4/modm3/include}/_build.h (100%) rename {modm3 => mk4/modm3/include}/file_catalog.h (100%) rename {modm3 => mk4/modm3/include}/file_entry.h (100%) rename {modm3 => mk4/modm3/include}/file_reader.h (100%) rename {modm3 => mk4/modm3/include}/idata_reader.h (100%) create mode 100644 mk4/modm3/include/iplaylist.h rename {modm3 => mk4/modm3/include}/ixtime.h (100%) create mode 100644 mk4/modm3/include/m3.h create mode 100644 mk4/modm3/include/m3_client.h create mode 100644 mk4/modm3/include/m3_server.h rename {modm3 => mk4/modm3/include}/m3_server_factory.h (100%) rename {modm3 => mk4/modm3/include}/m3_tcl.h (100%) rename {modm3 => mk4/modm3/include}/mp3_frame.h (100%) create mode 100644 mk4/modm3/include/mp3_reader.h create mode 100644 mk4/modm3/include/music_packet.h rename {modm3 => mk4/modm3/include}/order_playlist_engine.h (100%) create mode 100644 mk4/modm3/include/playlist.h rename {modm3 => mk4/modm3/include}/playlist_engine_factory.h (100%) create mode 100644 mk4/modm3/include/playlist_manager.h rename {modm3 => mk4/modm3/include}/queue_playlist_engine.h (100%) rename {modm3 => mk4/modm3/include}/randomlist_playlist_engine.h (100%) rename {modm3 => mk4/modm3/include}/shoutcast_metadata_writer.h (100%) rename {modm3 => mk4/modm3/include}/support.h (100%) create mode 100644 mk4/modm3/src/.cvsignore create mode 100644 mk4/modm3/src/CVS/Entries create mode 100644 mk4/modm3/src/CVS/Repository create mode 100644 mk4/modm3/src/CVS/Root create mode 100644 mk4/modm3/src/CVS/Tag create mode 100644 mk4/modm3/src/file_catalog.c create mode 100644 mk4/modm3/src/file_entry.c create mode 100644 mk4/modm3/src/file_reader.c rename {modm3 => mk4/modm3/src}/ixtime.c (100%) create mode 100644 mk4/modm3/src/m3.c create mode 100644 mk4/modm3/src/m3_client.c create mode 100644 mk4/modm3/src/m3_server.c create mode 100644 mk4/modm3/src/m3_server_factory.c create mode 100644 mk4/modm3/src/m3_tcl.c rename {modm3 => mk4/modm3/src}/mp3_frame.c (100%) create mode 100644 mk4/modm3/src/mp3_reader.c create mode 100644 mk4/modm3/src/music_packet.c create mode 100644 mk4/modm3/src/order_playlist_engine.c create mode 100644 mk4/modm3/src/playlist.c create mode 100644 mk4/modm3/src/playlist_engine_factory.c create mode 100644 mk4/modm3/src/playlist_manager.c create mode 100644 mk4/modm3/src/queue_playlist_engine.c rename {modm3 => mk4/modm3/src}/randomlist_playlist_engine.c (100%) create mode 100644 mk4/modm3/src/shoutcast_metadata_writer.c rename {modm3 => mk4/modm3/src}/support.c (100%) create mode 100644 mk4/modmobility/CVS/Entries create mode 100644 mk4/modmobility/CVS/Repository create mode 100644 mk4/modmobility/CVS/Root create mode 100644 mk4/modmobility/CVS/Tag create mode 100644 mk4/modmobility/Makefile create mode 100644 mk4/modmobility/include/CVS/Entries create mode 100644 mk4/modmobility/include/CVS/Repository create mode 100644 mk4/modmobility/include/CVS/Root create mode 100644 mk4/modmobility/include/CVS/Tag create mode 100644 mk4/modmobility/include/http_message_handler.h create mode 100644 mk4/modmobility/include/http_request.h create mode 100644 mk4/modmobility/include/http_request_list.h create mode 100644 mk4/modmobility/include/mobility.h create mode 100644 mk4/modmobility/include/mobilitytable.h create mode 100644 mk4/modmobility/src/CVS/Entries create mode 100644 mk4/modmobility/src/CVS/Repository create mode 100644 mk4/modmobility/src/CVS/Root create mode 100644 mk4/modmobility/src/CVS/Tag create mode 100644 mk4/modmobility/src/handler.c create mode 100644 mk4/modmobility/src/http_message_handler.c create mode 100644 mk4/modmobility/src/http_request.c create mode 100644 mk4/modmobility/src/http_request_list.c create mode 100644 mk4/modmobility/src/mobility.c create mode 100644 mk4/modmobility/src/mobilitytable.c create mode 100644 mk4/modoracle/CVS/Entries create mode 100644 mk4/modoracle/CVS/Repository create mode 100644 mk4/modoracle/CVS/Root create mode 100644 mk4/modoracle/CVS/Tag create mode 100644 mk4/modoracle/Makefile.blackwell create mode 100644 mk4/modoracle/Makefile.chiba create mode 100644 mk4/modoracle/Makefile.gorecki create mode 100644 mk4/modoracle/ora.c create mode 100644 mk4/modoracle/oracle.xml create mode 100644 mk4/modradius/CVS/Entries create mode 100644 mk4/modradius/CVS/Repository create mode 100644 mk4/modradius/CVS/Root create mode 100644 mk4/modradius/CVS/Tag create mode 100644 mk4/modradius/Makefile.in create mode 100644 mk4/modradius/radius.c create mode 100644 mk4/modradius/radius.h create mode 100644 mk4/modradius/radius.xml create mode 100644 mk4/modsite/CVS/Entries create mode 100644 mk4/modsite/CVS/Repository create mode 100644 mk4/modsite/CVS/Root create mode 100644 mk4/modsite/CVS/Tag create mode 100644 mk4/modsite/Makefile.in create mode 100644 mk4/modsite/log.c create mode 100644 mk4/modsite/site.c create mode 100644 mk4/modsite/site.h create mode 100644 mk4/modsite/site.xml rename {modsite => mk4/modsite}/siteerror.h (100%) create mode 100644 mk4/modssl/CVS/Entries create mode 100644 mk4/modssl/CVS/Repository create mode 100644 mk4/modssl/CVS/Root create mode 100644 mk4/modssl/CVS/Tag create mode 100644 mk4/modssl/LICENSE create mode 100644 mk4/modssl/Makefile create mode 100644 mk4/modssl/Makefile.osx create mode 100644 mk4/modssl/client.pem create mode 100644 mk4/modssl/dh1024.pem create mode 100644 mk4/modssl/root.pem create mode 100644 mk4/modssl/server.pem create mode 100644 mk4/modssl/ssl.c create mode 100644 mk4/modssl/ssl.h create mode 100644 mk4/modtcl/CVS/Entries create mode 100644 mk4/modtcl/CVS/Repository create mode 100644 mk4/modtcl/CVS/Root create mode 100644 mk4/modtcl/CVS/Tag create mode 100644 mk4/modtcl/Makefile.in create mode 100644 mk4/modtcl/src/CVS/Entries create mode 100644 mk4/modtcl/src/CVS/Repository create mode 100644 mk4/modtcl/src/CVS/Root create mode 100644 mk4/modtcl/src/CVS/Tag create mode 100644 mk4/modtcl/src/Makefile create mode 100644 mk4/modtcl/src/cmds.c create mode 100644 mk4/modtcl/src/modtcl.c create mode 100644 mk4/modtcl/src/modtcl.h rename {modtcl => mk4/modtcl/src}/modtcl.xml (100%) create mode 100644 mk4/modtcl/tcl8.3.4/CVS/Entries create mode 100644 mk4/modtcl/tcl8.3.4/CVS/Repository create mode 100644 mk4/modtcl/tcl8.3.4/CVS/Root create mode 100644 mk4/modtcl/tcl8.3.4/CVS/Tag create mode 100644 mk4/modtcl/tcl8.3.4/ChangeLog create mode 100644 mk4/modtcl/tcl8.3.4/README create mode 100644 mk4/modtcl/tcl8.3.4/changes create mode 100644 mk4/modtcl/tcl8.3.4/compat/CVS/Entries create mode 100644 mk4/modtcl/tcl8.3.4/compat/CVS/Repository create mode 100644 mk4/modtcl/tcl8.3.4/compat/CVS/Root create mode 100644 mk4/modtcl/tcl8.3.4/compat/CVS/Tag create mode 100644 mk4/modtcl/tcl8.3.4/compat/README create mode 100644 mk4/modtcl/tcl8.3.4/compat/dirent.h create mode 100644 mk4/modtcl/tcl8.3.4/compat/dirent2.h create mode 100644 mk4/modtcl/tcl8.3.4/compat/dlfcn.h create mode 100644 mk4/modtcl/tcl8.3.4/compat/fixstrtod.c create mode 100644 mk4/modtcl/tcl8.3.4/compat/float.h create mode 100644 mk4/modtcl/tcl8.3.4/compat/gettod.c create mode 100644 mk4/modtcl/tcl8.3.4/compat/license.terms create mode 100644 mk4/modtcl/tcl8.3.4/compat/limits.h create mode 100644 mk4/modtcl/tcl8.3.4/compat/memcmp.c create mode 100644 mk4/modtcl/tcl8.3.4/compat/opendir.c create mode 100644 mk4/modtcl/tcl8.3.4/compat/stdlib.h create mode 100644 mk4/modtcl/tcl8.3.4/compat/strftime.c create mode 100644 mk4/modtcl/tcl8.3.4/compat/string.h create mode 100644 mk4/modtcl/tcl8.3.4/compat/strncasecmp.c create mode 100644 mk4/modtcl/tcl8.3.4/compat/strstr.c create mode 100644 mk4/modtcl/tcl8.3.4/compat/strtod.c create mode 100644 mk4/modtcl/tcl8.3.4/compat/strtol.c create mode 100644 mk4/modtcl/tcl8.3.4/compat/strtoul.c create mode 100644 mk4/modtcl/tcl8.3.4/compat/tclErrno.h create mode 100644 mk4/modtcl/tcl8.3.4/compat/tmpnam.c create mode 100644 mk4/modtcl/tcl8.3.4/compat/unistd.h create mode 100644 mk4/modtcl/tcl8.3.4/compat/waitpid.c create mode 100644 mk4/modtcl/tcl8.3.4/doc/Access.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/AddErrInfo.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/Alloc.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/AllowExc.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/AppInit.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/AssocData.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/Async.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/BackgdErr.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/Backslash.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/BoolObj.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/ByteArrObj.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/CVS/Entries create mode 100644 mk4/modtcl/tcl8.3.4/doc/CVS/Repository create mode 100644 mk4/modtcl/tcl8.3.4/doc/CVS/Root create mode 100644 mk4/modtcl/tcl8.3.4/doc/CVS/Tag create mode 100644 mk4/modtcl/tcl8.3.4/doc/CallDel.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/ChnlStack.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/CmdCmplt.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/Concat.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/CrtChannel.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/CrtChnlHdlr.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/CrtCloseHdlr.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/CrtCommand.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/CrtFileHdlr.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/CrtInterp.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/CrtMathFnc.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/CrtObjCmd.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/CrtSlave.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/CrtTimerHdlr.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/CrtTrace.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/DString.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/DetachPids.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/DoOneEvent.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/DoWhenIdle.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/DoubleObj.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/DumpActiveMemory.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/Encoding.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/Eval.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/Exit.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/ExprLong.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/ExprLongObj.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/FindExec.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/GetCwd.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/GetHostName.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/GetIndex.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/GetInt.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/GetOpnFl.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/GetStdChan.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/GetVersion.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/Hash.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/Init.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/InitStubs.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/IntObj.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/Interp.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/LinkVar.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/ListObj.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/Notifier.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/Object.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/ObjectType.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/OpenFileChnl.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/OpenTcp.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/ParseCmd.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/PkgRequire.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/Preserve.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/PrintDbl.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/RecEvalObj.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/RecordEval.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/RegExp.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/SaveResult.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/SetErrno.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/SetRecLmt.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/SetResult.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/SetVar.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/Sleep.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/SourceRCFile.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/SplitList.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/SplitPath.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/StaticPkg.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/StrMatch.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/StringObj.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/TCL_MEM_DEBUG.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/Tcl.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/Tcl_Main.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/Thread.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/ToUpper.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/TraceVar.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/Translate.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/UpVar.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/Utf.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/WrongNumArgs.3 create mode 100644 mk4/modtcl/tcl8.3.4/doc/after.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/append.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/array.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/bgerror.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/binary.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/break.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/case.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/catch.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/cd.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/clock.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/close.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/concat.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/continue.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/dde.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/encoding.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/eof.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/error.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/eval.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/exec.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/exit.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/expr.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/fblocked.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/fconfigure.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/fcopy.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/file.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/fileevent.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/filename.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/flush.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/for.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/foreach.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/format.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/gets.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/glob.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/global.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/history.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/http.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/if.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/incr.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/info.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/interp.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/join.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/lappend.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/library.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/license.terms create mode 100644 mk4/modtcl/tcl8.3.4/doc/lindex.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/linsert.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/list.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/llength.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/load.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/lrange.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/lreplace.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/lsearch.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/lsort.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/man.macros create mode 100644 mk4/modtcl/tcl8.3.4/doc/memory.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/msgcat.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/namespace.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/open.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/package.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/packagens.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/pid.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/pkgMkIndex.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/proc.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/puts.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/pwd.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/re_syntax.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/read.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/regexp.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/registry.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/regsub.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/rename.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/resource.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/return.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/safe.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/scan.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/seek.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/set.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/socket.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/source.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/split.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/string.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/subst.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/switch.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/tclsh.1 create mode 100644 mk4/modtcl/tcl8.3.4/doc/tcltest.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/tclvars.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/tell.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/time.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/trace.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/unknown.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/unset.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/update.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/uplevel.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/upvar.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/variable.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/vwait.n create mode 100644 mk4/modtcl/tcl8.3.4/doc/while.n create mode 100644 mk4/modtcl/tcl8.3.4/generic/CVS/Entries create mode 100644 mk4/modtcl/tcl8.3.4/generic/CVS/Repository create mode 100644 mk4/modtcl/tcl8.3.4/generic/CVS/Root create mode 100644 mk4/modtcl/tcl8.3.4/generic/CVS/Tag create mode 100644 mk4/modtcl/tcl8.3.4/generic/README create mode 100644 mk4/modtcl/tcl8.3.4/generic/regc_color.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/regc_cvec.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/regc_lex.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/regc_locale.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/regc_nfa.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/regcomp.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/regcustom.h create mode 100644 mk4/modtcl/tcl8.3.4/generic/rege_dfa.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/regerror.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/regerrs.h create mode 100644 mk4/modtcl/tcl8.3.4/generic/regex.h create mode 100644 mk4/modtcl/tcl8.3.4/generic/regexec.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/regfree.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/regfronts.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/regguts.h create mode 100644 mk4/modtcl/tcl8.3.4/generic/tcl.decls create mode 100644 mk4/modtcl/tcl8.3.4/generic/tcl.h create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclAlloc.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclAsync.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclBasic.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclBinary.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclCkalloc.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclClock.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclCmdAH.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclCmdIL.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclCmdMZ.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclCompCmds.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclCompExpr.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclCompile.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclCompile.h create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclDate.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclDecls.h create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclEncoding.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclEnv.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclEvent.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclExecute.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclFCmd.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclFileName.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclGet.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclGetDate.y create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclHash.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclHistory.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclIO.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclIO.h create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclIOCmd.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclIOGT.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclIOSock.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclIOUtil.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclIndexObj.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclInitScript.h create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclInt.decls create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclInt.h create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclIntDecls.h create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclIntPlatDecls.h create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclInterp.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclLink.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclListObj.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclLiteral.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclLoad.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclLoadNone.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclMain.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclMath.h create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclNamesp.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclNotify.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclObj.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclPanic.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclParse.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclParseExpr.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclPipe.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclPkg.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclPlatDecls.h create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclPort.h create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclPosixStr.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclPreserve.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclProc.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclRegexp.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclRegexp.h create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclResolve.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclResult.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclScan.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclStringObj.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclStubInit.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclStubLib.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclTest.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclTestObj.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclTestProcBodyObj.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclThread.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclThreadTest.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclTimer.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclUniData.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclUtf.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclUtil.c create mode 100644 mk4/modtcl/tcl8.3.4/generic/tclVar.c create mode 100644 mk4/modtcl/tcl8.3.4/library/CVS/Entries create mode 100644 mk4/modtcl/tcl8.3.4/library/CVS/Repository create mode 100644 mk4/modtcl/tcl8.3.4/library/CVS/Root create mode 100644 mk4/modtcl/tcl8.3.4/library/CVS/Tag create mode 100644 mk4/modtcl/tcl8.3.4/library/auto.tcl create mode 100644 mk4/modtcl/tcl8.3.4/library/dde1.1/CVS/Entries create mode 100644 mk4/modtcl/tcl8.3.4/library/dde1.1/CVS/Repository create mode 100644 mk4/modtcl/tcl8.3.4/library/dde1.1/CVS/Root create mode 100644 mk4/modtcl/tcl8.3.4/library/dde1.1/CVS/Tag create mode 100644 mk4/modtcl/tcl8.3.4/library/dde1.1/pkgIndex.tcl create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/CVS/Entries create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/CVS/Repository create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/CVS/Root create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/CVS/Tag create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/ascii.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/big5.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/cp1250.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/cp1251.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/cp1252.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/cp1253.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/cp1254.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/cp1255.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/cp1256.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/cp1257.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/cp1258.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/cp437.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/cp737.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/cp775.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/cp850.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/cp852.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/cp855.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/cp857.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/cp860.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/cp861.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/cp862.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/cp863.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/cp864.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/cp865.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/cp866.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/cp869.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/cp874.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/cp932.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/cp936.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/cp949.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/cp950.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/dingbats.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/ebcdic.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/euc-cn.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/euc-jp.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/euc-kr.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/gb12345.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/gb1988.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/gb2312.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/iso2022-jp.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/iso2022-kr.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/iso2022.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/iso8859-1.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/iso8859-10.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/iso8859-13.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/iso8859-14.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/iso8859-15.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/iso8859-16.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/iso8859-2.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/iso8859-3.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/iso8859-4.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/iso8859-5.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/iso8859-6.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/iso8859-7.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/iso8859-8.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/iso8859-9.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/jis0201.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/jis0208.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/jis0212.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/koi8-r.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/koi8-u.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/ksc5601.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/macCentEuro.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/macCroatian.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/macCyrillic.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/macDingbats.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/macGreek.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/macIceland.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/macJapan.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/macRoman.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/macRomania.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/macThai.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/macTurkish.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/macUkraine.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/shiftjis.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/symbol.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/encoding/tis-620.enc create mode 100644 mk4/modtcl/tcl8.3.4/library/history.tcl create mode 100644 mk4/modtcl/tcl8.3.4/library/http/CVS/Entries create mode 100644 mk4/modtcl/tcl8.3.4/library/http/CVS/Repository create mode 100644 mk4/modtcl/tcl8.3.4/library/http/CVS/Root create mode 100644 mk4/modtcl/tcl8.3.4/library/http/CVS/Tag create mode 100644 mk4/modtcl/tcl8.3.4/library/http/http.tcl create mode 100644 mk4/modtcl/tcl8.3.4/library/http/pkgIndex.tcl create mode 100644 mk4/modtcl/tcl8.3.4/library/http1.0/CVS/Entries create mode 100644 mk4/modtcl/tcl8.3.4/library/http1.0/CVS/Repository create mode 100644 mk4/modtcl/tcl8.3.4/library/http1.0/CVS/Root create mode 100644 mk4/modtcl/tcl8.3.4/library/http1.0/CVS/Tag create mode 100644 mk4/modtcl/tcl8.3.4/library/http1.0/http.tcl create mode 100644 mk4/modtcl/tcl8.3.4/library/http1.0/pkgIndex.tcl create mode 100644 mk4/modtcl/tcl8.3.4/library/init.tcl create mode 100644 mk4/modtcl/tcl8.3.4/library/ldAout.tcl create mode 100644 mk4/modtcl/tcl8.3.4/library/license.terms create mode 100644 mk4/modtcl/tcl8.3.4/library/msgcat/CVS/Entries create mode 100644 mk4/modtcl/tcl8.3.4/library/msgcat/CVS/Repository create mode 100644 mk4/modtcl/tcl8.3.4/library/msgcat/CVS/Root create mode 100644 mk4/modtcl/tcl8.3.4/library/msgcat/CVS/Tag create mode 100644 mk4/modtcl/tcl8.3.4/library/msgcat/msgcat.tcl create mode 100644 mk4/modtcl/tcl8.3.4/library/msgcat/pkgIndex.tcl create mode 100644 mk4/modtcl/tcl8.3.4/library/opt/CVS/Entries create mode 100644 mk4/modtcl/tcl8.3.4/library/opt/CVS/Repository create mode 100644 mk4/modtcl/tcl8.3.4/library/opt/CVS/Root create mode 100644 mk4/modtcl/tcl8.3.4/library/opt/CVS/Tag create mode 100644 mk4/modtcl/tcl8.3.4/library/opt/optparse.tcl create mode 100644 mk4/modtcl/tcl8.3.4/library/opt/pkgIndex.tcl create mode 100644 mk4/modtcl/tcl8.3.4/library/package.tcl create mode 100644 mk4/modtcl/tcl8.3.4/library/parray.tcl create mode 100644 mk4/modtcl/tcl8.3.4/library/reg1.0/CVS/Entries create mode 100644 mk4/modtcl/tcl8.3.4/library/reg1.0/CVS/Repository create mode 100644 mk4/modtcl/tcl8.3.4/library/reg1.0/CVS/Root create mode 100644 mk4/modtcl/tcl8.3.4/library/reg1.0/CVS/Tag create mode 100644 mk4/modtcl/tcl8.3.4/library/reg1.0/pkgIndex.tcl create mode 100644 mk4/modtcl/tcl8.3.4/library/safe.tcl create mode 100644 mk4/modtcl/tcl8.3.4/library/tclIndex create mode 100644 mk4/modtcl/tcl8.3.4/library/tcltest1.0/CVS/Entries create mode 100644 mk4/modtcl/tcl8.3.4/library/tcltest1.0/CVS/Repository create mode 100644 mk4/modtcl/tcl8.3.4/library/tcltest1.0/CVS/Root create mode 100644 mk4/modtcl/tcl8.3.4/library/tcltest1.0/CVS/Tag create mode 100644 mk4/modtcl/tcl8.3.4/library/tcltest1.0/pkgIndex.tcl create mode 100644 mk4/modtcl/tcl8.3.4/library/tcltest1.0/tcltest.tcl create mode 100644 mk4/modtcl/tcl8.3.4/library/word.tcl create mode 100644 mk4/modtcl/tcl8.3.4/license.terms create mode 100644 mk4/modtcl/tcl8.3.4/mac/AppleScript.html create mode 100644 mk4/modtcl/tcl8.3.4/mac/Background.doc create mode 100644 mk4/modtcl/tcl8.3.4/mac/CVS/Entries create mode 100644 mk4/modtcl/tcl8.3.4/mac/CVS/Repository create mode 100644 mk4/modtcl/tcl8.3.4/mac/CVS/Root create mode 100644 mk4/modtcl/tcl8.3.4/mac/CVS/Tag create mode 100644 mk4/modtcl/tcl8.3.4/mac/MW_TclAppleScriptHeader.h create mode 100644 mk4/modtcl/tcl8.3.4/mac/MW_TclAppleScriptHeader.pch create mode 100644 mk4/modtcl/tcl8.3.4/mac/MW_TclBuildLibHeader.h create mode 100644 mk4/modtcl/tcl8.3.4/mac/MW_TclBuildLibHeader.pch create mode 100644 mk4/modtcl/tcl8.3.4/mac/MW_TclHeader.h create mode 100644 mk4/modtcl/tcl8.3.4/mac/MW_TclHeader.pch create mode 100644 mk4/modtcl/tcl8.3.4/mac/MW_TclHeaderCommon.h create mode 100644 mk4/modtcl/tcl8.3.4/mac/MW_TclStaticHeader.h create mode 100644 mk4/modtcl/tcl8.3.4/mac/MW_TclStaticHeader.pch create mode 100644 mk4/modtcl/tcl8.3.4/mac/MW_TclTestHeader.h create mode 100644 mk4/modtcl/tcl8.3.4/mac/MW_TclTestHeader.pch create mode 100644 mk4/modtcl/tcl8.3.4/mac/README create mode 100644 mk4/modtcl/tcl8.3.4/mac/bugs.doc create mode 100644 mk4/modtcl/tcl8.3.4/mac/libmoto.doc create mode 100644 mk4/modtcl/tcl8.3.4/mac/license.terms create mode 100644 mk4/modtcl/tcl8.3.4/mac/morefiles.doc create mode 100644 mk4/modtcl/tcl8.3.4/mac/porting.notes create mode 100644 mk4/modtcl/tcl8.3.4/mac/tclMac.h create mode 100644 mk4/modtcl/tcl8.3.4/mac/tclMacAETE.r create mode 100644 mk4/modtcl/tcl8.3.4/mac/tclMacAlloc.c create mode 100644 mk4/modtcl/tcl8.3.4/mac/tclMacAppInit.c create mode 100644 mk4/modtcl/tcl8.3.4/mac/tclMacApplication.r create mode 100644 mk4/modtcl/tcl8.3.4/mac/tclMacBOAAppInit.c create mode 100644 mk4/modtcl/tcl8.3.4/mac/tclMacBOAMain.c create mode 100644 mk4/modtcl/tcl8.3.4/mac/tclMacChan.c create mode 100644 mk4/modtcl/tcl8.3.4/mac/tclMacCommonPch.h create mode 100644 mk4/modtcl/tcl8.3.4/mac/tclMacDNR.c create mode 100644 mk4/modtcl/tcl8.3.4/mac/tclMacEnv.c create mode 100644 mk4/modtcl/tcl8.3.4/mac/tclMacExit.c create mode 100644 mk4/modtcl/tcl8.3.4/mac/tclMacFCmd.c create mode 100644 mk4/modtcl/tcl8.3.4/mac/tclMacFile.c create mode 100644 mk4/modtcl/tcl8.3.4/mac/tclMacInit.c create mode 100644 mk4/modtcl/tcl8.3.4/mac/tclMacInt.h create mode 100644 mk4/modtcl/tcl8.3.4/mac/tclMacInterupt.c create mode 100644 mk4/modtcl/tcl8.3.4/mac/tclMacLibrary.c create mode 100644 mk4/modtcl/tcl8.3.4/mac/tclMacLibrary.r create mode 100644 mk4/modtcl/tcl8.3.4/mac/tclMacLoad.c create mode 100644 mk4/modtcl/tcl8.3.4/mac/tclMacMath.h create mode 100644 mk4/modtcl/tcl8.3.4/mac/tclMacNotify.c create mode 100644 mk4/modtcl/tcl8.3.4/mac/tclMacOSA.c create mode 100644 mk4/modtcl/tcl8.3.4/mac/tclMacOSA.r create mode 100644 mk4/modtcl/tcl8.3.4/mac/tclMacPanic.c create mode 100644 mk4/modtcl/tcl8.3.4/mac/tclMacPort.h create mode 100644 mk4/modtcl/tcl8.3.4/mac/tclMacProjects.sea.hqx create mode 100644 mk4/modtcl/tcl8.3.4/mac/tclMacResource.c create mode 100644 mk4/modtcl/tcl8.3.4/mac/tclMacResource.r create mode 100644 mk4/modtcl/tcl8.3.4/mac/tclMacSock.c create mode 100644 mk4/modtcl/tcl8.3.4/mac/tclMacTclCode.r create mode 100644 mk4/modtcl/tcl8.3.4/mac/tclMacTest.c create mode 100644 mk4/modtcl/tcl8.3.4/mac/tclMacThrd.c create mode 100644 mk4/modtcl/tcl8.3.4/mac/tclMacThrd.h create mode 100644 mk4/modtcl/tcl8.3.4/mac/tclMacTime.c create mode 100644 mk4/modtcl/tcl8.3.4/mac/tclMacUnix.c create mode 100644 mk4/modtcl/tcl8.3.4/mac/tclMacUtil.c create mode 100644 mk4/modtcl/tcl8.3.4/tests/CVS/Entries create mode 100644 mk4/modtcl/tcl8.3.4/tests/CVS/Repository create mode 100644 mk4/modtcl/tcl8.3.4/tests/CVS/Root create mode 100644 mk4/modtcl/tcl8.3.4/tests/CVS/Tag create mode 100644 mk4/modtcl/tcl8.3.4/tests/README create mode 100644 mk4/modtcl/tcl8.3.4/tests/all.tcl create mode 100644 mk4/modtcl/tcl8.3.4/tests/append.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/assocd.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/async.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/autoMkindex.tcl create mode 100644 mk4/modtcl/tcl8.3.4/tests/autoMkindex.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/basic.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/binary.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/case.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/clock.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/cmdAH.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/cmdIL.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/cmdInfo.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/cmdMZ.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/compExpr-old.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/compExpr.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/compile.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/concat.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/dcall.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/dstring.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/encoding.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/env.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/error.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/eval.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/event.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/exec.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/execute.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/expr-old.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/expr.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/fCmd.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/fileName.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/for-old.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/for.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/foreach.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/format.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/get.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/history.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/http.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/httpd create mode 100644 mk4/modtcl/tcl8.3.4/tests/httpold.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/if-old.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/if.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/incr-old.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/incr.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/indexObj.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/info.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/init.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/interp.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/io.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/ioCmd.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/ioUtil.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/iogt.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/join.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/license.terms create mode 100644 mk4/modtcl/tcl8.3.4/tests/lindex.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/link.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/linsert.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/list.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/listObj.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/llength.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/load.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/lrange.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/lreplace.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/lsearch.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/macFCmd.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/misc.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/msgcat.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/namespace-old.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/namespace.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/obj.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/opt.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/osa.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/package.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/parse.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/parseExpr.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/parseOld.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/pid.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/pkg.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/pkg/CVS/Entries create mode 100644 mk4/modtcl/tcl8.3.4/tests/pkg/CVS/Repository create mode 100644 mk4/modtcl/tcl8.3.4/tests/pkg/CVS/Root create mode 100644 mk4/modtcl/tcl8.3.4/tests/pkg/CVS/Tag create mode 100644 mk4/modtcl/tcl8.3.4/tests/pkg/circ1.tcl create mode 100644 mk4/modtcl/tcl8.3.4/tests/pkg/circ2.tcl create mode 100644 mk4/modtcl/tcl8.3.4/tests/pkg/circ3.tcl create mode 100644 mk4/modtcl/tcl8.3.4/tests/pkg/global.tcl create mode 100644 mk4/modtcl/tcl8.3.4/tests/pkg/import.tcl create mode 100644 mk4/modtcl/tcl8.3.4/tests/pkg/license.terms create mode 100644 mk4/modtcl/tcl8.3.4/tests/pkg/magicchar.tcl create mode 100644 mk4/modtcl/tcl8.3.4/tests/pkg/magicchar2.tcl create mode 100644 mk4/modtcl/tcl8.3.4/tests/pkg/pkg1.tcl create mode 100644 mk4/modtcl/tcl8.3.4/tests/pkg/pkg2_a.tcl create mode 100644 mk4/modtcl/tcl8.3.4/tests/pkg/pkg2_b.tcl create mode 100644 mk4/modtcl/tcl8.3.4/tests/pkg/pkg3.tcl create mode 100644 mk4/modtcl/tcl8.3.4/tests/pkg/pkg4.tcl create mode 100644 mk4/modtcl/tcl8.3.4/tests/pkg/pkg5.tcl create mode 100644 mk4/modtcl/tcl8.3.4/tests/pkg/pkga.tcl create mode 100644 mk4/modtcl/tcl8.3.4/tests/pkg/samename.tcl create mode 100644 mk4/modtcl/tcl8.3.4/tests/pkg/simple.tcl create mode 100644 mk4/modtcl/tcl8.3.4/tests/pkg/spacename.tcl create mode 100644 mk4/modtcl/tcl8.3.4/tests/pkg/std.tcl create mode 100644 mk4/modtcl/tcl8.3.4/tests/pkgMkIndex.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/platform.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/proc-old.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/proc.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/pwd.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/reg.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/regexp.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/registry.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/remote.tcl create mode 100644 mk4/modtcl/tcl8.3.4/tests/rename.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/resource.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/result.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/safe.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/scan.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/security.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/set-old.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/set.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/socket.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/source.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/split.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/stack.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/string.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/stringObj.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/subst.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/switch.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/tcltest.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/thread.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/timer.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/trace.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/unixFCmd.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/unixFile.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/unixInit.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/unixNotfy.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/unknown.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/uplevel.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/upvar.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/utf.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/util.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/var.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/while-old.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/while.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/winConsole.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/winDde.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/winFCmd.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/winFile.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/winNotify.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/winPipe.test create mode 100644 mk4/modtcl/tcl8.3.4/tests/winTime.test create mode 100644 mk4/modtcl/tcl8.3.4/tools/CVS/Entries create mode 100644 mk4/modtcl/tcl8.3.4/tools/CVS/Repository create mode 100644 mk4/modtcl/tcl8.3.4/tools/CVS/Root create mode 100644 mk4/modtcl/tcl8.3.4/tools/CVS/Tag create mode 100644 mk4/modtcl/tcl8.3.4/tools/Makefile.in create mode 100644 mk4/modtcl/tcl8.3.4/tools/README create mode 100644 mk4/modtcl/tcl8.3.4/tools/checkLibraryDoc.tcl create mode 100644 mk4/modtcl/tcl8.3.4/tools/configure create mode 100644 mk4/modtcl/tcl8.3.4/tools/configure.in create mode 100644 mk4/modtcl/tcl8.3.4/tools/cvtEOL.tcl create mode 100644 mk4/modtcl/tcl8.3.4/tools/genStubs.tcl create mode 100644 mk4/modtcl/tcl8.3.4/tools/genWinImage.tcl create mode 100644 mk4/modtcl/tcl8.3.4/tools/index.tcl create mode 100644 mk4/modtcl/tcl8.3.4/tools/man2help.tcl create mode 100644 mk4/modtcl/tcl8.3.4/tools/man2help2.tcl create mode 100644 mk4/modtcl/tcl8.3.4/tools/man2html.tcl create mode 100644 mk4/modtcl/tcl8.3.4/tools/man2html1.tcl create mode 100644 mk4/modtcl/tcl8.3.4/tools/man2html2.tcl create mode 100644 mk4/modtcl/tcl8.3.4/tools/man2tcl.c create mode 100644 mk4/modtcl/tcl8.3.4/tools/regexpTestLib.tcl create mode 100644 mk4/modtcl/tcl8.3.4/tools/tcl.hpj.in create mode 100644 mk4/modtcl/tcl8.3.4/tools/tcl.wse.in create mode 100644 mk4/modtcl/tcl8.3.4/tools/tclSplash.bmp create mode 100644 mk4/modtcl/tcl8.3.4/tools/tcltk-man2html.tcl create mode 100644 mk4/modtcl/tcl8.3.4/tools/uniClass.tcl create mode 100644 mk4/modtcl/tcl8.3.4/tools/uniParse.tcl create mode 100644 mk4/modtcl/tcl8.3.4/tools/white.bmp create mode 100644 mk4/modtcl/tcl8.3.4/unix/.cvsignore create mode 100644 mk4/modtcl/tcl8.3.4/unix/CVS/Entries create mode 100644 mk4/modtcl/tcl8.3.4/unix/CVS/Repository create mode 100644 mk4/modtcl/tcl8.3.4/unix/CVS/Root create mode 100644 mk4/modtcl/tcl8.3.4/unix/CVS/Tag create mode 100644 mk4/modtcl/tcl8.3.4/unix/Makefile.in create mode 100644 mk4/modtcl/tcl8.3.4/unix/README create mode 100644 mk4/modtcl/tcl8.3.4/unix/aclocal.m4 create mode 100644 mk4/modtcl/tcl8.3.4/unix/configure create mode 100644 mk4/modtcl/tcl8.3.4/unix/configure.in create mode 100644 mk4/modtcl/tcl8.3.4/unix/dltest/CVS/Entries create mode 100644 mk4/modtcl/tcl8.3.4/unix/dltest/CVS/Repository create mode 100644 mk4/modtcl/tcl8.3.4/unix/dltest/CVS/Root create mode 100644 mk4/modtcl/tcl8.3.4/unix/dltest/CVS/Tag create mode 100644 mk4/modtcl/tcl8.3.4/unix/dltest/Makefile.in create mode 100644 mk4/modtcl/tcl8.3.4/unix/dltest/README create mode 100644 mk4/modtcl/tcl8.3.4/unix/dltest/configure create mode 100644 mk4/modtcl/tcl8.3.4/unix/dltest/configure.in create mode 100644 mk4/modtcl/tcl8.3.4/unix/dltest/pkga.c create mode 100644 mk4/modtcl/tcl8.3.4/unix/dltest/pkgb.c create mode 100644 mk4/modtcl/tcl8.3.4/unix/dltest/pkgc.c create mode 100644 mk4/modtcl/tcl8.3.4/unix/dltest/pkgd.c create mode 100644 mk4/modtcl/tcl8.3.4/unix/dltest/pkge.c create mode 100644 mk4/modtcl/tcl8.3.4/unix/dltest/pkgf.c create mode 100644 mk4/modtcl/tcl8.3.4/unix/install-sh create mode 100644 mk4/modtcl/tcl8.3.4/unix/ldAix create mode 100644 mk4/modtcl/tcl8.3.4/unix/mkLinks create mode 100644 mk4/modtcl/tcl8.3.4/unix/tcl.m4 create mode 100644 mk4/modtcl/tcl8.3.4/unix/tcl.spec create mode 100644 mk4/modtcl/tcl8.3.4/unix/tclAppInit.c create mode 100644 mk4/modtcl/tcl8.3.4/unix/tclConfig.sh.in create mode 100644 mk4/modtcl/tcl8.3.4/unix/tclLoadAix.c create mode 100644 mk4/modtcl/tcl8.3.4/unix/tclLoadAout.c create mode 100644 mk4/modtcl/tcl8.3.4/unix/tclLoadDl.c create mode 100644 mk4/modtcl/tcl8.3.4/unix/tclLoadDld.c create mode 100644 mk4/modtcl/tcl8.3.4/unix/tclLoadDyld.c create mode 100644 mk4/modtcl/tcl8.3.4/unix/tclLoadNext.c create mode 100644 mk4/modtcl/tcl8.3.4/unix/tclLoadOSF.c create mode 100644 mk4/modtcl/tcl8.3.4/unix/tclLoadShl.c create mode 100644 mk4/modtcl/tcl8.3.4/unix/tclMtherr.c create mode 100644 mk4/modtcl/tcl8.3.4/unix/tclUnixChan.c create mode 100644 mk4/modtcl/tcl8.3.4/unix/tclUnixEvent.c create mode 100644 mk4/modtcl/tcl8.3.4/unix/tclUnixFCmd.c create mode 100644 mk4/modtcl/tcl8.3.4/unix/tclUnixFile.c create mode 100644 mk4/modtcl/tcl8.3.4/unix/tclUnixInit.c create mode 100644 mk4/modtcl/tcl8.3.4/unix/tclUnixNotfy.c create mode 100644 mk4/modtcl/tcl8.3.4/unix/tclUnixPipe.c create mode 100644 mk4/modtcl/tcl8.3.4/unix/tclUnixPort.h create mode 100644 mk4/modtcl/tcl8.3.4/unix/tclUnixSock.c create mode 100644 mk4/modtcl/tcl8.3.4/unix/tclUnixTest.c create mode 100644 mk4/modtcl/tcl8.3.4/unix/tclUnixThrd.c create mode 100644 mk4/modtcl/tcl8.3.4/unix/tclUnixThrd.h create mode 100644 mk4/modtcl/tcl8.3.4/unix/tclUnixTime.c create mode 100644 mk4/modtcl/tcl8.3.4/unix/tclXtNotify.c create mode 100644 mk4/modtcl/tcl8.3.4/unix/tclXtTest.c create mode 100644 mk4/modtcl/tcl8.3.4/win/CVS/Entries create mode 100644 mk4/modtcl/tcl8.3.4/win/CVS/Repository create mode 100644 mk4/modtcl/tcl8.3.4/win/CVS/Root create mode 100644 mk4/modtcl/tcl8.3.4/win/CVS/Tag create mode 100644 mk4/modtcl/tcl8.3.4/win/Makefile.in create mode 100644 mk4/modtcl/tcl8.3.4/win/README create mode 100644 mk4/modtcl/tcl8.3.4/win/aclocal.m4 create mode 100644 mk4/modtcl/tcl8.3.4/win/cat.c create mode 100644 mk4/modtcl/tcl8.3.4/win/configure create mode 100644 mk4/modtcl/tcl8.3.4/win/configure.in create mode 100644 mk4/modtcl/tcl8.3.4/win/license.terms create mode 100644 mk4/modtcl/tcl8.3.4/win/makefile.vc create mode 100644 mk4/modtcl/tcl8.3.4/win/mkd.bat create mode 100644 mk4/modtcl/tcl8.3.4/win/rmd.bat create mode 100644 mk4/modtcl/tcl8.3.4/win/stub16.c create mode 100644 mk4/modtcl/tcl8.3.4/win/tcl.hpj.in create mode 100644 mk4/modtcl/tcl8.3.4/win/tcl.m4 create mode 100644 mk4/modtcl/tcl8.3.4/win/tcl.rc create mode 100644 mk4/modtcl/tcl8.3.4/win/tclAppInit.c create mode 100644 mk4/modtcl/tcl8.3.4/win/tclConfig.sh.in create mode 100644 mk4/modtcl/tcl8.3.4/win/tclWin32Dll.c create mode 100644 mk4/modtcl/tcl8.3.4/win/tclWinChan.c create mode 100644 mk4/modtcl/tcl8.3.4/win/tclWinConsole.c create mode 100644 mk4/modtcl/tcl8.3.4/win/tclWinDde.c create mode 100644 mk4/modtcl/tcl8.3.4/win/tclWinError.c create mode 100644 mk4/modtcl/tcl8.3.4/win/tclWinFCmd.c create mode 100644 mk4/modtcl/tcl8.3.4/win/tclWinFile.c create mode 100644 mk4/modtcl/tcl8.3.4/win/tclWinInit.c create mode 100644 mk4/modtcl/tcl8.3.4/win/tclWinInt.h create mode 100644 mk4/modtcl/tcl8.3.4/win/tclWinLoad.c create mode 100644 mk4/modtcl/tcl8.3.4/win/tclWinMtherr.c create mode 100644 mk4/modtcl/tcl8.3.4/win/tclWinNotify.c create mode 100644 mk4/modtcl/tcl8.3.4/win/tclWinPipe.c create mode 100644 mk4/modtcl/tcl8.3.4/win/tclWinPort.h create mode 100644 mk4/modtcl/tcl8.3.4/win/tclWinReg.c create mode 100644 mk4/modtcl/tcl8.3.4/win/tclWinSerial.c create mode 100644 mk4/modtcl/tcl8.3.4/win/tclWinSock.c create mode 100644 mk4/modtcl/tcl8.3.4/win/tclWinTest.c create mode 100644 mk4/modtcl/tcl8.3.4/win/tclWinThrd.c create mode 100644 mk4/modtcl/tcl8.3.4/win/tclWinThrd.h create mode 100644 mk4/modtcl/tcl8.3.4/win/tclWinTime.c create mode 100644 mk4/modtcl/tcl8.3.4/win/tclsh.ico create mode 100644 mk4/modtcl/tcl8.3.4/win/tclsh.rc rename CMakeLists.txt => mk5/CMakeLists.txt (100%) rename README.md => mk5/README.md (100%) rename {aura => mk5/aura}/CMakeLists.txt (100%) create mode 100644 mk5/aura/basictypes.c create mode 100644 mk5/aura/basictypes.h create mode 100644 mk5/aura/iterator.c create mode 100644 mk5/aura/iterator.h rename {aura => mk5/aura}/list_iterator.c (100%) create mode 100644 mk5/aura/list_iterator.h rename {aura => mk5/aura}/memutil.c (100%) create mode 100644 mk5/aura/memutil.h rename {aura => mk5/aura}/serialization.c (100%) rename {aura => mk5/aura}/serialization.h (100%) create mode 100644 mk5/aura/serializationinfo.c rename {aura => mk5/aura}/serializationinfo.h (100%) rename {aura => mk5/aura}/stringdictionary.c (100%) rename {aura => mk5/aura}/stringdictionary.h (100%) rename {aura => mk5/aura}/type.h (100%) create mode 100644 mk5/aura/typelocator.c create mode 100644 mk5/aura/typelocator.h rename {continuity => mk5/continuity}/CMakeLists.txt (100%) rename {continuity => mk5/continuity}/continuity.c (100%) rename {continuity => mk5/continuity}/continuity.h (100%) rename {continuity => mk5/continuity}/dis.c (100%) rename {continuity => mk5/continuity}/dl.c (100%) create mode 100644 mk5/continuity/mecha_dep.h rename {continuity => mk5/continuity}/mmc.c (100%) rename {continuity => mk5/continuity}/tas.c (100%) rename {continuity => mk5/continuity}/xfr.c (100%) rename conventions.txt => mk5/conventions.txt (100%) create mode 100644 mk5/example/base.xml create mode 100644 mk5/example/beacon.xml create mode 100644 mk5/example/config.xml create mode 100644 mk5/example/config.xml-dist create mode 100644 mk5/example/dotnet.xml create mode 100644 mk5/example/dynamo.xml create mode 100644 mk5/example/harmony.xml create mode 100644 mk5/example/phpdev.xml create mode 100644 mk5/example/radius.xml create mode 100644 mk5/example/ssl.xml create mode 100644 mk5/example/winkfep.xml rename {mecha => mk5/mecha}/CMakeLists.txt (100%) rename {mecha => mk5/mecha}/ast.c (100%) rename {mecha => mk5/mecha}/b64.c (100%) rename {mecha => mk5/mecha}/bsp.c (100%) rename {mecha => mk5/mecha}/crc.c (100%) rename {mecha => mk5/mecha}/dic.c (100%) rename {mecha => mk5/mecha}/dyn.c (100%) rename {mecha => mk5/mecha}/dyn.h (100%) rename {mecha => mk5/mecha}/exp.c (100%) rename {mecha => mk5/mecha}/fle.c (100%) rename {mecha => mk5/mecha}/hsh.c (100%) rename {mecha => mk5/mecha}/log.c (100%) rename {mecha => mk5/mecha}/lst.c (100%) rename {mecha => mk5/mecha}/lst.h (100%) rename {mecha => mk5/mecha}/lst_void.c (100%) rename {mecha => mk5/mecha}/map.c (100%) rename {mecha => mk5/mecha}/mecha.c (100%) rename {mecha => mk5/mecha}/mecha.h (100%) rename {mecha => mk5/mecha}/mem.c (100%) rename {mecha => mk5/mecha}/net.c (100%) rename {mecha => mk5/mecha}/net.h (100%) rename {mecha => mk5/mecha}/pat.c (100%) rename {mecha => mk5/mecha}/qry.c (100%) rename {mecha => mk5/mecha}/rnd.c (100%) rename {mecha => mk5/mecha}/str.c (100%) rename {mecha => mk5/mecha}/thr.c (100%) rename {mecha => mk5/mecha}/tls.c (100%) rename {mecha => mk5/mecha}/uid.c (100%) rename {mecha => mk5/mecha}/utl.c (100%) rename {mecha => mk5/mecha}/xml.c (100%) rename {modhttp => mk5/modhttp}/CMakeLists.txt (100%) rename {modhttp => mk5/modhttp}/http.c (100%) rename {modhttp => mk5/modhttp}/http.cbp (100%) rename {modhttp => mk5/modhttp}/http.h (100%) rename {modm3 => mk5/modm3}/CMakeLists.txt (100%) create mode 100644 mk5/modm3/_build.h rename {modm3 => mk5/modm3}/file_catalog.c (100%) create mode 100644 mk5/modm3/file_catalog.h rename {modm3 => mk5/modm3}/file_entry.c (100%) create mode 100644 mk5/modm3/file_entry.h rename {modm3 => mk5/modm3}/file_reader.c (100%) create mode 100644 mk5/modm3/file_reader.h create mode 100644 mk5/modm3/idata_reader.h rename {modm3 => mk5/modm3}/iplaylist.h (100%) create mode 100644 mk5/modm3/ixtime.c create mode 100644 mk5/modm3/ixtime.h rename {modm3 => mk5/modm3}/m3.c (100%) rename {modm3 => mk5/modm3}/m3.h (100%) rename {modm3 => mk5/modm3}/m3_client.c (100%) rename {modm3 => mk5/modm3}/m3_client.h (100%) rename {modm3 => mk5/modm3}/m3_server.c (100%) rename {modm3 => mk5/modm3}/m3_server.h (100%) rename {modm3 => mk5/modm3}/m3_server_factory.c (100%) create mode 100644 mk5/modm3/m3_server_factory.h rename {modm3 => mk5/modm3}/m3_tcl.c (100%) create mode 100644 mk5/modm3/m3_tcl.h create mode 100644 mk5/modm3/mp3_frame.c create mode 100644 mk5/modm3/mp3_frame.h rename {modm3 => mk5/modm3}/mp3_reader.c (100%) rename {modm3 => mk5/modm3}/mp3_reader.h (100%) rename {modm3 => mk5/modm3}/music_packet.c (100%) rename {modm3 => mk5/modm3}/music_packet.h (100%) rename {modm3 => mk5/modm3}/order_playlist_engine.c (100%) create mode 100644 mk5/modm3/order_playlist_engine.h rename {modm3 => mk5/modm3}/playlist.c (100%) rename {modm3 => mk5/modm3}/playlist.h (100%) rename {modm3 => mk5/modm3}/playlist_engine_factory.c (100%) create mode 100644 mk5/modm3/playlist_engine_factory.h rename {modm3 => mk5/modm3}/playlist_manager.c (100%) rename {modm3 => mk5/modm3}/playlist_manager.h (100%) rename {modm3 => mk5/modm3}/queue_playlist_engine.c (100%) create mode 100644 mk5/modm3/queue_playlist_engine.h create mode 100644 mk5/modm3/randomlist_playlist_engine.c create mode 100644 mk5/modm3/randomlist_playlist_engine.h rename {modm3 => mk5/modm3}/shoutcast_metadata_writer.c (100%) create mode 100644 mk5/modm3/shoutcast_metadata_writer.h create mode 100644 mk5/modm3/support.c create mode 100644 mk5/modm3/support.h rename {modsite => mk5/modsite}/CMakeFiles/progress.marks (100%) rename {modsite => mk5/modsite}/CMakeFiles/site.dir/C.includecache (100%) rename {modsite => mk5/modsite}/CMakeFiles/site.dir/DependInfo.cmake (100%) rename {modsite => mk5/modsite}/CMakeFiles/site.dir/build.make (100%) rename {modsite => mk5/modsite}/CMakeFiles/site.dir/cmake_clean.cmake (100%) rename {modsite => mk5/modsite}/CMakeFiles/site.dir/depend.internal (100%) rename {modsite => mk5/modsite}/CMakeFiles/site.dir/depend.make (100%) rename {modsite => mk5/modsite}/CMakeFiles/site.dir/flags.make (100%) rename {modsite => mk5/modsite}/CMakeFiles/site.dir/link.txt (100%) rename {modsite => mk5/modsite}/CMakeFiles/site.dir/log.c.o (100%) rename {modsite => mk5/modsite}/CMakeFiles/site.dir/progress.make (100%) rename {modsite => mk5/modsite}/CMakeFiles/site.dir/site.c.o (100%) rename {modsite => mk5/modsite}/CMakeLists.txt (100%) rename {modsite => mk5/modsite}/log.c (100%) rename {modsite => mk5/modsite}/site.c (100%) rename {modsite => mk5/modsite}/site.h (100%) create mode 100644 mk5/modsite/siteerror.h rename {modtcl => mk5/modtcl}/CMakeLists.txt (100%) rename {modtcl => mk5/modtcl}/cmds.c (100%) rename {modtcl => mk5/modtcl}/modtcl.c (100%) rename {modtcl => mk5/modtcl}/modtcl.h (100%) create mode 100644 mk5/modtcl/modtcl.xml rename {sandbox => mk5/sandbox}/CMakeLists.txt (100%) rename {sandbox => mk5/sandbox}/sandbox.c (100%) diff --git a/mk4/CVS/Entries b/mk4/CVS/Entries new file mode 100644 index 0000000..93673e6 --- /dev/null +++ b/mk4/CVS/Entries @@ -0,0 +1,28 @@ +/Makefile.in/1.8/Fri May 21 14:06:10 2004//Tmk4_mod6_rc2 +/buildconf/1.1.2.1/Fri Jul 9 14:05:35 2004//Tmk4_mod6_rc2 +/config.guess/1.1/Wed May 19 18:34:28 2004//Tmk4_mod6_rc2 +/config.sub/1.1/Wed May 19 18:34:28 2004//Tmk4_mod6_rc2 +/configure.in/1.5/Wed May 19 21:02:58 2004//Tmk4_mod6_rc2 +/install-sh/1.1/Wed May 19 18:34:28 2004//Tmk4_mod6_rc2 +D/continuity//// +D/doc//// +D/httpclient//// +D/lib//// +D/mobility-client//// +D/modbeacon//// +D/modcommand//// +D/moddb//// +D/moddynamo//// +D/modexample//// +D/modharmony//// +D/modhtaccess//// +D/modhttp//// +D/modimage//// +D/modjava//// +D/modm3//// +D/modmobility//// +D/modoracle//// +D/modradius//// +D/modsite//// +D/modssl//// +D/modtcl//// diff --git a/mk4/CVS/Repository b/mk4/CVS/Repository new file mode 100644 index 0000000..2a3f244 --- /dev/null +++ b/mk4/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc diff --git a/mk4/CVS/Root b/mk4/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/CVS/Tag b/mk4/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/Makefile.in b/mk4/Makefile.in new file mode 100644 index 0000000..d3a80b8 --- /dev/null +++ b/mk4/Makefile.in @@ -0,0 +1,51 @@ +# $Id: Makefile.in,v 1.8 2004/05/21 14:06:10 aleigh Exp $ + +MODS=@MODS@ +LIBS=@LIBS@ + +world: continuity/bin/continuity libs modules + +libs: + for dir in $(LIBS); do \ + $(MAKE) -C $$dir; \ + done + +libs_clean: + for dir in $(LIBS); do \ + $(MAKE) -C $$dir clean; \ + done + +modules: modules_depend + for dir in $(MODS); do \ + $(MAKE) -C $$dir; \ + done + +modules_depend: .modules_depended + +.modules_depended: + for dir in $(MODS); do \ + cp $$dir/Makefile.in $$dir/Makefile; \ + $(MAKE) -C $$dir depend; \ + done + touch .modules_depended + +modules_clean: + for dir in $(MODS); do \ + $(MAKE) -C $$dir clean; \ + done + +continuity/bin/continuity: continuity/Makefile + (cd continuity ; make) + +continuity/configure: continuity/configure.in + (cd continuity ; autoconf) + +continuity/Makefile: continuity/configure continuity/mecha/Makefile.in continuity/cont/Makefile.in + (cd continuity ; ./configure) + +count: + find . -name '*.c' | grep -v tcl8.3.4 | grep -v jpeg-6b | grep -v pcre | xargs wc -l | grep total + +clean: modules_clean + $(MAKE) -C continuity clean + diff --git a/mk4/buildconf b/mk4/buildconf new file mode 100644 index 0000000..8a7b020 --- /dev/null +++ b/mk4/buildconf @@ -0,0 +1,4 @@ +#!/bin/sh + +autoconf + diff --git a/mk4/config.guess b/mk4/config.guess new file mode 100644 index 0000000..81688c4 --- /dev/null +++ b/mk4/config.guess @@ -0,0 +1,1284 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000 +# Free Software Foundation, Inc. + +version='2000-07-27' + +# 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. + +# Written by Per Bothner . +# Please send patches to . +# +# 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 system type (host/target name). +# +# Only a few systems have been added to this list; please add others +# (but try to keep the structure clean). +# + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of this system. + +Operation modes: + -h, --help print this help, then exit + -V, --version print version number, then exit" + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case "$1" in + --version | --vers* | -V ) + echo "$version" ; exit 0 ;; + --help | --h* | -h ) + echo "$usage"; exit 0 ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + exec >&2 + echo "$me: invalid option $1" + echo "$help" + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +# Use $HOST_CC if defined. $CC may point to a cross-compiler +if test x"$CC_FOR_BUILD" = x; then + if test x"$HOST_CC" != x; then + CC_FOR_BUILD="$HOST_CC" + else + if test x"$CC" != x; then + CC_FOR_BUILD="$CC" + else + CC_FOR_BUILD=cc + fi + fi +fi + + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 8/24/94.) +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 + +dummy=dummy-$$ +trap 'rm -f $dummy.c $dummy.o $dummy; exit 1' 1 2 15 + +# 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. + # Determine the machine/vendor (is the vendor relevant). + case "${UNAME_MACHINE}" in + amiga) machine=m68k-unknown ;; + arm32) machine=arm-unknown ;; + atari*) machine=m68k-atari ;; + sun3*) machine=m68k-sun ;; + mac68k) machine=m68k-apple ;; + macppc) machine=powerpc-apple ;; + hp3[0-9][05]) machine=m68k-hp ;; + ibmrt|romp-ibm) machine=romp-ibm ;; + *) machine=${UNAME_MACHINE}-unknown ;; + esac + # The Operating System including object format. + 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 + # The OS release + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + # 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 ;; + alpha:OSF1:*:*) + if test $UNAME_RELEASE = "V4.0"; then + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + fi + # 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. + cat <$dummy.s + .data +\$Lformat: + .byte 37,100,45,37,120,10,0 # "%d-%x\n" + + .text + .globl main + .align 4 + .ent main +main: + .frame \$30,16,\$26,0 + ldgp \$29,0(\$27) + .prologue 1 + .long 0x47e03d80 # implver \$0 + lda \$2,-1 + .long 0x47e20c21 # amask \$2,\$1 + lda \$16,\$Lformat + mov \$0,\$17 + not \$1,\$18 + jsr \$26,printf + ldgp \$29,0(\$26) + mov 0,\$16 + jsr \$26,exit + .end main +EOF + $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null + if test "$?" = 0 ; then + case `./$dummy` in + 0-0) + UNAME_MACHINE="alpha" + ;; + 1-0) + UNAME_MACHINE="alphaev5" + ;; + 1-1) + UNAME_MACHINE="alphaev56" + ;; + 1-101) + UNAME_MACHINE="alphapca56" + ;; + 2-303) + UNAME_MACHINE="alphaev6" + ;; + 2-307) + UNAME_MACHINE="alphaev67" + ;; + esac + fi + rm -f $dummy.s $dummy + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | 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;; + amiga:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit 0 ;; + arc64:OpenBSD:*:*) + echo mips64el-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + arc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + hkmips:OpenBSD:*:*) + echo mips-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + pmax:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sgi:OpenBSD:*:*) + echo mips-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + wgrisc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit 0 ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit 0;; + SR2?01: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 ;; + 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=`(head -1 /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 ;; + atari*:OpenBSD:*:*) + echo m68k-unknown-openbsd${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 ;; + sun3*:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mac68k:OpenBSD:*:*) + echo m68k-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 ;; + 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) + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* 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 $dummy.c -o $dummy \ + && ./$dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \ + && rm $dummy.c $dummy && exit 0 + rm -f $dummy.c $dummy + echo mips-mips-riscos${UNAME_RELEASE} + 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 ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm $dummy.c $dummy && exit 0 + rm -f $dummy.c $dummy + 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:*:4) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | head -1 | awk '{ print $1 }'` + if /usr/sbin/lsattr -EHl ${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=4.${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:*:*) + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + 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 $dummy.c -o $dummy 2>/dev/null ) && HP_ARCH=`./$dummy` + rm -f $dummy.c $dummy + esac + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit 0 ;; + 3050*:HI-UX:*:*) + sed 's/^ //' << EOF >$dummy.c + #include + 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 $dummy.c -o $dummy && ./$dummy && rm $dummy.c $dummy && exit 0 + rm -f $dummy.c $dummy + 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:*:*) + 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 ;; + hppa*:OpenBSD:*:*) + echo hppa-unknown-openbsd + 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*X-MP:*:*:*) + echo xmp-cray-unicos + exit 0 ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} + 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/ + exit 0 ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*T3E:*:*:*) + echo alpha-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY-2:*:*:*) + echo cray2-cray-unicos + exit 0 ;; + F300:UNIX_System_V:*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "f300-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit 0 ;; + F301:UNIX_System_V:*:*) + echo f301-fujitsu-uxpv`echo $UNAME_RELEASE | sed 's/ .*//'` + exit 0 ;; + hp300:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + 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 ;; + *:OpenBSD:*:*) + echo ${UNAME_MACHINE}-unknown-openbsd`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*: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 i386-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:*:*) + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit 0 ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit 0 ;; + *: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. + ld_help_string=`cd /; ld --help 2>&1` + ld_supported_emulations=`echo $ld_help_string \ + | sed -ne '/supported emulations:/!d + s/[ ][ ]*/ /g + s/.*supported emulations: *// + s/ .*// + p'` + case "$ld_supported_emulations" in + *ia64) + echo "${UNAME_MACHINE}-unknown-linux" + exit 0 + ;; + i?86linux) + echo "${UNAME_MACHINE}-pc-linux-gnuaout" + exit 0 + ;; + elf_i?86) + TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" + ;; + i?86coff) + echo "${UNAME_MACHINE}-pc-linux-gnucoff" + exit 0 + ;; + sparclinux) + echo "${UNAME_MACHINE}-unknown-linux-gnuaout" + exit 0 + ;; + armlinux) + echo "${UNAME_MACHINE}-unknown-linux-gnuaout" + exit 0 + ;; + elf32arm*) + echo "${UNAME_MACHINE}-unknown-linux-gnuoldld" + exit 0 + ;; + armelf_linux*) + echo "${UNAME_MACHINE}-unknown-linux-gnu" + exit 0 + ;; + m68klinux) + echo "${UNAME_MACHINE}-unknown-linux-gnuaout" + exit 0 + ;; + elf32ppc | elf32ppclinux) + # Determine Lib Version + cat >$dummy.c < +#if defined(__GLIBC__) +extern char __libc_version[]; +extern char __libc_release[]; +#endif +main(argc, argv) + int argc; + char *argv[]; +{ +#if defined(__GLIBC__) + printf("%s %s\n", __libc_version, __libc_release); +#else + printf("unkown\n"); +#endif + return 0; +} +EOF + LIBC="" + $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null + if test "$?" = 0 ; then + ./$dummy | grep 1\.99 > /dev/null + if test "$?" = 0 ; then + LIBC="libc1" + fi + fi + rm -f $dummy.c $dummy + echo powerpc-unknown-linux-gnu${LIBC} + exit 0 + ;; + shelf_linux) + echo "${UNAME_MACHINE}-unknown-linux-gnu" + exit 0 + ;; + esac + + if test "${UNAME_MACHINE}" = "alpha" ; then + cat <$dummy.s + .data + \$Lformat: + .byte 37,100,45,37,120,10,0 # "%d-%x\n" + + .text + .globl main + .align 4 + .ent main + main: + .frame \$30,16,\$26,0 + ldgp \$29,0(\$27) + .prologue 1 + .long 0x47e03d80 # implver \$0 + lda \$2,-1 + .long 0x47e20c21 # amask \$2,\$1 + lda \$16,\$Lformat + mov \$0,\$17 + not \$1,\$18 + jsr \$26,printf + ldgp \$29,0(\$26) + mov 0,\$16 + jsr \$26,exit + .end main +EOF + LIBC="" + $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null + if test "$?" = 0 ; then + case `./$dummy` in + 0-0) + UNAME_MACHINE="alpha" + ;; + 1-0) + UNAME_MACHINE="alphaev5" + ;; + 1-1) + UNAME_MACHINE="alphaev56" + ;; + 1-101) + UNAME_MACHINE="alphapca56" + ;; + 2-303) + UNAME_MACHINE="alphaev6" + ;; + 2-307) + UNAME_MACHINE="alphaev67" + ;; + esac + + objdump --private-headers $dummy | \ + grep ld.so.1 > /dev/null + if test "$?" = 0 ; then + LIBC="libc1" + fi + fi + rm -f $dummy.s $dummy + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} ; exit 0 + elif test "${UNAME_MACHINE}" = "mips" ; then + cat >$dummy.c < /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif +#ifdef __MIPSEB__ + printf ("%s-unknown-linux-gnu\n", argv[1]); +#endif +#ifdef __MIPSEL__ + printf ("%sel-unknown-linux-gnu\n", argv[1]); +#endif + return 0; +} +EOF + $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0 + rm -f $dummy.c $dummy + elif test "${UNAME_MACHINE}" = "s390"; then + echo s390-ibm-linux && exit 0 + else + # Either a pre-BFD a.out linker (linux-gnuoldld) + # or one that does not give us useful --help. + # GCC wants to distinguish between linux-gnuoldld and linux-gnuaout. + # If ld does not provide *any* "supported emulations:" + # that means it is gnuoldld. + echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations:" + test $? != 0 && echo "${UNAME_MACHINE}-pc-linux-gnuoldld" && exit 0 + + case "${UNAME_MACHINE}" in + i?86) + VENDOR=pc; + ;; + *) + VENDOR=unknown; + ;; + esac + # Determine whether the default compiler is a.out or elf + cat >$dummy.c < +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif +#ifdef __ELF__ +# ifdef __GLIBC__ +# if __GLIBC__ >= 2 + printf ("%s-${VENDOR}-linux-gnu\n", argv[1]); +# else + printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]); +# endif +# else + printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]); +# endif +#else + printf ("%s-${VENDOR}-linux-gnuaout\n", argv[1]); +#endif + return 0; +} +EOF + $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0 + rm -f $dummy.c $dummy + test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0 + fi ;; +# 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. + i?86:DYNIX/ptx:4*:*) + 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:*: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:7*) + # Fixed at (any) Pentium or better + UNAME_MACHINE=i586 + if [ ${UNAME_SYSTEM} = "UnixWare" ] ; then + echo ${UNAME_MACHINE}-sco-sysv${UNAME_RELEASE}uw${UNAME_VERSION} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE} + fi + exit 0 ;; + i?86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')` + (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|egrep '^Machine.*Pent ?II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|egrep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit 0 ;; + i?86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + 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 ;; + M68*:*:R3V[567]*:*) + test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; + 3[34]??:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*: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.*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit 0 ;; + i?86:LynxOS:2.*:* | i?86:LynxOS:3.[01]*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + rs6000:LynxOS:2.*:* | PowerPC:LynxOS:2.*:*) + echo rs6000-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:CPunix:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit 0 ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # 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 ;; + 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 ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit 0 ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit 0 ;; + *:Darwin:*:*) + echo `uname -p`-apple-darwin${UNAME_RELEASE} + exit 0 ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + if test "${UNAME_MACHINE}" = "x86pc"; then + UNAME_MACHINE=pc + fi + echo `uname -p`-${UNAME_MACHINE}-nto-qnx + exit 0 ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit 0 ;; + NSR-W:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + 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 ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +cat >$dummy.c < +# include +#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 + 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) + printf ("vax-dec-bsd\n"); exit (0); +#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 $dummy.c -o $dummy 2>/dev/null && ./$dummy && rm $dummy.c $dummy && exit 0 +rm -f $dummy.c $dummy + +# 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 < in order to provide the needed +information to handle your system. + +config.guess version = $version + +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: "version='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/mk4/config.sub b/mk4/config.sub new file mode 100644 index 0000000..945a7f4 --- /dev/null +++ b/mk4/config.sub @@ -0,0 +1,1324 @@ +#! /bin/sh +# Configuration validation subroutine script, version 1.1. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000 +# Free Software Foundation, Inc. + +version='2000-08-07' + +# 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 . +# +# 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 + -V, --version print version number, then exit" + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case "$1" in + --version | --vers* | -V ) + echo "$version" ; exit 0 ;; + --help | --h* | -h ) + echo "$usage"; exit 0 ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + exec >&2 + echo "$me: invalid option $1" + echo "$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*) + 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) + os= + basic_machine=$1 + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + 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. + tahoe | i860 | ia64 | m32r | m68k | m68000 | m88k | ns32k | arc | arm \ + | arme[lb] | armv* | pyramid | mn10200 | mn10300 | tron | a29k \ + | 580 | i960 | h8300 \ + | x86 | ppcbe | mipsbe | mipsle | shbe | shle | armbe | armle \ + | hppa | hppa1.0 | hppa1.1 | hppa2.0 | hppa2.0w | hppa2.0n \ + | hppa64 \ + | alpha | alphaev[4-8] | alphaev56 | alphapca5[67] \ + | alphaev6[78] \ + | we32k | ns16k | clipper | i370 | sh | sh[34] \ + | powerpc | powerpcle \ + | 1750a | dsp16xx | pdp11 | mips16 | mips64 | mipsel | mips64el \ + | mips64orion | mips64orionel | mipstx39 | mipstx39el \ + | mips64vr4300 | mips64vr4300el | mips64vr4100 | mips64vr4100el \ + | mips64vr5000 | miprs64vr5000el | mcore \ + | sparc | sparclet | sparclite | sparc64 | sparcv9 | v850 | c4x \ + | thumb | d10v | d30v | fr30 | avr) + 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 | z8k | v70 | h8500 | w65 | pj | pjl) + ;; + + # 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[234567]86) + 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. + # FIXME: clean up the formatting here. + vax-* | tahoe-* | i[234567]86-* | i860-* | ia64-* | m32r-* | m68k-* | m68000-* \ + | m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | arm-* | c[123]* \ + | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \ + | power-* | none-* | 580-* | cray2-* | h8300-* | h8500-* | i960-* \ + | xmp-* | ymp-* \ + | x86-* | ppcbe-* | mipsbe-* | mipsle-* | shbe-* | shle-* | armbe-* | armle-* \ + | hppa-* | hppa1.0-* | hppa1.1-* | hppa2.0-* | hppa2.0w-* \ + | hppa2.0n-* | hppa64-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphapca5[67]-* \ + | alphaev6[78]-* \ + | we32k-* | cydra-* | ns16k-* | pn-* | np1-* | xps100-* \ + | clipper-* | orion-* \ + | sparclite-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \ + | sparc64-* | sparcv9-* | sparc86x-* | mips16-* | mips64-* | mipsel-* \ + | mips64el-* | mips64orion-* | mips64orionel-* \ + | mips64vr4100-* | mips64vr4100el-* | mips64vr4300-* | mips64vr4300el-* \ + | mipstx39-* | mipstx39el-* | mcore-* \ + | f301-* | armv*-* | s390-* | sv1-* | t3e-* \ + | m88110-* | m680[01234]0-* | m683?2-* | m68360-* | z8k-* | d10v-* \ + | thumb-* | v850-* | d30v-* | tic30-* | c30-* | fr30-* \ + | bs2000-* | tic54x-* | c54x-*) + ;; + # 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 + ;; + 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 + ;; + 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 + ;; + 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 | ymp) + basic_machine=ymp-cray + os=-unicos + ;; + cray2) + basic_machine=cray2-cray + os=-unicos + ;; + [ctj]90-cray) + basic_machine=c90-cray + os=-unicos + ;; + crds | unos) + basic_machine=m68k-crds + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + 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 + ;; + 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[34567]86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i[34567]86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i[34567]86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i[34567]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 + ;; + i386-go32 | go32) + basic_machine=i386-unknown + os=-go32 + ;; + i386-mingw32 | mingw32) + basic_machine=i386-unknown + os=-mingw32 + ;; + 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 + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mipsel*-linux*) + basic_machine=mipsel-unknown + os=-linux-gnu + ;; + mips*-linux*) + basic_machine=mips-unknown + os=-linux-gnu + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + mmix*) + basic_machine=mmix-knuth + os=-mmixware + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + msdos) + basic_machine=i386-unknown + 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 + ;; + np1) + basic_machine=np1-gould + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + 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 | nexen) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon) + basic_machine=i686-pc + ;; + pentiumii | pentium2) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexen-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=rs6000-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/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sparclite-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=t3e-cray + os=-unicos + ;; + tic54x | c54x*) + basic_machine=tic54x-unknown + os=-coff + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + 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 + ;; + xmp) + basic_machine=xmp-cray + os=-unicos + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + 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 + ;; + mips) + if [ x$os = x-linux-gnu ]; then + basic_machine=mips-unknown + else + basic_machine=mips-mips + fi + ;; + romp) + basic_machine=romp-ibm + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh3 | sh4) + base_machine=sh-unknown + ;; + sparc | sparcv9) + 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 + ;; + c4x*) + basic_machine=c4x-none + os=-coff + ;; + *) + 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. + -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* | -netbsd* | -openbsd* | -freebsd* | -riscix* \ + | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i[34567]86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto*) + os=-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*) + 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 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -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) + os=-mint + ;; + -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 + ;; + 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 + ;; + *-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 + ;; + *-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 + ;; + f301-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 + ;; + -ptx*) + vendor=sequent + ;; + -vxsim* | -vxworks*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -*MiNT) + vendor=atari + ;; + 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: "version='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/mk4/configure.in b/mk4/configure.in new file mode 100644 index 0000000..c9f9531 --- /dev/null +++ b/mk4/configure.in @@ -0,0 +1,27 @@ +AC_INIT(continuity/configure.in) + +AC_ARG_ENABLE(causality,dnl +[ --enable-causality Build Causality and associated modules], +docausality=yes) + +AC_CANONICAL_SYSTEM + +echo "target_cpu: $target_cpu" +echo "target_os: $target_os" + +case "$target_os" in +*) + MODS="modcommand moddb modhttp modsite modtcl modbeacon modimage modm3" + LIBS="lib/aura" + + if test "$docausality" = "yes" ; then + echo "Building w/ Causality" + LIBS="$LIBS lib/causality lib/causality-client" + MODS="$MODS" + fi +;; +esac + +AC_SUBST(MODS) +AC_SUBST(LIBS) +AC_OUTPUT(Makefile) diff --git a/mk4/continuity/.cvsignore b/mk4/continuity/.cvsignore new file mode 100644 index 0000000..39915d0 --- /dev/null +++ b/mk4/continuity/.cvsignore @@ -0,0 +1,5 @@ +autom4te.cache +configure +config.log +config.status +Makefile diff --git a/mk4/continuity/CVS/Entries b/mk4/continuity/CVS/Entries new file mode 100644 index 0000000..9a1eb19 --- /dev/null +++ b/mk4/continuity/CVS/Entries @@ -0,0 +1,15 @@ +/.cvsignore/1.1/Thu Mar 11 01:11:48 2004//Tmk4_mod6_rc2 +/ChangeLog/1.23/Tue Dec 30 16:21:06 2003//Tmk4_mod6_rc2 +/Makefile.in/1.11/Wed May 19 19:49:55 2004//Tmk4_mod6_rc2 +/TODO/1.14/Fri May 21 20:53:44 2004//Tmk4_mod6_rc2 +/config.guess/1.1.1.1/Wed Oct 1 20:43:36 2003//Tmk4_mod6_rc2 +/config.sub/1.1.1.1/Wed Oct 1 20:43:36 2003//Tmk4_mod6_rc2 +/configure.in/1.30/Thu Jun 3 14:40:29 2004//Tmk4_mod6_rc2 +/install-sh/1.1.1.1/Wed Oct 1 20:43:36 2003//Tmk4_mod6_rc2 +/todoc/1.24/Thu May 13 14:11:25 2004//Tmk4_mod6_rc2 +D/bin//// +D/cont//// +D/include//// +D/lib//// +D/mecha//// +D/pcre//// diff --git a/mk4/continuity/CVS/Repository b/mk4/continuity/CVS/Repository new file mode 100644 index 0000000..6470a57 --- /dev/null +++ b/mk4/continuity/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/continuity diff --git a/mk4/continuity/CVS/Root b/mk4/continuity/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/continuity/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/continuity/CVS/Tag b/mk4/continuity/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/continuity/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/continuity/ChangeLog b/mk4/continuity/ChangeLog new file mode 100644 index 0000000..8f20ab7 --- /dev/null +++ b/mk4/continuity/ChangeLog @@ -0,0 +1,659 @@ +# $Id: ChangeLog,v 1.23 2003/12/30 16:21:06 aleigh Exp $ + +- Mark 4 mod 1 rc3 + ++ Added lstFset_badd() + ++ Added memFdup() + +- Mark 4 mod 1 rc3 + +- Mark 4 mod 1 rc2 + ++ Added memFalloc, memFfree, memFrealloc in mecha. + ++ Converted bcopy() to memFcopy() in mecha. + ++ Converted bzero() to memFclear() in mecha. + ++ Changed #include directives in mecha to include the literal path. + +- Mark 4 mod 1 rc1 + ++ XML Parser now supports comments + ++ Added int utlFip_match(unsigned int ipa, unsigned int ipb, unsigned int netmask) + ++ Fixed an issue where bspFdestroy() could double-destruct a user data + pointer. + ++ Fixed an issue where a blank extension would trigger an assertion + in siteFfind_mimetype. + ++ New function xmlFcreate_list(); + ++ SSL support via OpenSSL Library + ++ Removed OpenBSD, FreeBSD configuration targets + ++ Removed old un-used functions checks from configure + ++ Changed utlFhttp_time_print() to be recursive. + ++ added mem.c + ++ Added dynFreset() + ++ Removed version information from mod/http + ++ Removed version information from mod/site + +- Mark 4 mod 0 + ++ Changed the format of the output line when a library is linked + ++ Solved a synchronization problem in the thread-pool. + ++ Added fleFget_size(), fleFload_file() + ++ Added strFis_whitespace() + ++ Removed old qry API + ++ Moved qryF* into qry.c + ++ Added netTreader *netFreader_init(void), void netFreader_free(netTreader *reader); + ++ disF* interface moved to dis.c + ++ Moved b64, bsp, bus, crc, dyn, fle, hsh, log, lst, rnd, str, thr, + tls, uid and utl to new "mechanism" library. + ++ pckF* interface moved to lst.c / lstF* + ++ uuidF* interface moved to uid.c / uidF* + ++ utlF* interface moved into utl.c + ++ hshFlist_* interface moved to hsh_dep.c + ++ utlFurl_encode() and utlFurl_decode() now return int status instead + of a pointer to the string. The encoded string can be found inside + the dynbuffer. + ++ Added dynFgetstr(), dynFgetlen() + ++ Seperated the lstFlist* code into lst_void.c + ++ strFdup() deprecated, strFcopy() instead. + ++ Changed types in networking functions; size_t -> ssize_t + ++ Disabled delayed-thread-creation in the thread pools. + +- Mark 3 mod 7 + ++ mod/php: Country-code now added as $_SERVER["country_code"] if present in the + transaction. + ++ Added hash iterator code. + ++ Added new code bus.c for a bus data structure. + ++ Added new raw hashing calls for hashing void pointers where + the object representing the name is not a text string. + ++ Added a new set of convinience hashing calls for dealing with + integer keys. + ++ Added mod/outboard, for two-task IPC processing. + ++ Added unsigned int rndFnumber (void) + ++ Added new IPC handling code built on the SysV message queue interface. + + + +- Mark 3 mod 6 + ++ Removed the annoying size debug message. + ++ Removed "did not find mime-type" message. + ++ Added _netFwritef which takes char *fmt, va_list + ++ Added httpFwritef() which takes *fmt, ... + ++ Code re-formatting and error message updating for tpool.c + ++ tpool now tracks in-use threads, and started threads, via the tpool structure. + ++ Removed dispatcher startup messages. + ++ Removed the triggering message on timeout sockets. + ++ Modified the thread-pool so that threads are only created when there are less than the max + number of configured threads, but, the no threads are available to process a work element. + Threads will still never be destroyed. This will allow people to set relatively high thread + maximums while only using the resources they actually need. + ++ Removed continuity startup broadcast messages. + ++ Removed mod/http short request message. + ++ Updated release header for http.h, which was missing httpFread() + ++ Removed mod/oracle checkin/checkout messages. + + + +- Mark 3 mod 5 + ++ Removed the pthread_cond functionality under LINUX for the startup wait. + instead the threads pin every 500ms checking the startup condition. On Linux + if threads go into pthread_cond_wait, then the process changes uid and triggers + the conditional, the blocked threads do not fire. + ++ Modified crt paths to support the Forte 7 compiler + ++ Checks for -lresolv, inet_aton() moved here + ++ New ip= option for dispatcher to set the bind IP. Defaults to + 0 (*) if unset in the configuration. + ++ Brought back BUG 10022 + ++ Fixed a problem in the php POST read function that was preventing + file upload from working properly. + + + +- Mark 3 mod 4 + + + Improved interior header files. + + + Removed a bug in hshFvoid_del() + + + Removed old dead ring code. + + + Started transitioning error messages to use sterror() + + + -Wall now default for GCC builds + + = Moved REQ_ constants from continuity.h into mod/http. + + + Added new transaction status REQ_HEADERSENT. + + = httpFstart_response no() longer sends the headers. + + + httpFhandler now calls httpFsend_response() if the transaction finishes + and the status is still REQ_STARTED. + + + Added netFwrite_two() and netFwritev() + + + mod/general do_error() now calls httpFsend_response() + + + reponse headers now arrive in same packet as the first data. + + + moved REQ_* and included new netF() functions in the release headers. + + + re-instituted TCP_NODELAY + + + I/O completly remodeled to use poll() and to guarantee read to worker threads + + + New profiling capability: define CAPI_PROFILE in continuity.h + + + New options for the dispatcher, threads and queue. + + + Failure to dlopen() a .so is now a fatal error. + + + +- Mark 3 mod 3 + + ID PRODUCT_OS SUBPRODUCT SDESC +---------- ---------- ---------- --------------------------------------------- + 10003 generic modhttp 404 needs to happen in send_file + 10009 darwin6.1 modphp php won't compile on OSX + 10011 generic modhttp docpath not documented + 10013 generic modhttp req_uri vanished + 10014 darwin6.2 continuity xfrFmmap does not work on OSX + + + +- Mark 3 mod 1 + + + +- Mark 3 Mod 0 + + + Added stub code for mod/tcl_http + + + Re-Introduced mod/tcl. Rewrote the module so that it supposed the concept + of Tcl Worlds, which allow for multiple things to use interpreter pools. + + + Introduced mod/voice, a VRU processing platform. + + + Moved the rdwr code from compat into core, as this is going to be used on all + the platforms due to semantical difficulties with the way the unlock function + is called. + + + Build makefile.in's now take care to ./configure + + + Deprecated the incr stat function. + + + mod/tcl now has a sketched out interface for multiple TCL worlds. + + + Cleaned up dispatcher to have a single interface. + + + continuity no longer takes the -p or -a options. + + + Removed all the modules from the build except for TCL. + The TCL module is going to be genericized to only offer + the TCL functionality without any HTTP functions. + + + Removed include/capi.h. This file is now deprecated. + The public module include will be continuity.h for the platform, + with the addition of http.h for the webserver functionality. + + + Removed balance.c and associated functions. + + + Removed qry functions that used qryTent. The lstTset interface + is now the only supported interface. + + + Removed dead symlink call from file.c + + + Removed http.c, and all functions from dl.c, net.c, xfer.c, etc that + referenced httpTtrans. + + + +- mk2 mod15 + + + Added client_read variable to the httpTtrans structure for keeping + track of post reads. + + + +- mk2 mod14 + + + Error dump page now contains the hostname. + + + Dialer now supports pgmid parameter. + + + +- 2.0.13 + + + New -u option for setting user. + + + dispatcher split up to setup / run phase, to allow + setuid activity after the ports are bound. + + + check-type strips trailing slashes. + + + New TCL command ta_http_query_get + + + httpTtrans now contains a new element. OLD MODULES + WILL HAVE TO BE RECOMPILED. + + + dynFappend() was not actually honoring len on copy. + + + HTTP 201 response was malformed. + + + Solaris target now is enabled for pre-fetching. + + + Continuity now has a single-shot build which provides marked + optimization performance. + + + utlFurl_decode now converts +'s into spaces + + + ID based messages, which will eventually be backed by some form of + loaded NLS. + + + Certain situations resulting in a valid result->error from TCL + that did not have a global error would result in a crash. + + + New mod/general function redirect_master, allowing for + site-level redirection. + + + New mod/general function travel_page which is a simple + virtual URL that will redirect to a provided URL. + + + New mod/general function ipsec_check which will allow for + site based IP access lists. + + + New mod/general function lower_uri which will take the URI + in t->vars and make it all lowercase for case insensitive + websites. + + + pthread_rwlock compatability interface now changed to be more + like the POSIX standard. rdwr calls are now not included unless + the pthread_rwlock interface is missing on the platform. + + + +- 2.0.12 + + + New tav_ vector TCL commands. + + + Fixed broken BSP subsystem. + + + Introduced new hsh.c void interface that will eventually + replace the old API. + + + if-modified-since and last-modified now work properly + with sendfile + + + mod/tcl now traps init script errors. + + + mod/tcl all aspects of TCL error trapping are now useful and + verbose, TCL script backtraces are provided. + + + dl.c no longer logs loaded shared library loads. + + + TCL now does the right thing in regards to TLS. + + + Unbroke TLS/Oracle. + + + tls now uses UUID for memory handle. + + + Created a thread to run the mmap cleanup every 60 seconds. This will + prevent the server from accumulating maps over time. + + + Fixed an overflow in the UUID handler which could cause a crash. + + + +- 2.0.11 + + + mod/beacon now adds memory information to tasF (Solaris) + + + mod/beacon now adds CPU metrics (Solaris) + + + Added w_err_eagain, w_err_estale, and w_err_epipe counters + in net.0 + + + +- 2.0.10 + + + Changed the http short request error to a warning. + + + mod/general's logging format is changed back to match + CDP's 1.1 by the inclusion of two placeholder values. + + + mod/general now creates access log files that always have + two digit values for day and year. + + + mod/general now appends the hostname of the machine on the end + of the access log. + + + Additional changes to support 64-bits. + + + Fixed broken dispatcher behavior which was causing the server + to pipeline. + + + httpFparse now URL decodes the path parameter before inserting + it into t->vars + + + +- 2.0.9 + + + Replaced dynamic memory handling in the TCL commands + + + I/O is now non-blocking + + + Added mod/beacon + + + Modifications for 64-bit + + + Added a statistics interface for use with the rrd + tool, and other applications. + + + New TCL commands: ta_urlencode, ta_urldecode + + + +- 2.0.8 + + + mod/general, created do_404 for generic 404 handling. find_index + will now 404 if the request was for a directory but no matching + index pages were found. + + + Added a new module, mod/image, which is essnetially libjpeg + with some TCL binder functions. + + + tclFinit now takes arg init= which specifies tcl loadfile + + + New TCL commands: ta_db_open, ta_db_select, ta_db_getrow, + ta_jpg_getsize + + + Removed broken and useless structure defenitions from tcl_pub.h + + + Restructured the TLS system to take dynamic cleanup handlers, + and to allocate the classes at runtime. + + + Added a select() timeout function for the reads, 5 seconds. + + + Removed the extra trailing space from utlFlocal_time(). + + + Introduced cdog watchdog program. + + + +- 2.0.7 + + + Log output now includes time. + + + Fixed a bug in commonlog that would cause the timezone offset + to appear as a random, corrupted string. + + + mod/general now exits at startup if it cannot load the + instance.cfg. + + + Hardened http parser. + + + Added new functions qryFlst_parse(), utlFurl_encode(), + utlFurl_decode(), dynFfree(), utlFlocal_time(), uuidFgenerate_str() + + + Added new TCL functions: tcl_http_var_set, tcl_http_res_set, + tcl_http_req_set, ta_pwd, ta_http_vars_get, ta_http_req_get, + ta_http_res_get. + + + Fixed a structure containment problem in mod/tcl, due to an + improper assignment with dyn command. Thanks eric. + + + Fixed a leak. The handler has to free the passed disTconn + structure. + + + Added dynFappend_print() + + + Moved back to an emphasis on shlibs, with RTLD_GLOBAL on + Linux and Solaris allowing x-calls between modules. + + + MMC system now logs %d/errno rather than %m + + + MMC system now logs the logFmsg() service rather than logging + errors to syslog. + + + t->vars:path is now cleaned of extra slashes before it's added + to the set. + + + Removed an extra space after the time from the mod/general + access log. + + + OpenBSD port is being dropped because their linker does not support + --no-whole-archive, which breaks the continuity link. + + + Re-Organized distribution, with bin, lib, and include directories. + + + Added a new function, dlFmap_funcs that can be called from the + module.cfg with a funcs= argument. This will map functions from + RTLD_DEFAULT, rather than a shared library. This is required to + call functions in the core build from the module.cfg + + + Moved to .a compilation format. On installation the end-user + will perform the final link step. This allows for linking + against arbitrary end-user libraries, as well as providing a + mechanism to allow the libraries to cross-call one another without + the performance penalties or hassles of going through dlsym. + + + mod/tcl is now included in the standard distribution. + + + send_file now returns the content-length. + + + mod/tcl is now functional for embedded pages. + + + Added proper functiond decl's to stat.h + + + Moved mod/tcl source in. + + + Added mod/oracle, and OCI based Oracle interface library. + + + +- 2.0.6 (v2.00 p6) + + + Changing version numbering to a more realistic style. + + + Modified build message. Continuity is now + "Continuity Enterprise Edition". Build message also now + reflects Production/Development and 320-bit/64-bit. + + + Modified the server variable on the return HTTP response + to include the version number rather than a hardcoded 2.00 + + + Generalized the dispatcher so that alternative handlers + can be registered. + + + +- v2.00 p5 + + + Added ability for modules to get transaction with + httpFthread_gettrans(void). This is implemented through TLS + and was required for modtcl. + + + Changed the req_line buffer in httpFparse to 1k. + + + Added netFwrite() as documented. + + + removed dietlibc options from configure + + + t->cli_ipv4_address is now guaranteed to be host order. This was + causing problems with the logs on little endian platforms. + + + utlFip_to_str was not formatting the IP address properly. + + + Number of threads and runq size are now tunable from module.cfg using + set_option. The parameters are "threads" and "runq_size". + + + New global configuration calls, get_option and set_option. + + + +- v2.00 p4 + + + continuity now supports the -a option, for binding to a specific IP + address. + + + The list code had two issues: one, it was losing entries on realloc + and it was over-freeing one entry. Well. realloc() with mtmalloc is still + broken. Here's the deal, at this point I think mtmalloc is just fucked + after you realloc() memory and it changes it out from under you. This is + too bad because mtmalloc is really fast. + + + httpFparse was not properly storing the HTTP request variables + in t->req_hdrs, problems such as spacing and cutting values at the ':' + + + mod/general now looks for group.siteid instead of siteid.group + + + Hard 404 page now sets the type as text/html + + + Fixed the return values from httpFparse, which was possible causing + bad requests to make it through to processing. + + + mod/general now includes find_index, which will for a configured list + of index pages for requests that are directories. + + + mod/general no longer tries to log the country code for the request. + The ccode is only present when mod/iplk is running, and mod/iplk is + proprietary to CyberDataProcessing. + + + Moved the WLOG call into the http handler from the http + cleanup code, because WLOG was being called for aborted + and broken connections. + + + On OpenBSD, thrFsleep() now locks the mutex before calling + pthread_cond_timeout. Apparently OBSd requires the mutex be + locked, or, it returns EINVAL. + + + accept() trapping eith EINTR will call intr_handler() on OpenBSD. This is + so that ctl+c will interrupt the running process properly. + + + Modified the way the fputs weirdness trap works in mod/general/log.c + + + +- v2.00 p3 + + + PHP4 no longer leaks. + + + Significantly improved the thread pooling performance. + + + removed cache miss message from utlFtime + + + Thread pooling is now the default. This is generally a good idea, + I suppose, but it's basically being required by PHP which can't + deal with threads that are destroyed. + + + dl.c will now try preprending _ to the function names if they are not + found. This helps on platforms like openbsd which insist on putting a + leading underscore in the fn names for shared libraries. + + + No longer trying to use sigignore at all. + + + find_pathinfo now sets the type to internal/directory for directories, + regardless of extension. + + + find_pathinfo will now 302 uri's for directories that are missing their + trailing / + + + Linux builds now sense mmap() properly. Before they were using a read() + loop as a fallback, causing horrible performance. + + + mod/general/log.c was expecting fputs() to be the num bytes written. + On Linux, this just seems to return 1 on success. #ifdef'd around the + return check. + + + +- v2.00 p2 + + + dl now honors type= setting for the service functions. The function + will only run if the type for the request is in the comma seperated list. + To run for all types, do not specify type. + + + pathinfo now returns a hard 404 error when the stat() fails. + + + trans now carries started, which indicates at which point the request + is at. Dispatch won't run the obj or service classes unless started + is 0. + + + Source now uses capi.h, the public API header file. Duplicate + defenitions removed from the other headers. + + + Added an -enable-diet target, which is broken, because + diet-libc SUCKS AND MUST BE DESTROYED + + + Inclusion of strings.h is now based on configure. strings.h + is discouraged by diet libc on Linux. + + + xfr.c no longer uses pwrite, because pwrite()ing a socket under + RH7 is not legal, and it was pointless anyways. + + + -c now works properly rather than opening "module.cfg" regardless. + +- v2.00 p1 diff --git a/mk4/continuity/Makefile.in b/mk4/continuity/Makefile.in new file mode 100644 index 0000000..faa0fab --- /dev/null +++ b/mk4/continuity/Makefile.in @@ -0,0 +1,33 @@ +# $Id: Makefile.in,v 1.11 2004/05/19 19:49:55 aleigh Exp $ + +world: pcre/Makefile + (cd pcre ; $(MAKE)) + (cd mecha ; $(MAKE)) + (cd cont ; $(MAKE)) + +clean: + (cd mecha ; $(MAKE) clean) + (cd cont ; $(MAKE) clean) + +realclean: clean + (cd pcre; $(MAKE) clean) + + +pcre/Makefile: + (cd pcre; ./configure); + +count: + (find . -name '*.[ch]' | xargs wc -l) + +dist: world + mkdir -p dist/bin + mkdir -p dist/lib + mkdir -p dist/include + cp bin/continuity bin/cdog dist/bin + cp bin/*-dist dist/bin + cp -r include/*.h dist/include + cp -r lib/*.a lib/*.so lib/env.mk lib/build.mk lib/*.xml dist/lib +depend: + (cd mecha ; $(MAKE) depend) + (cd cont ; $(MAKE) depend) + diff --git a/mk4/continuity/TODO b/mk4/continuity/TODO new file mode 100644 index 0000000..2d76aa7 --- /dev/null +++ b/mk4/continuity/TODO @@ -0,0 +1,3 @@ +$Header: /san01/cvs/ashpool/csrc/continuity/TODO,v 1.14 2004/05/21 20:53:44 aleigh Exp $ + +Excessively long URLs do not generate a protocol error. diff --git a/mk4/continuity/bin/.cvsignore b/mk4/continuity/bin/.cvsignore new file mode 100644 index 0000000..38dc3a6 --- /dev/null +++ b/mk4/continuity/bin/.cvsignore @@ -0,0 +1,2 @@ +continuity +cdog diff --git a/mk4/continuity/bin/CVS/Entries b/mk4/continuity/bin/CVS/Entries new file mode 100644 index 0000000..b8c0cc2 --- /dev/null +++ b/mk4/continuity/bin/CVS/Entries @@ -0,0 +1,13 @@ +/.cvsignore/1.1/Thu Mar 11 01:11:48 2004//Tmk4_mod6_rc2 +/base.xml/1.4/Tue Jun 22 15:54:36 2004//Tmk4_mod6_rc2 +/beacon.xml/1.3/Wed May 12 14:37:52 2004//Tmk4_mod6_rc2 +/config.xml/1.27/Sun May 16 20:29:59 2004//Tmk4_mod6_rc2 +/config.xml-dist/1.6/Wed May 12 15:20:48 2004//Tmk4_mod6_rc2 +/dotnet.xml/1.3/Tue Jun 22 15:54:36 2004//Tmk4_mod6_rc2 +/dynamo.xml/1.6/Tue Feb 24 04:38:42 2004//Tmk4_mod6_rc2 +/harmony.xml/1.5/Wed May 12 14:29:44 2004//Tmk4_mod6_rc2 +/phpdev.xml/1.5/Tue Feb 24 04:38:42 2004//Tmk4_mod6_rc2 +/radius.xml/1.4/Fri May 14 15:21:24 2004//Tmk4_mod6_rc2 +/ssl.xml/1.3/Sun May 16 20:29:59 2004//Tmk4_mod6_rc2 +/winkfep.xml/1.10/Tue Jun 22 15:54:36 2004//Tmk4_mod6_rc2 +D diff --git a/mk4/continuity/bin/CVS/Repository b/mk4/continuity/bin/CVS/Repository new file mode 100644 index 0000000..01b86c5 --- /dev/null +++ b/mk4/continuity/bin/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/continuity/bin diff --git a/mk4/continuity/bin/CVS/Root b/mk4/continuity/bin/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/continuity/bin/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/continuity/bin/CVS/Tag b/mk4/continuity/bin/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/continuity/bin/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/example/base.xml b/mk4/continuity/bin/base.xml similarity index 100% rename from example/base.xml rename to mk4/continuity/bin/base.xml diff --git a/example/beacon.xml b/mk4/continuity/bin/beacon.xml similarity index 100% rename from example/beacon.xml rename to mk4/continuity/bin/beacon.xml diff --git a/example/config.xml b/mk4/continuity/bin/config.xml similarity index 100% rename from example/config.xml rename to mk4/continuity/bin/config.xml diff --git a/example/config.xml-dist b/mk4/continuity/bin/config.xml-dist similarity index 100% rename from example/config.xml-dist rename to mk4/continuity/bin/config.xml-dist diff --git a/example/dotnet.xml b/mk4/continuity/bin/dotnet.xml similarity index 100% rename from example/dotnet.xml rename to mk4/continuity/bin/dotnet.xml diff --git a/example/dynamo.xml b/mk4/continuity/bin/dynamo.xml similarity index 100% rename from example/dynamo.xml rename to mk4/continuity/bin/dynamo.xml diff --git a/example/harmony.xml b/mk4/continuity/bin/harmony.xml similarity index 100% rename from example/harmony.xml rename to mk4/continuity/bin/harmony.xml diff --git a/example/phpdev.xml b/mk4/continuity/bin/phpdev.xml similarity index 100% rename from example/phpdev.xml rename to mk4/continuity/bin/phpdev.xml diff --git a/example/radius.xml b/mk4/continuity/bin/radius.xml similarity index 100% rename from example/radius.xml rename to mk4/continuity/bin/radius.xml diff --git a/example/ssl.xml b/mk4/continuity/bin/ssl.xml similarity index 100% rename from example/ssl.xml rename to mk4/continuity/bin/ssl.xml diff --git a/example/winkfep.xml b/mk4/continuity/bin/winkfep.xml similarity index 100% rename from example/winkfep.xml rename to mk4/continuity/bin/winkfep.xml diff --git a/mk4/continuity/config.guess b/mk4/continuity/config.guess new file mode 100644 index 0000000..81688c4 --- /dev/null +++ b/mk4/continuity/config.guess @@ -0,0 +1,1284 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000 +# Free Software Foundation, Inc. + +version='2000-07-27' + +# 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. + +# Written by Per Bothner . +# Please send patches to . +# +# 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 system type (host/target name). +# +# Only a few systems have been added to this list; please add others +# (but try to keep the structure clean). +# + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of this system. + +Operation modes: + -h, --help print this help, then exit + -V, --version print version number, then exit" + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case "$1" in + --version | --vers* | -V ) + echo "$version" ; exit 0 ;; + --help | --h* | -h ) + echo "$usage"; exit 0 ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + exec >&2 + echo "$me: invalid option $1" + echo "$help" + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +# Use $HOST_CC if defined. $CC may point to a cross-compiler +if test x"$CC_FOR_BUILD" = x; then + if test x"$HOST_CC" != x; then + CC_FOR_BUILD="$HOST_CC" + else + if test x"$CC" != x; then + CC_FOR_BUILD="$CC" + else + CC_FOR_BUILD=cc + fi + fi +fi + + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 8/24/94.) +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 + +dummy=dummy-$$ +trap 'rm -f $dummy.c $dummy.o $dummy; exit 1' 1 2 15 + +# 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. + # Determine the machine/vendor (is the vendor relevant). + case "${UNAME_MACHINE}" in + amiga) machine=m68k-unknown ;; + arm32) machine=arm-unknown ;; + atari*) machine=m68k-atari ;; + sun3*) machine=m68k-sun ;; + mac68k) machine=m68k-apple ;; + macppc) machine=powerpc-apple ;; + hp3[0-9][05]) machine=m68k-hp ;; + ibmrt|romp-ibm) machine=romp-ibm ;; + *) machine=${UNAME_MACHINE}-unknown ;; + esac + # The Operating System including object format. + 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 + # The OS release + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + # 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 ;; + alpha:OSF1:*:*) + if test $UNAME_RELEASE = "V4.0"; then + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + fi + # 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. + cat <$dummy.s + .data +\$Lformat: + .byte 37,100,45,37,120,10,0 # "%d-%x\n" + + .text + .globl main + .align 4 + .ent main +main: + .frame \$30,16,\$26,0 + ldgp \$29,0(\$27) + .prologue 1 + .long 0x47e03d80 # implver \$0 + lda \$2,-1 + .long 0x47e20c21 # amask \$2,\$1 + lda \$16,\$Lformat + mov \$0,\$17 + not \$1,\$18 + jsr \$26,printf + ldgp \$29,0(\$26) + mov 0,\$16 + jsr \$26,exit + .end main +EOF + $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null + if test "$?" = 0 ; then + case `./$dummy` in + 0-0) + UNAME_MACHINE="alpha" + ;; + 1-0) + UNAME_MACHINE="alphaev5" + ;; + 1-1) + UNAME_MACHINE="alphaev56" + ;; + 1-101) + UNAME_MACHINE="alphapca56" + ;; + 2-303) + UNAME_MACHINE="alphaev6" + ;; + 2-307) + UNAME_MACHINE="alphaev67" + ;; + esac + fi + rm -f $dummy.s $dummy + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | 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;; + amiga:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit 0 ;; + arc64:OpenBSD:*:*) + echo mips64el-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + arc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + hkmips:OpenBSD:*:*) + echo mips-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + pmax:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sgi:OpenBSD:*:*) + echo mips-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + wgrisc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit 0 ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit 0;; + SR2?01: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 ;; + 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=`(head -1 /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 ;; + atari*:OpenBSD:*:*) + echo m68k-unknown-openbsd${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 ;; + sun3*:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mac68k:OpenBSD:*:*) + echo m68k-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 ;; + 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) + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* 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 $dummy.c -o $dummy \ + && ./$dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \ + && rm $dummy.c $dummy && exit 0 + rm -f $dummy.c $dummy + echo mips-mips-riscos${UNAME_RELEASE} + 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 ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm $dummy.c $dummy && exit 0 + rm -f $dummy.c $dummy + 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:*:4) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | head -1 | awk '{ print $1 }'` + if /usr/sbin/lsattr -EHl ${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=4.${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:*:*) + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + 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 $dummy.c -o $dummy 2>/dev/null ) && HP_ARCH=`./$dummy` + rm -f $dummy.c $dummy + esac + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit 0 ;; + 3050*:HI-UX:*:*) + sed 's/^ //' << EOF >$dummy.c + #include + 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 $dummy.c -o $dummy && ./$dummy && rm $dummy.c $dummy && exit 0 + rm -f $dummy.c $dummy + 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:*:*) + 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 ;; + hppa*:OpenBSD:*:*) + echo hppa-unknown-openbsd + 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*X-MP:*:*:*) + echo xmp-cray-unicos + exit 0 ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} + 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/ + exit 0 ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*T3E:*:*:*) + echo alpha-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY-2:*:*:*) + echo cray2-cray-unicos + exit 0 ;; + F300:UNIX_System_V:*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "f300-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit 0 ;; + F301:UNIX_System_V:*:*) + echo f301-fujitsu-uxpv`echo $UNAME_RELEASE | sed 's/ .*//'` + exit 0 ;; + hp300:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + 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 ;; + *:OpenBSD:*:*) + echo ${UNAME_MACHINE}-unknown-openbsd`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*: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 i386-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:*:*) + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit 0 ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit 0 ;; + *: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. + ld_help_string=`cd /; ld --help 2>&1` + ld_supported_emulations=`echo $ld_help_string \ + | sed -ne '/supported emulations:/!d + s/[ ][ ]*/ /g + s/.*supported emulations: *// + s/ .*// + p'` + case "$ld_supported_emulations" in + *ia64) + echo "${UNAME_MACHINE}-unknown-linux" + exit 0 + ;; + i?86linux) + echo "${UNAME_MACHINE}-pc-linux-gnuaout" + exit 0 + ;; + elf_i?86) + TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" + ;; + i?86coff) + echo "${UNAME_MACHINE}-pc-linux-gnucoff" + exit 0 + ;; + sparclinux) + echo "${UNAME_MACHINE}-unknown-linux-gnuaout" + exit 0 + ;; + armlinux) + echo "${UNAME_MACHINE}-unknown-linux-gnuaout" + exit 0 + ;; + elf32arm*) + echo "${UNAME_MACHINE}-unknown-linux-gnuoldld" + exit 0 + ;; + armelf_linux*) + echo "${UNAME_MACHINE}-unknown-linux-gnu" + exit 0 + ;; + m68klinux) + echo "${UNAME_MACHINE}-unknown-linux-gnuaout" + exit 0 + ;; + elf32ppc | elf32ppclinux) + # Determine Lib Version + cat >$dummy.c < +#if defined(__GLIBC__) +extern char __libc_version[]; +extern char __libc_release[]; +#endif +main(argc, argv) + int argc; + char *argv[]; +{ +#if defined(__GLIBC__) + printf("%s %s\n", __libc_version, __libc_release); +#else + printf("unkown\n"); +#endif + return 0; +} +EOF + LIBC="" + $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null + if test "$?" = 0 ; then + ./$dummy | grep 1\.99 > /dev/null + if test "$?" = 0 ; then + LIBC="libc1" + fi + fi + rm -f $dummy.c $dummy + echo powerpc-unknown-linux-gnu${LIBC} + exit 0 + ;; + shelf_linux) + echo "${UNAME_MACHINE}-unknown-linux-gnu" + exit 0 + ;; + esac + + if test "${UNAME_MACHINE}" = "alpha" ; then + cat <$dummy.s + .data + \$Lformat: + .byte 37,100,45,37,120,10,0 # "%d-%x\n" + + .text + .globl main + .align 4 + .ent main + main: + .frame \$30,16,\$26,0 + ldgp \$29,0(\$27) + .prologue 1 + .long 0x47e03d80 # implver \$0 + lda \$2,-1 + .long 0x47e20c21 # amask \$2,\$1 + lda \$16,\$Lformat + mov \$0,\$17 + not \$1,\$18 + jsr \$26,printf + ldgp \$29,0(\$26) + mov 0,\$16 + jsr \$26,exit + .end main +EOF + LIBC="" + $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null + if test "$?" = 0 ; then + case `./$dummy` in + 0-0) + UNAME_MACHINE="alpha" + ;; + 1-0) + UNAME_MACHINE="alphaev5" + ;; + 1-1) + UNAME_MACHINE="alphaev56" + ;; + 1-101) + UNAME_MACHINE="alphapca56" + ;; + 2-303) + UNAME_MACHINE="alphaev6" + ;; + 2-307) + UNAME_MACHINE="alphaev67" + ;; + esac + + objdump --private-headers $dummy | \ + grep ld.so.1 > /dev/null + if test "$?" = 0 ; then + LIBC="libc1" + fi + fi + rm -f $dummy.s $dummy + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} ; exit 0 + elif test "${UNAME_MACHINE}" = "mips" ; then + cat >$dummy.c < /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif +#ifdef __MIPSEB__ + printf ("%s-unknown-linux-gnu\n", argv[1]); +#endif +#ifdef __MIPSEL__ + printf ("%sel-unknown-linux-gnu\n", argv[1]); +#endif + return 0; +} +EOF + $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0 + rm -f $dummy.c $dummy + elif test "${UNAME_MACHINE}" = "s390"; then + echo s390-ibm-linux && exit 0 + else + # Either a pre-BFD a.out linker (linux-gnuoldld) + # or one that does not give us useful --help. + # GCC wants to distinguish between linux-gnuoldld and linux-gnuaout. + # If ld does not provide *any* "supported emulations:" + # that means it is gnuoldld. + echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations:" + test $? != 0 && echo "${UNAME_MACHINE}-pc-linux-gnuoldld" && exit 0 + + case "${UNAME_MACHINE}" in + i?86) + VENDOR=pc; + ;; + *) + VENDOR=unknown; + ;; + esac + # Determine whether the default compiler is a.out or elf + cat >$dummy.c < +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif +#ifdef __ELF__ +# ifdef __GLIBC__ +# if __GLIBC__ >= 2 + printf ("%s-${VENDOR}-linux-gnu\n", argv[1]); +# else + printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]); +# endif +# else + printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]); +# endif +#else + printf ("%s-${VENDOR}-linux-gnuaout\n", argv[1]); +#endif + return 0; +} +EOF + $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0 + rm -f $dummy.c $dummy + test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0 + fi ;; +# 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. + i?86:DYNIX/ptx:4*:*) + 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:*: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:7*) + # Fixed at (any) Pentium or better + UNAME_MACHINE=i586 + if [ ${UNAME_SYSTEM} = "UnixWare" ] ; then + echo ${UNAME_MACHINE}-sco-sysv${UNAME_RELEASE}uw${UNAME_VERSION} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE} + fi + exit 0 ;; + i?86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')` + (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|egrep '^Machine.*Pent ?II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|egrep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit 0 ;; + i?86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + 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 ;; + M68*:*:R3V[567]*:*) + test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; + 3[34]??:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*: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.*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit 0 ;; + i?86:LynxOS:2.*:* | i?86:LynxOS:3.[01]*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + rs6000:LynxOS:2.*:* | PowerPC:LynxOS:2.*:*) + echo rs6000-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:CPunix:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit 0 ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # 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 ;; + 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 ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit 0 ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit 0 ;; + *:Darwin:*:*) + echo `uname -p`-apple-darwin${UNAME_RELEASE} + exit 0 ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + if test "${UNAME_MACHINE}" = "x86pc"; then + UNAME_MACHINE=pc + fi + echo `uname -p`-${UNAME_MACHINE}-nto-qnx + exit 0 ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit 0 ;; + NSR-W:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + 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 ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +cat >$dummy.c < +# include +#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 + 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) + printf ("vax-dec-bsd\n"); exit (0); +#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 $dummy.c -o $dummy 2>/dev/null && ./$dummy && rm $dummy.c $dummy && exit 0 +rm -f $dummy.c $dummy + +# 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 < in order to provide the needed +information to handle your system. + +config.guess version = $version + +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: "version='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/mk4/continuity/config.sub b/mk4/continuity/config.sub new file mode 100644 index 0000000..945a7f4 --- /dev/null +++ b/mk4/continuity/config.sub @@ -0,0 +1,1324 @@ +#! /bin/sh +# Configuration validation subroutine script, version 1.1. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000 +# Free Software Foundation, Inc. + +version='2000-08-07' + +# 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 . +# +# 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 + -V, --version print version number, then exit" + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case "$1" in + --version | --vers* | -V ) + echo "$version" ; exit 0 ;; + --help | --h* | -h ) + echo "$usage"; exit 0 ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + exec >&2 + echo "$me: invalid option $1" + echo "$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*) + 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) + os= + basic_machine=$1 + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + 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. + tahoe | i860 | ia64 | m32r | m68k | m68000 | m88k | ns32k | arc | arm \ + | arme[lb] | armv* | pyramid | mn10200 | mn10300 | tron | a29k \ + | 580 | i960 | h8300 \ + | x86 | ppcbe | mipsbe | mipsle | shbe | shle | armbe | armle \ + | hppa | hppa1.0 | hppa1.1 | hppa2.0 | hppa2.0w | hppa2.0n \ + | hppa64 \ + | alpha | alphaev[4-8] | alphaev56 | alphapca5[67] \ + | alphaev6[78] \ + | we32k | ns16k | clipper | i370 | sh | sh[34] \ + | powerpc | powerpcle \ + | 1750a | dsp16xx | pdp11 | mips16 | mips64 | mipsel | mips64el \ + | mips64orion | mips64orionel | mipstx39 | mipstx39el \ + | mips64vr4300 | mips64vr4300el | mips64vr4100 | mips64vr4100el \ + | mips64vr5000 | miprs64vr5000el | mcore \ + | sparc | sparclet | sparclite | sparc64 | sparcv9 | v850 | c4x \ + | thumb | d10v | d30v | fr30 | avr) + 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 | z8k | v70 | h8500 | w65 | pj | pjl) + ;; + + # 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[234567]86) + 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. + # FIXME: clean up the formatting here. + vax-* | tahoe-* | i[234567]86-* | i860-* | ia64-* | m32r-* | m68k-* | m68000-* \ + | m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | arm-* | c[123]* \ + | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \ + | power-* | none-* | 580-* | cray2-* | h8300-* | h8500-* | i960-* \ + | xmp-* | ymp-* \ + | x86-* | ppcbe-* | mipsbe-* | mipsle-* | shbe-* | shle-* | armbe-* | armle-* \ + | hppa-* | hppa1.0-* | hppa1.1-* | hppa2.0-* | hppa2.0w-* \ + | hppa2.0n-* | hppa64-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphapca5[67]-* \ + | alphaev6[78]-* \ + | we32k-* | cydra-* | ns16k-* | pn-* | np1-* | xps100-* \ + | clipper-* | orion-* \ + | sparclite-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \ + | sparc64-* | sparcv9-* | sparc86x-* | mips16-* | mips64-* | mipsel-* \ + | mips64el-* | mips64orion-* | mips64orionel-* \ + | mips64vr4100-* | mips64vr4100el-* | mips64vr4300-* | mips64vr4300el-* \ + | mipstx39-* | mipstx39el-* | mcore-* \ + | f301-* | armv*-* | s390-* | sv1-* | t3e-* \ + | m88110-* | m680[01234]0-* | m683?2-* | m68360-* | z8k-* | d10v-* \ + | thumb-* | v850-* | d30v-* | tic30-* | c30-* | fr30-* \ + | bs2000-* | tic54x-* | c54x-*) + ;; + # 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 + ;; + 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 + ;; + 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 + ;; + 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 | ymp) + basic_machine=ymp-cray + os=-unicos + ;; + cray2) + basic_machine=cray2-cray + os=-unicos + ;; + [ctj]90-cray) + basic_machine=c90-cray + os=-unicos + ;; + crds | unos) + basic_machine=m68k-crds + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + 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 + ;; + 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[34567]86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i[34567]86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i[34567]86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i[34567]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 + ;; + i386-go32 | go32) + basic_machine=i386-unknown + os=-go32 + ;; + i386-mingw32 | mingw32) + basic_machine=i386-unknown + os=-mingw32 + ;; + 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 + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mipsel*-linux*) + basic_machine=mipsel-unknown + os=-linux-gnu + ;; + mips*-linux*) + basic_machine=mips-unknown + os=-linux-gnu + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + mmix*) + basic_machine=mmix-knuth + os=-mmixware + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + msdos) + basic_machine=i386-unknown + 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 + ;; + np1) + basic_machine=np1-gould + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + 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 | nexen) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon) + basic_machine=i686-pc + ;; + pentiumii | pentium2) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexen-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=rs6000-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/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sparclite-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=t3e-cray + os=-unicos + ;; + tic54x | c54x*) + basic_machine=tic54x-unknown + os=-coff + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + 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 + ;; + xmp) + basic_machine=xmp-cray + os=-unicos + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + 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 + ;; + mips) + if [ x$os = x-linux-gnu ]; then + basic_machine=mips-unknown + else + basic_machine=mips-mips + fi + ;; + romp) + basic_machine=romp-ibm + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh3 | sh4) + base_machine=sh-unknown + ;; + sparc | sparcv9) + 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 + ;; + c4x*) + basic_machine=c4x-none + os=-coff + ;; + *) + 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. + -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* | -netbsd* | -openbsd* | -freebsd* | -riscix* \ + | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i[34567]86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto*) + os=-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*) + 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 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -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) + os=-mint + ;; + -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 + ;; + 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 + ;; + *-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 + ;; + *-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 + ;; + f301-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 + ;; + -ptx*) + vendor=sequent + ;; + -vxsim* | -vxworks*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -*MiNT) + vendor=atari + ;; + 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: "version='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/mk4/continuity/configure.in b/mk4/continuity/configure.in new file mode 100644 index 0000000..1318d82 --- /dev/null +++ b/mk4/continuity/configure.in @@ -0,0 +1,254 @@ +walldnl Process this file with autoconf to produce a configure script. +AC_INIT(mecha/lst.c) + +AC_CANONICAL_SYSTEM +AC_PROG_CC +AC_SUBST(CC) +AC_PROG_CPP + +AC_ARG_ENABLE(64bit,dnl +[ --enable-64bit Attempt to build a 64bit target (sparc)], +do64=yes) + +AC_ARG_ENABLE(production,dnl +[ --enable-production Perform a production build, full opts, no debugging], +doprod=yes) + +AC_ARG_ENABLE(prof,dnl +[ --enable-prof Enable profiling], +doprof=yes) + +AC_ARG_ENABLE(gprof,dnl +[ --enable-gprof Enable g-profiling], +dogprof=yes) + +AC_ARG_ENABLE(oneshot,dnl +[ --enable-oneshot Enable one-shot build], +dooneshot=yes) + +echo "target_cpu: $target_cpu" +echo "target_os: $target_os" + +AC_CHECK_LIB(c_r,pthread_create) +AC_CHECK_LIB(resolv, inet_aton) +AC_CHECK_LIB(m,floor) +AC_CHECK_LIB(nsl, gethostname) +AC_CHECK_LIB(kstat,kstat_open) +AC_CHECK_LIB(socket, connect) +AC_CHECK_LIB(aio,aiowrite) +AC_CHECK_LIB(thread, pthread_create) +AC_CHECK_LIB(pthread, pthread_create) +AC_CHECK_LIB(dl,dlopen) +AC_CHECK_LIB(LiS,putpmsg) +AC_CHECK_LIB(mtmalloc,malloc) +AC_CHECK_LIB(c,prctl) + +AC_CHECK_PROG(MAKEDEPEND,makedepend,"yes","no") +if test "$MAKEDEPEND" = "no" ; then + echo "No makedepend found." + MAKEDEPEND="echo" +else + echo "makedepend found." + MAKEDEPEND="makedepend" +fi + +# Each platform needs to set a number of variables for the make. +# +# BUILD_CMD - The command that will be used to build executables. ld or cc, depending. +# PRE_BUILD - Any arguments that need to be called before the object list for BUILD_CMD. +# POST_BUILD - Any arguments that need to be called after the object list for BUILD_CMD. +# OPT_CFLAGS - Optional cflag lines, such as -g, etc. +# LDSHARED - The command to build a shared library, eg, gcc -shared, ld -G, etc. + +echo $target_os + +case "$target_os" in +#### +# OSX +#### +darwin*) + CC=cc + if test "$doprod" = "yes" ; then + echo "Setting GCC production flags." ; OPT_CFLAGS="$OPT_CFLAGS -O2 -DNDEBUG -DPRODUCTION -DDARWIN -pedantic -D_POSIX_C_SOURCE=199506L -std=c99" + else + echo "Setting GCC Development flags." ; OPT_CFLAGS="$OPT_CFLAGS -g -DDARWIN -pedantic -D_POSIX_C_SOURCE=199506L -std=c99" + fi + + LD_FLAGS="-rdynamic" + LDSHARED="cc -bundle -flat_namespace -undefined suppress -Wl,-all_load" + AR_CMD="ar cr" + BUILD_CMD=cc + PRE_CMD="-bundle -flat_namespace -undefined-suppress" + DEPFLAGS="-DDARWIN" +;; + +#### +# SUN SOLARIS +#### +solaris*) +if test "${CC}" != "gcc" ; then + # CC + case "$target_cpu" in + sparc) + if test "$do64" = "yes" ; then + echo "Setting 64-bit Ultra architecture flags." ; ARCH_CFLAGS="-xarch=v9a -DTA_64BIT" + BUILD_CMD="/usr/ccs/bin/ld" + PRE_BUILD="-zallextract /opt/SUNWspro/prod/lib/v9/crti.o /opt/SUNWspro/prod/lib/v9/crt1.o /opt/SUNWspro/prod/lib/v9/values-xa.o" + POST_BUILD="-Y "P,/opt/SUNWspro/prod/lib/v9a:/opt/SUNWspro/prod/lib/v9:/usr/ccs/lib/sparcv9:/usr/lib/sparcv9" -Qy -lc /opt/SUNWspro/prod/lib/v9/crtn.o" + MODTCL_TCLOPT="--enable-64bit-vis" + else + echo "Setting 32-bit Ultra architecture flags." ; ARCH_CFLAGS="-xarch=v8plusa" + PRE_BUILD="-zallextract /opt/SUNWspro/prod/lib/crti.o /opt/SUNWspro/prod/lib/crt1.o /opt/SUNWspro/prod/lib/values-xa.o" + POST_BUILD="-Y P,/opt/SUNWspro/prod/lib:/usr/ccs/lib:/usr/lib -Qy -lc /opt/SUNWspro/prod/lib/crtn.o" + BUILD_CMD=ld + fi + + if test "$doprod" = "yes" ; then + echo "Setting SUNWspro production flags." ; OPT_CFLAGS="-xtime -xO5 -xprefetch -DNDEBUG -DPRODUCTION -DSOLARIS -xc99=%all" + else + echo "Setting SUNWspro debug flags." ; OPT_CFLAGS="-xtime -g -DSOLARIS -xc99=%all" + fi + + AR_CMD="ar crs" + ;; + esac +else + # GCC + if test "$doprod" = "yes" ; then + echo "Setting GCC production flags." ; OPT_CFLAGS="-O2 -DSOLARIS -DNDEBUG -DPRODUCTION -Wall -std=c99 -D__STDC__=0 -D__EXTENSIONS__" + else + echo "Setting GCC Development flags." ; OPT_CFLAGS="-g -DSOLARIS -Wall -std=c99 -D__STDC__=0 -D__EXTENSIONS__" + fi + AR_CMD="ar crs" +# LD_FLAGS="-rdynamic" +fi + +DEPFLAGS="-DSOLARIS" + +if test "$doprof" = "yes" ; then + OPT_CFLAGS="$OPT_CFLAGS -p" +fi + +if test "$dogprof" = "yes" ; then + OPT_CFLAGS="$OPT_CFLAGS -xpg" +fi + +LDSHARED="ld -G" +;; + + +#### +# LINUX +#### +linux*) + if test "$doprod" = "yes" ; then + echo "Setting GCC production flags." ; OPT_CFLAGS="-O2 -W -Wall -Wimplicit -Wunused -Wchar-subscripts -Wshadow -Wwrite-strings -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes -Wno-long-long -pedantic -DNDEBUG -DPRODUCTION -DLINUX -D_XOPEN_SOURCE=500 -D_POSIX_C_SOURCE=199506L -DLIS -rdynamic -pedantic -std=c99" + else +echo "Setting GCC Development flags." ; OPT_CFLAGS="-g -W -Wall -Wimplicit -Wunused -Wchar-subscripts -Wshadow -Wwrite-strings -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes -Wno-long-long -pedantic -DLINUX -D_XOPEN_SOURCE=500 -D_POSIX_C_SOURCE=199506L -DLIS -rdynamic -std=c99" + fi + LDSHARED="gcc -shared" + BUILD_CMD="gcc" + LD_FLAGS="-rdynamic" + PRE_BUILD="-Wl,--whole-archive" + POST_BUILD="-Wl,--no-whole-archive" + AR_CMD="ar crs" + DEPFLAGS="-DLINUX -D_XOPEN_SOURCE=500 -D_POSIX_C_SOURCE=199506L -DLIS" +;; + +#### +# EVERYTHING ELSE +#### +*) + if test "$doprod" = "yes" ; then + echo "Setting GCC production flags." ; OPT_CFLAGS="-O2 -Wall -DNDEBUG -DPRODUCTION" + else + echo "Setting GCC Development flags." ; OPT_CFLAGS="-g -Wall" + fi + LDSHARED="ld -G" + AR_CMD="ar crs" + DEPFLAGS="" +;; +esac + +if test "$dooneshot" = "yes" ; then + echo "Configuring for One-Shot Build" + BUILD_CFLAGS="-DONESHOT" + BUILDMODE="oneshot" +else + echo "Configuring for Multi-Shot Build" + BUILD_CFLAGS="-DMULTISHOT" + BUILDMODE="multishot" +fi + +# Globals +RM="rm -rf" + +AC_SUBST(BUILDMODE) +AC_SUBST(BUILD_CFLAGS) +AC_SUBST(AR_CMD) +AC_SUBST(ARCH_CFLAGS) +AC_SUBST(OPT_CFLAGS) +AC_SUBST(LDSHARED) +AC_SUBST(LD_FLAGS) +AC_SUBST(CC) +AC_SUBST(BUILD_CMD) +AC_SUBST(PRE_BUILD) +AC_SUBST(POST_BUILD) +AC_SUBST(RM) +AC_SUBST(MODTCL_TCLOPT) +AC_SUBST(PWD) +AC_SUBST(DEPFLAGS) +AC_SUBST(MAKEDEPEND) + +dnl Checks for header files. +AC_HEADER_DIRENT +AC_HEADER_STDC +AC_CHECK_HEADERS(stropts.h libintl.h sys/dlpi.h kstat.h sys/lock.h stdint.h strings.h string.h malloc.h libgen.h) + +dnl Checks for typedefs, structures, and compiler characteristics. +#AC_C_CONST +#AC_TYPE_SIZE_T +#AC_HEADER_TIME +#AC_STRUCT_TM + +dnl Checks for library functions. +AC_TYPE_SIGNAL +AC_FUNC_VPRINTF +AC_CHECK_FUNCS(mmap rand_r prctl pthread_rwlock_init getloadavg on_exit) + + + dnl **************************** + dnl *** Checks for socklen_t *** + dnl **************************** + + AC_MSG_CHECKING([for socklen_t]) + ac_cv_socklen_t="" + AC_TRY_COMPILE([ +#include +#include + ],[ +socklen_t a=0; +getsockname(0,(struct sockaddr*)0, &a); + ], + ac_cv_socklen_t="socklen_t", + AC_TRY_COMPILE([ +#include +#include + ],[ +int a=0; +getsockname(0,(struct sockaddr*)0, &a); + ], + ac_cv_socklen_t="int", + ac_cv_socklen_t="size_t" + ) + ) + + AC_MSG_RESULT($ac_cv_socklen_t) + if test "$ac_cv_socklen_t" != "socklen_t"; then + AC_DEFINE_UNQUOTED(socklen_t, $ac_cv_socklen_t, + [Define the real type of socklen_t]) + fi + +AC_CONFIG_HEADER(include/config.h) + +AC_OUTPUT(Makefile mecha/Makefile cont/Makefile lib/env.mk) diff --git a/mk4/continuity/cont/.cvsignore b/mk4/continuity/cont/.cvsignore new file mode 100644 index 0000000..f3c7a7c --- /dev/null +++ b/mk4/continuity/cont/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/mk4/continuity/cont/CVS/Entries b/mk4/continuity/cont/CVS/Entries new file mode 100644 index 0000000..88b79ef --- /dev/null +++ b/mk4/continuity/cont/CVS/Entries @@ -0,0 +1,10 @@ +/.cvsignore/1.1/Thu Mar 11 01:11:48 2004//Tmk4_mod6_rc2 +/Makefile.in/1.23/Mon May 3 14:55:00 2004//Tmk4_mod6_rc2 +/cdog.c/1.6/Tue Mar 30 14:37:43 2004//Tmk4_mod6_rc2 +/continuity.c/1.42/Tue May 11 02:53:17 2004//Tmk4_mod6_rc2 +/dis.c/1.13/Wed Apr 21 21:47:03 2004//Tmk4_mod6_rc2 +/dl.c/1.31/Fri May 14 15:12:34 2004//Tmk4_mod6_rc2 +/mmc.c/1.6/Thu Mar 18 15:04:15 2004//Tmk4_mod6_rc2 +/tas.c/1.7/Fri May 14 06:20:32 2004//Tmk4_mod6_rc2 +/xfr.c/1.11/Thu Mar 18 15:04:15 2004//Tmk4_mod6_rc2 +D diff --git a/mk4/continuity/cont/CVS/Repository b/mk4/continuity/cont/CVS/Repository new file mode 100644 index 0000000..07b567e --- /dev/null +++ b/mk4/continuity/cont/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/continuity/cont diff --git a/mk4/continuity/cont/CVS/Root b/mk4/continuity/cont/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/continuity/cont/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/continuity/cont/CVS/Tag b/mk4/continuity/cont/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/continuity/cont/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/continuity/cont/Makefile.in b/mk4/continuity/cont/Makefile.in new file mode 100644 index 0000000..7db23c3 --- /dev/null +++ b/mk4/continuity/cont/Makefile.in @@ -0,0 +1,60 @@ +# $Header: /san01/cvs/ashpool/csrc/continuity/cont/Makefile.in,v 1.23 2004/05/03 14:55:00 aleigh Exp $ + +SRCS=tas.c xfr.c mmc.c dl.c dis.c continuity.c +OBJS=tas.o xfr.o mmc.o dl.o dis.o continuity.o + +MECHA_OBJS=../mecha/ast.o ../mecha/b64.o ../mecha/bsp.o ../mecha/bus.o ../mecha/crc.o ../mecha/dyn.o \ +../mecha/fle.o ../mecha/hsh.o ../mecha/log.o ../mecha/lst.o \ +../mecha/rnd.o ../mecha/str.o ../mecha/thr.o ../mecha/tls.o ../mecha/uid.o ../mecha/utl.o \ +../mecha/lst_void.o ../mecha/qry.o ../mecha/xml.o ../mecha/mem.o ../mecha/exp.o ../mecha/net.o ../mecha/pat.o \ +../mecha/dic.o ../mecha/sys.o ../mecha/cv.o ../pcre/pcreposix.o ../pcre/pcre.o ../pcre/get.o + +MECHA_SRCS=../mecha/ast.c ../mecha/b64.c ../mecha/bsp.c ../mecha/bus.c ../mecha/crc.c ../mecha/dyn.c \ +../mecha/fle.c ../mecha/hsh.c ../mecha/log.c ../mecha/lst.c \ +../mecha/rnd.c ../mecha/str.c ../mecha/thr.c ../mecha/tls.c ../mecha/uid.c ../mecha/utl.c \ +../mecha/lst_void.c ../mecha/qry.c ../mecha/xml.c ../mecha/mem.c ../mecha/exp.c \ +../mecha/net.c ../mecha/pat.c ../mecha/dic.c ../mecha/sys.c ../mecha/cv.c + +CFLAGS=-I../include @ARCH_CFLAGS@ @OPT_CFLAGS@ -D_REENTRANT -DTHR_POOL @BUILD_CFLAGS@ +LD_SHARECMD= @LDSHARED@ +CC=@CC@ +AR_CMD=@AR_CMD@ +BUILDMODE=@BUILDMODE@ +MAKEDEPEND=@MAKEDEPEND@ + +world: build.h $(BUILDMODE) ../bin/cdog + $(RM) build.h + +multishot: $(OBJS) $(MECHA_OBJS) + $(CC) $(CFLAGS) -o ../bin/continuity $(OBJS) $(MECHA_OBJS) @LDFLAGS@ @LIBS@ -L/usr/local/lib +oneshot: $(SRCS) $(MECHA_SRCS) + rm lst.h ; ln -s ../mecha/lst.h . + rm dyn.h ; ln -s ../mecha/dyn.h . + rm net.h ; ln -s ../mecha/net.h . + cat $(SRCS) $(MECHA_SRCS) > _continuity.c + $(CC) $(CFLAGS) _continuity.c -c + $(CC) $(CFLAGS) _continuity.o ../pcre/pcreposix.o ../pcre/pcre.o -o continuity @LDFLAGS@ @LIBS@ -L/usr/local/lib + +../bin/cdog: cdog.c + $(CC) $(CFLAGS) cdog.c -o ../bin/cdog + +clean: + rm -rf $(OBJS) *~ *.ln gmon.out mon.out _continuity.c ../bin/continuity ../bin/cdog + +count: + wc -l `find . -name '*.[ch]'` + +build.h: + @echo \#define CONT_UNAME \"`uname -a`\" > build.h + @echo \#define CONT_DATE \"`date`\" >> build.h + @echo \#define CONT_HOST \"`hostname`\" >> build.h + @echo \#define CONT_CFLAGS \" @CFLAGS@ \" >> build.h + @echo \#define CONT_LDSHARE \" @LDSHARED@ \" >> build.h + @echo \#define CONT_LIBS \" @LIBS@ \" >> build.h + @echo \#define CONT_PREBUILD \" @PRE_BUILD@ \" >> build.h + @echo \#define CONT_POSTBUILD \" @POST_BUILD@ \" >> build.h + +depend: build.h + $(MAKEDEPEND) @DEPFLAGS@ -I ../include $(SRCS) + $(RM) build.h + diff --git a/mk4/continuity/cont/cdog.c b/mk4/continuity/cont/cdog.c new file mode 100644 index 0000000..0d6ab25 --- /dev/null +++ b/mk4/continuity/cont/cdog.c @@ -0,0 +1,90 @@ +/* + * $Header: /cvsroot/csrc/continuity/cont/cdog.c,v 1.4 2004/03/18 15:04:15 + * aleigh Exp $ + */ + +/* + * Copyright (c) 1994, 2004 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Disclosure, copying, distribution, or transmission of this code without + * express permission is prohibited. + */ + +#include +#include + +#include "csys.h" + +#define CBIN "./continuity" + +static void print_usage(void); + +static void print_usage(void) +{ + printf("For Continuity startup options, run cdog -h\n"); +} + +int main(int argc, char **argv) +{ + int status; + char **alist; + int acount; + + if (argc == 1) { + print_usage(); + exit(0); + } + + /* Prevent Continuity from daemonizing which will cause + us to lose track of it's PID */ + + if(fork()!=0) { + exit(0); + } + + setsid(); + + if(fork()!=0) { + exit(0); + } + + printf("Continuity Watchdog v1.0.2\n"); + + putenv((char *)"__CONT_NODAEMON=true"); + + signal(SIGHUP, SIG_IGN); + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + signal(SIGPIPE, SIG_IGN); + + acount = argc + 1; + alist = (char **) malloc(acount * sizeof(char *)); + bzero(alist, acount * sizeof(char *)); + bcopy(argv, alist, argc * sizeof(char *)); + alist[0] = (char *) CBIN; + + while (1) { + if (fork() != 0) { + wait(&status); + if (WIFEXITED(status)) { + printf("cdog: Continuity exited, status %d.\n", + WEXITSTATUS(status)); + if (WEXITSTATUS(status) == 5) { + printf("cdog: Continuity requested exit.\n"); + exit(0); + } + if (WEXITSTATUS(status) == 6) { + printf("cdog: Could not start server. Exiting.\n"); + exit(0); + } + } + continue; + } + if (execvp(CBIN, alist) == -1) + exit(6); + } +} diff --git a/mk4/continuity/cont/continuity.c b/mk4/continuity/cont/continuity.c new file mode 100644 index 0000000..73cb233 --- /dev/null +++ b/mk4/continuity/cont/continuity.c @@ -0,0 +1,382 @@ +/* + * $Header: /san01/cvs/ashpool/csrc/continuity/cont/continuity.c,v 1.42 2004/05/11 02:53:17 aleigh Exp $ + */ + +/* + * Copyright (c) 2001, 2004 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Use, disclosure, copying, distribution, or transmission of this code without + * express permission is prohibited. + */ + +#include "continuity.h" +#include "build.h" + +#if HAVE_PRCTL +#include +#endif + +/* Continuity's birthday is 12.05.2001 */ + +/* + * When the startup is finished, this conditional will receive a broadcast. + */ +static pthread_cond_t startup_conditional = PTHREAD_COND_INITIALIZER; +static int started = 0; + +static xmlTconfig *global_config = NULL; +static const xmlTtag *base_config_tag = NULL; +static hshTvoid_list *socket_stash; + +static void print_version(void); +static int test_build(void); +static void print_usage(void); +static void forever(void); + +static int test_build(void) { + cTval *v; + + CVNEWSTRCPY(v,"foo"); +} + +static void conFdaemonize(void) { + fclose(stdout); + fclose(stdin); + fclose(stderr); + + if(fork()!=0) { + exit(0); + } + + setsid(); + + if(fork()!=0) { + exit(0); + } +} + +const xmlTtag *conFget_config_basetag(void) +{ + assert(base_config_tag != NULL); + return base_config_tag; +} + +/* + * Do not go off the reservation. If you go off the reservation, I will not + * come after you. + */ +void intr_handler(int sigraised) +{ + exit(0); + /* logFmsgid(0, "CON", 1); */ + logFmsg(3, "intr_handler called: rcv'd sigraised %d", sigraised); + signal(SIGINT, intr_handler); + return; +} + +const char *conFget_build(void) +{ + return BUILD_STRING; +} + +static void forever(void) { + while(1) { + thrFsleep(99999); + } +} + +static void print_usage(void) +{ + printf(BUILD_STRING); + printf("\n"); + + printf("Copyright (c) 2001, 2004 Alex Leigh.\n"); + printf("Contains contributions by Eric Lindvall.\n\n"); + + printf("Usage: \tcontinuity -c module.cfg [-o logfile [-r n]] [-u username]\n"); + printf("\tcontinuity -v\n\n"); + printf("\t-c\tPath to the module configuration file.\n"); + printf("\t-o\tOutput messages to a file. Server will run in the background.\n"); + printf("\t-r\tRotate message files and do not use more than n MB total disk.\n"); + printf("\t-u\tUser to run as.\n"); + printf("\t-v\tPrint version information.\n"); +} + +int conFsocketstash_update(int sd, int idx) { + hshFvoid_int_update(socket_stash,idx,(void *)sd); + return 0; +} + +int conFsocketstash_find(int idx) { + int s; + + s=(int)hshFvoid_int_find(socket_stash,idx); + if(s==0) return -1; + return s; +} + +int main(int argc, char **argv) +{ + extern char *optarg; + int ret; + int c = 0, a = 0, t = 0, v = 0, o = 0, r=0, err = 0; + char *c_arg = NULL, *a_arg = NULL, *o_arg = NULL, *r_arg=NULL; + + signal(SIGINT, intr_handler); + signal(SIGPIPE, SIG_IGN); + + socket_stash=hshFvoid_int_init(NULL); + + logFinit(); + + while ((ret = getopt(argc, argv, "tvc:u:a:o:r:")) != EOF) { + switch (ret) { + case 'c': + if (c==1) { + err++; + } else { + c++; + } + c_arg = optarg; + break; + + case 'a': + if (a==1) { + err++; + } else { + a++; + } + a_arg = optarg; + break; + + case 'v': + if (v==1) { + err++; + } else { + v++; + } + break; + + case 't': + if (t==1) { + err++; + } else { + t++; + } + break; + + case 'o': + if (o==1) { + err++; + } else { + o++; + o_arg=optarg; + } + break; + case'r': + if(r==1) { + err++; + } else { + r++; + r_arg=optarg; + } + break; + + default: + err++; + } + } + + if (v==1) { + print_version(); + } + + if (t==1) { + exit(test_build()); + } + + /* no -c */ + if (c==0) { + err++; + } + + /* -r without -o */ + if(r==1&&o==0) { + err++; + } + + if (err != 0) { + print_usage(); + exit(5); + } + + if(r_arg!=NULL) { + logFset_rotatesize(atoi(r_arg)*1048576); + } + + if(o_arg!=NULL) { + if(getenv("__CONT_NODAEMON")==NULL) { + conFdaemonize(); + } + + if(logFset_outputfile(o_arg)==-1) { + perror(o_arg); + exit(1); + } + } + + thrFmod_init(); + + /* Bring the statistics interface online */ + tasFinit(); + tasFstat_counter_add("sys", 0, "startup", utlFtime()); + + logFmsg(0, BUILD_STRING); + logFmsg(0, + "Copyright (c) 2001, 2004 Alex Leigh."); + logFmsg(0, "Contains contributions by Eric Lindvall."); + logFmsg(0, "Use is subject to license terms."); + + global_config = xmlFload_file(c_arg); + if (global_config == NULL) { + logFmsg(2, "Could not load configuration file. [f: %s] [e: %d]", + c_arg, errno); + exit(0); + } + base_config_tag = xmlFbase_tag(global_config); + + assert(base_config_tag != NULL); + + base_config_tag = + xmlFfind_first_tag_children(base_config_tag, "configuration"); + + rndFinit(); + + /* Initialize TLS memory system. */ + tlsFinit(); + + /* Load the module.cfg */ + if (dlFload_config() != STATUS_OK) { + logFmsgid(2, "CON", 2); + exit(5); + } + + /* Initialize mmap memory system -- this creates a thread */ + mmcFinit(); + + started = 1; + + pthread_cond_broadcast(&startup_conditional); + + /* Never exit */ + forever(); + + return 0; +} + + +/* + * This function returns when the init functions have all been executed. + */ +void conFwait_for_init(void) +{ + +#ifdef LINUX + while (1) { + if (started == 1) + return; + thrFsleep(500); + } +#else + pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; + + if (started == 1) + return; + + pthread_cond_wait(&startup_conditional, &mut); +#endif +} + +static void print_version(void) +{ + + printf("%s\n", BUILD_STRING); + printf("Copyright (c) 2001, 2004 Alex Leigh.\n"); + printf + ("Contains contributions by Eric Lindvall.\nUse is subject to license terms.\n\n"); + printf("Built on: %s\n", CONT_DATE); + printf("Hostname: %s\n", CONT_HOST); + printf("%s\n\n", CONT_UNAME); + printf("CFLAGS: %s\n", CONT_CFLAGS); + printf("LDSHARECMD: %s\n", CONT_LDSHARE); + printf("LIBS: %s\n\n", CONT_LIBS); + printf("PRE_BUILD: %s\n", CONT_PREBUILD); + printf("POST_BUILD: %s\n", CONT_POSTBUILD); + + exit(0); +} + +int op_show_version(netTconn *conn) +{ + netFconn_writef(conn,"%s\r\n", BUILD_STRING); + netFconn_writef(conn,"Copyright (c) 2001, 2004 Alex Leigh\r\n"); + netFconn_writef(conn,"Contains contributions by Eric Lindvall\r\n"); + netFconn_writef(conn,"Built on: %s\r\n", CONT_DATE); + netFconn_writef(conn,"Hostname: %s\r\n", CONT_HOST); + netFconn_writef(conn,"%s\r\n\r\n", CONT_UNAME); + netFconn_writef(conn,"CFLAGS: %s\r\n", CONT_CFLAGS); + netFconn_writef(conn,"LDSHARECMD: %s\r\n", CONT_LDSHARE); + netFconn_writef(conn,"LIBS: %s\r\n\r\n", CONT_LIBS); + netFconn_writef(conn,"PRE_BUILD: %s\r\n", CONT_PREBUILD); + netFconn_writef(conn,"POST_BUILD: %s\r\n", CONT_POSTBUILD); + + return STATUS_OK; +} + +int set_userid(MECHA_UNUSED_ARGUMENT void *p, lstTset *opts) { + const char *u_arg = lstFset_get(opts,"user"); + int uid, gid; + + if(u_arg==NULL) return STATUS_ERROR; + + uid = utlFgetuid((const char *)u_arg); + gid = utlFgetgid (u_arg); + + if (gid != -1) { + if (setregid (gid, gid) != 0) { + logFmsg(2, "Unable to change GID to %d. Failing.", + gid); + exit(5); + } else { + logFmsg(0, "Changed GID to %d.", gid); + } + } else { + logFmsg(2, "No such user: %s.", u_arg); + exit(5); + } + + if (uid != -1) { + if (setreuid (uid, uid) != 0) { + logFmsg(2, "Unable to change UID to %s(%d). Failing.", + u_arg, uid); + exit(5); + } else { + logFmsg(0, "Changed UID to %s(%d).", u_arg, uid); + } + } else { + logFmsg(2, "No such user: %s.", u_arg); + exit(5); + } + +#if HAVE_PRCTL + /* if we have the ability to force coredumps -- let's do it */ + prctl (PR_SET_DUMPABLE, 1); +#endif + + return STATUS_PROCEED; +} + diff --git a/mk4/continuity/cont/dis.c b/mk4/continuity/cont/dis.c new file mode 100644 index 0000000..5e6e033 --- /dev/null +++ b/mk4/continuity/cont/dis.c @@ -0,0 +1,445 @@ +/* + * $Header: /datum01/src/continuity/src/dispatch.c,v 1.78.2.5 2002/09/15 + * 02:32:40 aleigh Exp $ + */ + +/* + * Copyright (c) 1994, 2004 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Disclosure, copying, distribution, or transmission of this code without + * express permission is prohibited. + */ + +#undef POLL_LISTENER + +/* + * The new role of the dispatcher in the v3 configuration is to monitor a + * network socket for new connections. When a connection is received, a pool + * thread is used to run a user-provided function to handle the request in + * whatever manner is appropriate. + */ + +#include "csys.h" +#include "mecha.h" + +struct disSsock { + int sd; + uint32_t cli_ipv4_addr; +}; +typedef struct disSsock disTsock; + +struct disSlistener { + int sd; + int ipv4_port; + unsigned int ipv4_ip; + const char *socketstash_id; + int thr_max; + int thr_runq; + int thr_block; + const char *handler_name; + int (*handler)(void *, lstTset *); + thrTtpool *req_pool; +}; + +#include "continuity.h" + +int disFwait_for_startup(disTlistener * listener) +{ + conFwait_for_init(); + + /* We have to create this here, rather than in disFsetup(), because on Linux setguid() + * does not set the user-id for all the threads of a process. + */ + + listener->req_pool = + thrFinit(listener->thr_max, listener->thr_runq, + listener->thr_block); + + return disFlisten_loop(listener); +} + +int ipv4_openport(MECHA_UNUSED_ARGUMENT void *p, lstTset * opts) +{ + const char *port; + const char *ip; + const char *id; + unsigned int port_int; + unsigned int ip_int; + int sd; + + port = lstFset_get(opts, "port"); + if (port == NULL) { + logFmsg(2,"port parameter unset!"); + exit(5); + } + + port_int=atoi(port); + + id = lstFset_get(opts,"id"); + if(id==NULL) { + logFmsg(2,"id parameter unset!"); + exit(5); + } + + ip = lstFset_get(opts, "ip"); + if (ip != NULL) { + struct in_addr saddr; + + if (inet_aton(ip, &saddr) == 0) { + logFmsg(2, "Invalid IP specified."); + return STATUS_ERROR; + } + + ip_int = ntohl(saddr.s_addr); + } else { + ip_int = 0; + } + + sd = netFipv4_listen_tcp(port_int,ip_int, 5); + + if(sd<0) { + logFmsg(2,"Unable to open socket. e: %d", errno); + exit(5); + } + + conFsocketstash_update(sd,atoi(id)); + + return STATUS_OK; +} + +int ipv4_dispatcher(MECHA_UNUSED_ARGUMENT void *p, lstTset * opts) +{ + const char *port; + const char *ip; + const char *threads = lstFset_get(opts, "threads"); + const char *queue = lstFset_get(opts, "queue"); + const char *id = lstFset_get(opts,"id"); + + disTlistener *listener; + pthread_t tid; + + listener = (disTlistener *) malloc(sizeof(disTlistener)); + bzero(listener, sizeof(disTlistener)); + + listener->socketstash_id=id; + + listener->handler_name = lstFset_get(opts, "handler"); + if (listener->handler_name == NULL) { + logFmsg(2, "Handler not specified."); + return STATUS_ERROR; + } + listener->handler = (cont_handler)dlFget_addr(listener->handler_name); + if (listener->handler == NULL) { + logFmsg(2, "Unable to map handler function."); + return STATUS_ERROR; + } + port = lstFset_get(opts, "port"); + if (port == NULL) { + logFmsg(3, "Port unspecified."); + return STATUS_ERROR; + } + listener->ipv4_port = atoi(port); + + if (threads == NULL) + listener->thr_max = 32; + else + listener->thr_max = atoi(threads); + + logFmsg(3, "pool threads: %d", listener->thr_max); + + if (queue == NULL) + listener->thr_runq = 512; + else + listener->thr_runq = atoi(queue); + + listener->thr_block = 0; + + ip = lstFset_get(opts, "ip"); + if (ip != NULL) { + struct in_addr saddr; + + if (inet_aton(ip, &saddr) == 0) { + logFmsg(2, "Invalid IP specified."); + return STATUS_ERROR; + } + + listener->ipv4_ip = ntohl(saddr.s_addr); + } else { + listener->ipv4_ip = 0; + } + + listener->sd = disFsetup(listener); + + if (listener->sd < 0) + return STATUS_ERROR; + + pthread_create(&tid, NULL, (void *(*)(void *)) disFwait_for_startup, + listener); + + return STATUS_OK; +} + +/* + * Create a dispatcher. + */ +int disFsetup(disTlistener * listener) +{ + int sock; + + logFmsgid(0, "CON", 10, listener->thr_max, listener->thr_runq, + listener->thr_block); + + if(listener->socketstash_id!=NULL) { + logFmsg(3,"Getting socket from stash."); + sock=conFsocketstash_find(atoi(listener->socketstash_id)); + logFmsg(3,"socket is %d", sock); + } else { + sock = netFipv4_listen_tcp(listener->ipv4_port, listener->ipv4_ip, 5); + } + + if (sock < 0) { + logFmsgid(2, "CON", 5, errno); + exit(5); + } + + fleFset_close_exec(sock); + + return sock; +} + +#ifndef POLL_LISTENER +int disFlisten_loop(disTlistener * listener) +{ + struct sockaddr_in ca; + + int calen = sizeof(ca); + int ns; + struct in_addr *ia; + pthread_attr_t tattr; + netTconn *conn; + + assert(listener->handler != NULL); + assert(listener->req_pool != NULL); + + listen(listener->sd, 1024); + + logFmsgid(0, "CON", 6, pthread_self(), listener->handler); + + pthread_attr_init(&tattr); + pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); + + while (1) { + conn = (netTconn *) malloc(sizeof(netTconn)); + + ns = accept(listener->sd, (struct sockaddr *) &ca, (socklen_t *) &calen); + + if (ns == -1) { + if (errno == EINTR) { + logFmsgid(0, "CON", 7); + intr_handler(0); + } + logFmsgid(1, "CON", 8, strerror(errno)); + continue; + } + + fleFset_close_exec(ns); + + netFset_reuse(ns); /* Set the socket to be reusable */ +/* netFset_nodelay(ns); */ + +#ifdef NOTDEF + /* Set the socket to nonblocking */ + if ((fd_flags = fcntl(ns, F_GETFL)) == -1) + return -1; + fd_flags |= O_NONBLOCK; + if (fcntl(ns, F_SETFL, fd_flags) == -1) + return -1; +#endif + + ia = &ca.sin_addr; + + conn->sd = ns; + conn->cli_ipv4_addr = ntohl(ia->s_addr); + conn->io_read = &netFconn_os_read; + conn->io_write = &netFconn_os_write; + conn->io_close = &netFconn_os_close; + conn->io_writev = &netFconn_os_writev; + conn->data_free = NULL; + + tasFstat_counter_add("net", 0, "conn_rcvd", 1); + + /* + * It's up to the work fucntion to free the connection structure + * whenever it's done with it + */ + + if (thrFadd_work(listener->req_pool, (mecha_handler)listener->handler, conn) == -1) { + logFmsgid(1, "CON", 9); + conn->io_close(conn); + } + } +} + +#else +/* + * this is the primary function that the dispatcher spins in while receiving + * connections. A connection is received and then placed into the poll list. + * If it becomes available for read, it is put on the work list where a + * thread will pick it up when one becomes available. This ensures that the + * request data has been received, which prevents read() from spinning on the + * socket later. + */ + +int disFlisten_loop(disTlistener * listener) +{ + struct sockaddr_in ca; + int calen = sizeof(ca); + int ns, fd_flags; + struct in_addr *ia; + pthread_attr_t tattr; + netTconn *conn; + int i, ret; + + struct pollfd *pfds; + int nfds; + disTsock *socks; + int maxsds = listener->thr_max + 1; + + assert(listener->handler != NULL); + assert(listener->req_pool != NULL); + + listen(listener->sd, 1024); + + logFmsgid(0, "CON", 6, pthread_self(), listener->handler); + + pthread_attr_init(&tattr); + pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); + + /* + * Create a pfd array large enough to hold an entry for every possible + * connection, which is equal to the number of threads. + */ + pfds = (struct pollfd *) malloc(sizeof(struct pollfd) * maxsds); + + socks = (disTsock *) malloc(sizeof(disTsock) * maxsds); + bzero(socks, sizeof(disTsock) * maxsds); + + if ((fd_flags = fcntl(listener->sd, F_GETFL)) == -1) + return -1; + fd_flags |= O_NONBLOCK; + if (fcntl(listener->sd, F_SETFL, fd_flags) == -1) + return -1; + + pfds[0].fd = listener->sd; + pfds[0].events = POLLIN | POLLPRI; + + while (1) { + /* Create poll list of socks currently in socks */ + + /* { utlTswatch *sw = utlFstart_swatch(); */ + nfds = 1; /* we start with the listener */ + for (i = 0; i < listener->thr_max; i++) { + if (socks[i].sd > 0) { + pfds[nfds].fd = socks[i].sd; + pfds[nfds].events = POLLIN | POLLPRI; + nfds++; + } + } + /* logFmsg(3,"poll build took %d us", utlFstop_swatch(sw));} */ + + + /* { utlTswatch *sw = utlFstart_swatch(); */ + ret = poll(pfds, nfds, 5000); + /* logFmsg(3,"poll() took %d us", utlFstop_swatch(sw));} */ + + + if (ret == -1) { + logFmsg(2, "poll() returned -1 (e: %d)", errno); + exit(1); + } + if (poll > 0) { + for (i = 1; i < nfds; i++) { + if ((pfds[i].revents & POLLIN) == POLLIN) { + int x; + + for (x = 0; x < listener->thr_max; x++) { + if (socks[x].sd == pfds[i].fd) { + conn = (netTconn *) malloc(sizeof(netTconn)); + + conn->cli_ipv4_addr = socks[x].cli_ipv4_addr; + conn->sd = socks[x].sd; + conn->io_read = &netFconn_os_read; + conn->io_write = &netFconn_os_write; + conn->io_close = &netFconn_os_close; + conn->io_writev = &netFconn_os_writev; + conn->data_free = NULL; + + + logFmsg(3, "%d", conn->sd); + + socks[x].sd = 0; + + tasFstat_counter_add("net", 0, "conn_rcvd", 1); + + if (thrFadd_work + (listener->req_pool, listener->handler, + conn) == -1) { + logFmsgid(1, "CON", 9); + close(conn->sd); + free(conn); + } + } + } + } + } + + /* if (pfds[0].revents & POLLIN == POLLIN) { */ + ns = accept(listener->sd, (struct sockaddr *) &ca, + (int *) &calen); + + if (ns == -1) { + if (errno == EINTR) { + logFmsgid(0, "CON", 7); + intr_handler(0); + } + /* logFmsgid(1, "CON", 8, strerror(errno)); */ + continue; + } + netFset_reuse(ns); /* Set the socket to be reusable */ + netFset_nodelay(ns); /* Disable the NAGLE algorithm on the socket */ + + { + unsigned int x = 50000; + if (setsockopt + (ns, SOL_SOCKET, SO_SNDBUF, &x, + sizeof(unsigned int)) == -1) { + logFmsg(3, + "setsockopt() SNDBUF failed: e: %d", + errno); + } + } + + /* Set the socket to nonblocking */ + if ((fd_flags = fcntl(ns, F_GETFL)) == -1) + return -1; + fd_flags |= O_NONBLOCK; + if (fcntl(ns, F_SETFL, fd_flags) == -1) + return -1; + + ia = &ca.sin_addr; + for (i = 0; i < listener->thr_max; i++) { + if (socks[i].sd == 0) { + socks[i].sd = ns; + socks[i].cli_ipv4_addr = ntohl(ia->s_addr); + break; + } + } + } + } +} + +#endif diff --git a/mk4/continuity/cont/dl.c b/mk4/continuity/cont/dl.c new file mode 100644 index 0000000..35b401d --- /dev/null +++ b/mk4/continuity/cont/dl.c @@ -0,0 +1,702 @@ +/* + * $Header: /datum01/src/continuity/src/dl.c,v 1.41.2.6 2002/09/11 18:02:28 + * aleigh Exp $ + */ + +/* + * Copyright (c) 1994, 2004 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Disclosure, copying, distribution, or transmission of of this code without + * express permission is prohibited. + */ + +/* + * MTS: The category list is MTS write unsafe. + */ + +#include "csys.h" +#include "mecha.h" + +struct dlSlib { + char *fn; // Filename without extension; ie ../lib/site + void *handle; // Handle to the library load + char *name; // Short name of the module. + xmlTconfig *profile; // XML profile (if provided) + struct dlSlib *next; +}; +typedef struct dlSlib dlTlib; + +struct dlSmap { + char symbol[64]; + void *addr; + lstTset *opts; + struct dlSmap *next; +}; + +struct dlSentry { + lstTset *opts; + int (*addr)(void *, lstTset *); + struct dlSentry *next; +}; + +struct dlScategory { + char *name; + unsigned int id; + struct dlSentry *entry; + struct dlScategory *next; +}; + +#include "continuity.h" + +static void dlFcreate_config(void); +static void dlFmap_append(dlTmap ** mapset, dlTmap * entry); +static void dlFentry_append(dlTcategory * category, dlTentry * entry); +static dlTcategory *dlFcategory_getbyid(unsigned int catid); +static dlTcategory *dlFcategory_get(const char *category); +static dlTcategory *dlFcategory_add(const char *category); +static void dlFresolve_categories(void); +static int dlFsatisfy_conditions(dlTlib *lib); + +#include + +#ifndef LINUX +/* #include */ +#endif + +unsigned int dlGcategory_seq = 0; +dlTcategory *dlGcategories = NULL; +dlTlib *dlGlibs = NULL; +dlTmap *dlGmap = NULL; + +int dlFop_show_dl_loads(netTconn *conn, int argc, char **argv) { + netFconn_writef(conn,"\r\nDL Loads\r\n--------\r\n"); + if(dlGlibs==NULL) { + netFconn_writef(conn,"No loads.\r\n"); + return STATUS_OK; + } + + for(dlTlib *p=dlGlibs;p!=NULL;p=p->next) { + netFconn_writef(conn,"%s\r\n", p->fn); + } + + return STATUS_OK; +} + +int dlFop_show_dl_symbols(netTconn *conn, int argc, char **argv) { + netFconn_writef(conn,"\r\nSymbols\r\n-------\r\n"); + + if(dlGmap==NULL) { + netFconn_writef(conn,"No dynamic symbols.\r\n"); + return STATUS_OK; + } + + for(dlTmap *p=dlGmap;p!=NULL;p=p->next) { + netFconn_writef(conn,"0x%06x %s()\r\n", p->addr, p->symbol); + } + return STATUS_OK; +} + +/* + * Append a new function reference to the map. This is reverse order out of + * legacy from mk2 and should probably be changed to just FILO the list, + * since the order is no longer relavant in mk3. + */ +static void dlFmap_append(dlTmap ** mapset, dlTmap * entry) +{ + dlTmap *p; + + if (*mapset == NULL) { + entry->next = NULL; + *mapset = entry; + return; + } + p = (dlTmap *) * mapset; + + while (1) { + if (p->next == NULL) { + entry->next = NULL; + p->next = entry; + return; + } else { + p = p->next; + } + } +} + +/* + * FIFO an entry into the categories list. The order is important here since + * this is the order they are going to get executed in the pipeline. + */ +static void dlFentry_append(dlTcategory * category, dlTentry * entry) +{ + dlTentry *p; + + if (category->entry == NULL) { + entry->next = NULL; + category->entry = entry; + return; + } + p = (dlTentry *) category->entry; + + while (1) { + if (p->next == NULL) { + entry->next = NULL; + p->next = entry; + return; + } else { + p = p->next; + } + } +} + +/* + * Return the category structure for the given cateogy name. Returns NULL if + * the category did not exist. + */ +static dlTcategory *dlFcategory_getbyid(unsigned int catid) +{ + dlTcategory *cat; + + cat = dlGcategories; + while (cat != NULL) { + if (catid == cat->id) { + return cat; + } + cat = cat->next; + } + return NULL; +} + +/* + * Return the category structure for the given cateogy name. Returns NULL if + * the category did not exist. + */ +static dlTcategory *dlFcategory_get(const char *category) +{ + dlTcategory *cat; + + cat = dlGcategories; + while (cat != NULL) { + if (strcmp(cat->name, category) == 0) { + return cat; + } + cat = cat->next; + } + return NULL; +} + +/* + * Return the catid for the given category name. Returns -1 if the name was + * not found. + */ +int dlFpipeline_getid(const char *pipeline) +{ + dlTcategory *cat; + + cat = dlGcategories; + while (cat != NULL) { + if (strcmp(cat->name, pipeline) == 0) { + return cat->id; + } + cat = cat->next; + } + return -1; +} + +/* + * o/~ What we see, and what we seem, are but a dream, within a dream o/~ + */ + +static dlTcategory *dlFcategory_add(const char *category) +{ + dlTcategory *cat; + + cat = (dlTcategory *) malloc(sizeof(dlTcategory)); + cat->name = strFcopy(category); + + /* + * Side-effect + */ + cat->id = dlGcategory_seq++; + cat->entry = NULL; + + cat->next = dlGcategories; + dlGcategories = cat; + + return cat; +} + +int dlFload_config(void) +{ + dlTcategory *category; + const xmlTtag *atag; + xmlTiterator *ait; + + dlFcreate_config(); + + atag = conFget_config_basetag(); + assert(atag != NULL); + if (atag == NULL) + return -1; + + atag = xmlFfind_first_tag_children(atag, "continuity_config"); + assert(atag != NULL); + + if (atag == NULL) + return -1; + + atag = xmlFfind_first_tag_children(atag, "modules"); + assert(atag != NULL); + + if (atag == NULL) + return -1; + + ait = xmlFiterator_init(atag); + assert(ait != NULL); + + while ((atag = xmlFiterator_next_name(ait, "module")) != NULL) { + const char *value = xmlFtag_get_value_str(atag); + dlFload_library(value); + } + + xmlFiterator_free(ait); + + /* Run the init class */ + + category = dlFcategory_get("init"); + + dlFresolve_categories(); + + dlFpipeline_exec(NULL, dlFpipeline_getid("__init"), NULL, NULL); + dlFpipeline_exec(NULL, dlFpipeline_getid("init"), NULL, NULL); + + return STATUS_OK; +} + +/* + * This function is used to execute one of the dynamic categories. By the + * time this function is called, all of the addresses in the category should + * have been mapped. + */ +int dlFpipeline_exec(void *payload, int catid, const char *limit_name, + const char *limit_value) +{ + dlTcategory *cat; + dlTentry *entry; + int (*func) (void *, lstTset *); + register int ret; + const char *limit; + register int done = 1; + int restart_count = 0; + + cat = dlFcategory_getbyid(catid); + + if (cat == NULL) { + return STATUS_ERROR; + } + + if (cat->entry == NULL) { + return STATUS_OK; + } + + while (1) { + if (limit_name != NULL && limit_value != NULL) { + for (entry = cat->entry; entry != NULL; entry = entry->next) { + limit = lstFset_get(entry->opts, limit_name); + if (limit != NULL) { + if (strcmp(limit_value, limit) != 0) + continue; + } + func = (int (*)(void *, lstTset *)) entry->addr; + + ret = (func) (payload, entry->opts); + if (ret == STATUS_EXIT) + return ret; + + if (ret == STATUS_RESTART) { + done = 0; + break; + } + } + } else { + for (entry = cat->entry; entry != NULL; entry = entry->next) { + func = (int (*)(void *, lstTset *)) entry->addr; + ret = (func) (payload, entry->opts); + if (ret == STATUS_EXIT) + return ret; + if (ret == STATUS_RESTART) { + done = 0; + break; + } + } + } + + if (done == 0) { + restart_count++; + if (restart_count > 32) + return STATUS_ERROR; + done = 1; + continue; + } + break; + } + return STATUS_OK; +} + +static void dlFresolve_categories(void) +{ + dlTcategory *c; + dlTentry *e; + const char *sym; + + for (c = dlGcategories; c != NULL; c = c->next) { + for (e = c->entry; e != NULL; e = e->next) { + sym = lstFset_get(e->opts, "fn"); + if (sym == NULL) + continue; + + if (strcmp(sym, "ipv4_dispatcher") == 0) { + e->addr = ipv4_dispatcher; + } else { + if(strcmp(sym,"set_userid")==0) { + e->addr=set_userid; + } else { + if(strcmp(sym,"ipv4_openport")==0) { + e->addr=ipv4_openport; + } else { + e->addr = (cont_handler)dlFget_addr(sym); + + if (e->addr == NULL) { + logFmsg(2, + "Failed to map function %s from loaded libraries.", + sym); + exit(5); + } + } + } + } + } + } +} + +static void dlFcreate_config(void) +{ + const xmlTtag *atag, *btag, *ctag; + xmlTiterator *ait, *bit, *cit; + dlTentry *entry; + dlTcategory *cat; + + /* + * Create the special __init pipeline that will hold + * the automatic init handlers. + */ + dlFcategory_add("__init"); + + atag = conFget_config_basetag(); + if (atag == NULL) + return; + + atag = xmlFfind_first_tag_children(atag, "continuity_config"); + if (atag == NULL) + return; + + atag = xmlFfind_first_tag_children(atag, "pipelines"); + if (atag == NULL) + return; + + ait = xmlFiterator_init(atag); + assert(ait != NULL); + + while ((atag = xmlFiterator_next_name(ait, "pipeline")) != NULL) { + const char *name = xmlFtag_get_attrib_value(atag, "name"); + assert(name != NULL); + cat = dlFcategory_get(name); + if (cat == NULL) + cat = dlFcategory_add(name); + + bit = xmlFiterate_children(atag); + if (bit != NULL) { + while ((btag = xmlFiterator_next_name(bit, "handler")) != NULL) { + const char *func = xmlFtag_get_attrib_value(btag, "func"); + assert(func != NULL); + + entry = (dlTentry *) malloc(sizeof(dlTentry)); + bzero(entry, sizeof(dlTentry)); + entry->opts = lstFset_init(); + lstFset_add(entry->opts, "fn", func); + + cit = xmlFiterate_children(btag); + if (cit != NULL) { + while ((ctag = + xmlFiterator_next_name(cit, "arg")) != NULL) { + const char *arg_name = + xmlFtag_get_attrib_value(ctag, "name"); + const char *arg_value = xmlFtag_get_value_str(ctag); + if (arg_name != NULL && arg_value != NULL) { + lstFset_add(entry->opts, arg_name, arg_value); + } + } + xmlFiterator_free(cit); + } + dlFentry_append(cat, entry); + } + xmlFiterator_free(bit); + } + } + xmlFiterator_free(ait); +} + +/* Check to see if the conditions of the XML profile + * are met and that this module should be loaded. The specific + * requirements that are checked are that the modules listed + * in the tag have already been loaded into the + * server. */ +static int dlFsatisfy_conditions(dlTlib *lib) +{ + xmlTtag *tag, *req; + xmlTiterator *it; + + /* + * If there is no XML profile associated with the module + * there's nothing we can do but hope. + */ + + if(lib->profile==NULL) { + return -1; + } + + tag=xmlFbase_tag(lib->profile); + + /* If we have a profile but it's empty that's the same + as not having any requirements, so we pass this + config */ + + if(tag==NULL) { + return 0; + } + + tag=xmlFtag_get_children(tag); + + /* Ditto */ + if(tag==NULL) { + return 0; + } + + req=xmlFfind_first_tag_children(tag,"requires"); + + /* Ditto */ + if(req==NULL) { + return 0; + } + + it=xmlFiterator_init(req); + + assert(it!=NULL); + + while((tag=xmlFiterator_next_name(it,"require"))!=NULL) { + char *required=xmlFtag_get_value_str(tag); + int found=0; + + if(required==NULL) continue; + +// logFmsg(3,"Module requires %s; searching...", xmlFtag_get_value_str(tag)); + + for(dlTlib *lp=dlGlibs;lp!=NULL;lp=lp->next) { + /* Not all modules have profiles, so not + * all modules have names. */ + if(lp->name==NULL) continue; + + if(strcmp(lp->name,required)==0) { + found=1; + break; + } + } + + if(found==0) { + logFmsg(2,"Unable to load module: requires %s", required); + return -1; + } + } + + xmlFiterator_free(it); + + return 0; +} + +/* Load the requested library. This is called directly in reponse + * to tags stored in the XML configuration. + */ +int dlFload_library(const char *shlib) +{ + void *handle; + dlTlib *lib; + char xmlpath[1024]; + char sopath[1024]; + dlTcategory *cat = dlFcategory_get("__init"); + + assert(shlib != NULL); + assert(cat!=NULL); + + snprintf(xmlpath,1024,"%s.xml", shlib); + snprintf(sopath,1024,"%s.so",shlib); + + lib = (dlTlib *) malloc(sizeof(dlTlib)); + + memFclear (lib, sizeof (dlTlib)); + + if(fleFexist(xmlpath)==0) { + logFmsg(0,"XML profile %s not found.", xmlpath); + } else { + char *xmlfile; + size_t xmllen; +// logFmsg(3,"XML profile found for %s", shlib); + + xmlfile=fleFload_file(xmlpath,&xmllen); + if(xmlfile==NULL) { + logFmsg(1,"Unable to load XML profile. %s", xmlpath); + exit(5); + } + lib->profile=xmlFparse(xmlfile); + if(lib->profile==NULL) { + logFmsg(1,"Unable to parse XML profile. %s", xmlpath); + } else { + xmlTtag *base, *tag; + + base=xmlFbase_tag(lib->profile); + if(base!=NULL) { + tag=xmlFfind_first_child(base,"module_name"); + if(tag!=NULL) { + const char *n = xmlFtag_get_value_str(tag); + if(n!=NULL) { + lib->name=n; +// logFmsg(3,"Module was named %s", n); + } + } + + tag=xmlFfind_first_child(base,"init_func"); + if(tag!=NULL) { + const char *f = xmlFtag_get_value_str(tag); + + if(f!=NULL) { + dlTentry *e; + + e=(dlTentry *)malloc(sizeof(dlTentry)); + memFclear(e,sizeof(dlTentry)); + e->opts=lstFset_init(); + lstFset_add(e->opts,"fn",f); + dlFentry_append(cat,e); + } + } + } + +// logFmsg(3,"XML profile loaded."); + if(dlFsatisfy_conditions(lib)!=0) { + logFmsg(2,"Could not load module %s. Failing.", shlib); + exit(5); + } + } + } + +#ifndef OPENBSD + handle = dlopen(sopath, RTLD_LAZY | RTLD_GLOBAL); +#else + handle = dlopen(sopath, RTLD_LAZY); +#endif + + if (handle == NULL) { + logFmsg(3, "Unable to dlopen() shlib %s: %s", + sopath, dlerror()); + exit(1); + } else { + logFmsg(0, "Loaded %s", sopath); + } + + + lib->fn = strFcopy(shlib); + lib->handle = handle; + + lib->next = dlGlibs; + dlGlibs = lib; + + return STATUS_OK; +} + +void *dlFget_addr(const char *name) +{ + void *sym; + dlTmap *map; + dlTlib *l; + +#if defined(SOLARIS)||defined(DARWIN) + void *ghandle; +#endif + +#if defined(SOLARIS)||defined(DARWIN) +#ifdef SOLARIS + sym = dlsym(RTLD_DEFAULT, name); +#else /* darwin */ + ghandle = dlopen(NULL, 0); + sym = dlsym(ghandle, name); +#endif +#else + sym = dlsym(NULL, name); +#endif + + if (sym == NULL) { + char buf[64]; + + snprintf(buf, sizeof(buf), "_%s", name); + +#if defined(SOLARIS)||defined(DARWIN) +#ifdef SOLARIS + sym = dlsym(RTLD_DEFAULT, buf); + +#else /* darwin */ + sym = dlsym(ghandle, buf); +#endif +#else + sym = dlsym(NULL, buf); +#endif + } + /**** Try the loaded libraries ****/ + + for (l = dlGlibs; l != NULL; l = l->next) { + sym = dlsym(l->handle, name); + + /* + * Also required for OPENBSD but we dropped support for that anyways + */ +#ifdef DARWIN + if (sym == NULL) { + char buf[64]; + + snprintf(buf, sizeof(buf), "_%s", name); + sym = dlsym(l->handle, buf); + } +#endif + if (sym != NULL) + break; + } + + if (sym == NULL) { + logFmsg(1, "Failed to map symbol %s.", name); + return NULL; + } + /* + * We've found the symbol but it wasn't in the map cache, so we're going + * to add it. + */ + + map = (dlTmap *) malloc(sizeof(dlTmap)); + map->addr = sym; + strcpy(map->symbol, name); + map->opts = NULL; + + dlFmap_append(&dlGmap, map); + + return sym; +} diff --git a/mk4/continuity/cont/mmc.c b/mk4/continuity/cont/mmc.c new file mode 100644 index 0000000..7bb8315 --- /dev/null +++ b/mk4/continuity/cont/mmc.c @@ -0,0 +1,452 @@ +/* $Header: /san01/cvs/ashpool/csrc/continuity/cont/mmc.c,v 1.6 2004/03/18 15:04:15 aleigh Exp $ */ +/* + * Copyright (c) 1994, 2004 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Disclosure, copying, distribution, or transmission of this code without + * express permission is prohibited. + */ + + +#include "continuity.h" +#include "mecha.h" + +#ifdef HAVE_MMAP +#include +#endif /* HAVE_MMAP */ + +/* Defines. */ +#ifndef DEFAULT_EXPIRE_AGE +#define DEFAULT_EXPIRE_AGE 600 +#endif +#ifndef DESIRED_FREE_COUNT +#define DESIRED_FREE_COUNT 100 +#endif +#ifndef DESIRED_MAX_MAPPED_FILES +#define DESIRED_MAX_MAPPED_FILES 2000 +#endif +#ifndef INITIAL_HASH_SIZE +#define INITIAL_HASH_SIZE (1 << 10) +#endif + +#define max(a,b) ((a)>(b)?(a):(b)) +#define min(a,b) ((a)<(b)?(a):(b)) + + +/* The Map struct. */ +typedef struct MapStruct { + ino_t ino; + dev_t dev; + off_t size; + time_t ctime; + int refcount; + time_t reftime; + void *addr; + unsigned int hash; + int hash_idx; + struct MapStruct *next; +} Map; + +static Map *maps = (Map *) 0; +static Map *free_maps = (Map *) 0; +static int alloc_count = 0, map_count = 0, free_count = 0; +static Map **hash_table = (Map **) 0; +static int hash_size; +static unsigned int hash_mask; +static time_t expire_age = DEFAULT_EXPIRE_AGE; + +static void really_unmap(Map ** mm); +static int check_hash_size(void); +static int add_hash(Map * m); +static Map *find_hash(ino_t ino, dev_t dev, off_t size, time_t stat_ctime); +static unsigned int hash(ino_t ino, dev_t dev, off_t size, + time_t stat_ctime); + +int mmcFinit(void) +{ + pthread_t ignored; + + pthread_create(&ignored, NULL, (void *(*)(void *)) mmcFcleanup_thr, + NULL); + + return STATUS_OK; +} + +void *mmcFmap(const char *filename, struct stat *sbP, struct timeval *nowP) +{ + time_t now; + struct stat sb; + Map *m; + int fd; + + /* Stat the file, if necessary. */ + if (sbP != (struct stat *) 0) + sb = *sbP; + else { + if (stat(filename, &sb) != 0) { + logFmsgid(1, "CON", 12, filename, errno); + return NULL; + } + } + + /* Get the current time, if necessary. */ + if (nowP != (struct timeval *) 0) + now = nowP->tv_sec; + else + now = time((time_t *) 0); + + /* See if we have it mapped already, via the hash table. */ + if (check_hash_size() < 0) { + logFmsgid(1, "CON", 13, "mmc: check_hash_size() failed."); + return NULL; + } + m = find_hash(sb.st_ino, sb.st_dev, sb.st_size, sb.st_ctime); + if (m != (Map *) 0) { + /* Yep. Just return the existing map */ + ++m->refcount; + m->reftime = now; + return m->addr; + } + /* Open the file. */ + fd = open(filename, O_RDONLY); + if (fd < 0) { + logFmsgid(1, "CON", 14, filename, errno); + return NULL; + } + + /* don't keep this fd open on fork() */ + fleFset_close_exec(fd); + + /* Find a free Map entry or make a new one. */ + if (free_maps != (Map *) 0) { + m = free_maps; + free_maps = m->next; + --free_count; + } else { + m = (Map *) malloc(sizeof(Map)); + if (m == (Map *) 0) { + (void) close(fd); + logFmsgid(1, "CON", 15, "mmc map creation"); + return NULL; + } + ++alloc_count; + } + + /* Fill in the Map entry. */ + m->ino = sb.st_ino; + m->dev = sb.st_dev; + m->size = sb.st_size; + m->ctime = sb.st_ctime; + m->refcount = 1; + m->reftime = now; + + /* + * Avoid doing anything for zero-length files; some systems don't like * + * to mmap them, other systems dislike mallocing zero bytes. + */ + if (m->size == 0) + m->addr = (void *) 1; /* arbitrary non-NULL address */ + else { +#ifdef HAVE_MMAP + /* Map the file into memory. */ + m->addr = mmap(0, m->size, PROT_READ, MAP_SHARED, fd, 0); + if (m->addr == MAP_FAILED) { + logFmsgid(1, "CON", 16, errno, "mmc"); + (void) close(fd); + free((void *) m); + --alloc_count; + return NULL; + } +#else /* HAVE_MMAP */ + /* Read the file into memory. */ + m->addr = (void *) malloc(m->size); + if (m->addr == NULL) { + logFmsgid(1, "CON", 15, "mmc: file store"); + (void) close(fd); + free((void *) m); + --alloc_count; + return NULL; + } + if (read(fd, m->addr, m->size) != m->size) { + logFmsgid(1, "CON", 17, errno, "mmcFmap"); + (void) close(fd); + free((void *) m); + --alloc_count; + return NULL; + } +#endif /* HAVE_MMAP */ + } + (void) close(fd); + + /* Put the Map into the hash table. */ + if (add_hash(m) < 0) { + logFmsgid(1, "CON", 13, "mmc: add_hash() failure."); + free((void *) m); + --alloc_count; + return (void *) 0; + } + /* Put the Map on the active list. */ + m->next = maps; + maps = m; + ++map_count; + + /* And return the address. */ + return m->addr; +} + + +void mmc_unmap(void *addr, struct stat *sbP, struct timeval *nowP) +{ + Map *m = (Map *) 0; + + /* Find the Map entry for this address. First try a hash. */ + if (sbP != (struct stat *) 0) { + m = find_hash(sbP->st_ino, sbP->st_dev, sbP->st_size, + sbP->st_ctime); + if (m != (Map *) 0 && m->addr != addr) + m = (Map *) 0; + } + /* If that didn't work, try a full search. */ + if (m == (Map *) 0) + for (m = maps; m != (Map *) 0; m = m->next) + if (m->addr == addr) + break; + if (m == (Map *) 0) + logFmsgid(1, "CON", 13, "mmcFunmap: Unable to find entry."); + else if (m->refcount <= 0) + logFmsgid(1, "CON", 13, "mmcFunmap: Reference was <=0"); + else { + --m->refcount; + if (nowP != (struct timeval *) 0) + m->reftime = nowP->tv_sec; + else + m->reftime = time((time_t *) 0); + } +} + + +void mmcFcleanup(void) +{ + time_t now; + Map **mm; + Map *m; + + /* Get the current time, if necessary. */ + now = time((time_t *) 0); + + /* Really unmap any unreferenced entries older than the age limit. */ + for (mm = &maps; *mm != (Map *) 0;) { + m = *mm; + if (m->refcount == 0 && now - m->reftime >= expire_age) + really_unmap(mm); + else + mm = &(*mm)->next; + } + + /* If there are still too many (or too few) maps, adjust the age limit. */ + if (map_count > DESIRED_MAX_MAPPED_FILES) + expire_age = max((expire_age * 2) / 3, DEFAULT_EXPIRE_AGE / 10); + else if (map_count < DESIRED_MAX_MAPPED_FILES / 2) + expire_age = min((expire_age * 5) / 4, DEFAULT_EXPIRE_AGE * 3); + + /* Really free excess blocks on the free list. */ + while (free_count > DESIRED_FREE_COUNT) { + m = free_maps; + free_maps = m->next; + --free_count; + free((void *) m); + --alloc_count; + } +} + +void mmcFcleanup_thr(void) +{ + while (1) { + mmcFcleanup(); + thrFsleep(60000); + } +} + +static void really_unmap(Map ** mm) +{ + Map *m; + + m = *mm; + if (m->size != 0) { +#ifdef HAVE_MMAP + if (munmap(m->addr, m->size) < 0) + logFmsgid(1, "CON", 18, errno, "mmc"); +#else /* HAVE_MMAP */ + free((void *) m->addr); +#endif /* HAVE_MMAP */ + } + /* And move the Map to the free list. */ + *mm = m->next; + --map_count; + m->next = free_maps; + free_maps = m; + ++free_count; + /* + * This will sometimes break hash chains, but that's harmless; the * + * unmapping code that searches the hash table knows to keep searching. + */ + hash_table[m->hash_idx] = (Map *) 0; +} + + +void mmc_destroy(void) +{ + Map *m; + + while (maps != (Map *) 0) + really_unmap(&maps); + while (free_maps != (Map *) 0) { + m = free_maps; + free_maps = m->next; + --free_count; + free((void *) m); + --alloc_count; + } +} + +/* Make sure the hash table is big enough. */ +static int check_hash_size(void) +{ + int i; + Map *m; + + /* Are we just starting out? */ + if (hash_table == (Map **) 0) { + hash_size = INITIAL_HASH_SIZE; + hash_mask = hash_size - 1; + } + /* Is it at least three times bigger than the number of entries? */ + else if (hash_size >= map_count * 3) + return 0; + else { + /* No, got to expand. */ + free((void *) hash_table); + /* Double the hash size until it's big enough. */ + do { + hash_size = hash_size << 1; + } + while (hash_size < map_count * 6); + hash_mask = hash_size - 1; + } + /* Make the new table. */ + hash_table = (Map **) malloc(hash_size * sizeof(Map *)); + if (hash_table == (Map **) 0) + return -1; + /* Clear it. */ + for (i = 0; i < hash_size; ++i) + hash_table[i] = (Map *) 0; + /* And rehash all entries. */ + for (m = maps; m != (Map *) 0; m = m->next) + if (add_hash(m) < 0) + return -1; + return 0; +} + + +static int add_hash(Map * m) +{ + unsigned int h, he, i; + + h = hash(m->ino, m->dev, m->size, m->ctime); + he = (h + hash_size - 1) & hash_mask; + for (i = h;; i = (i + 1) & hash_mask) { + if (hash_table[i] == (Map *) 0) { + hash_table[i] = m; + m->hash = h; + m->hash_idx = i; + return 0; + } + if (i == he) + break; + } + return -1; +} + + +static Map *find_hash(ino_t ino, dev_t dev, off_t size, time_t stat_ctime) +{ + unsigned int h, he, i; + Map *m; + + h = hash(ino, dev, size, stat_ctime); + he = (h + hash_size - 1) & hash_mask; + for (i = h;; i = (i + 1) & hash_mask) { + m = hash_table[i]; + if (m == (Map *) 0) + break; + if (m->hash == h && m->ino == ino && m->dev == dev && + m->size == size && m->ctime == stat_ctime) + return m; + if (i == he) + break; + } + return (Map *) 0; +} + + +static unsigned int hash(ino_t ino, dev_t dev, off_t size, + time_t stat_ctime) +{ + unsigned int h = 177573; + + h ^= ino; + h += h << 5; + h ^= dev; + h += h << 5; + h ^= size; + h += h << 5; + h ^= stat_ctime; + + return h & hash_mask; +} + + +/* + * Stolen from VI + */ + +int mmcFopen(char *filename, char **buf, int *len) +{ + int fd; + void *map; + struct stat sbuf; + + if ((fd = open(filename, O_RDONLY)) == -1) + return (-errno); + + fleFset_close_exec(fd); + + if (fstat(fd, &sbuf) == -1) { + close(fd); + return (-1); + } + if ((map = + mmap(0, sbuf.st_size, PROT_READ, MAP_PRIVATE, fd, + 0)) == MAP_FAILED) { + close(fd); + return 0; + } + close(fd); + + *buf = map; + *len = sbuf.st_size; + + return 0; +} + +/* Stolen from VI */ + +int mmcFclose(char *buf, int len) +{ + if (munmap(buf, len) == -1) + return (-1); + return (0); +} diff --git a/mk4/continuity/cont/tas.c b/mk4/continuity/cont/tas.c new file mode 100644 index 0000000..b51ee4d --- /dev/null +++ b/mk4/continuity/cont/tas.c @@ -0,0 +1,265 @@ +/* $Header: /san01/cvs/ashpool/csrc/continuity/cont/tas.c,v 1.7 2004/05/14 06:20:32 eric Exp $ */ + +/* Copyright (c) 1994, 2004 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH + * The copyright notice above does not evidence any + * actual or intended publication of such source code. + * + * Disclosure, copying, distribution, or transmission of + * this code without express permission is prohibited. + */ + +/* + * Runtime Statistics Alex Leigh, 1995, 2000 $Id: stat.c,v 1.1 2000/04/08 + * 17:35:55 aleigh Exp $ + */ + +#include "csys.h" + +#define TA_STAT_STRLEN 32 + +#define TA_STAT_INT 1 +#define TA_STAT_UINT 2 +#define TA_STAT_CHAR 3 + +struct tasSstat { + unsigned int tas_ctime; + struct tasSstat *tas_next; + + char tas_module[TA_STAT_STRLEN]; + int tas_instance; + char tas_name[TA_STAT_STRLEN]; + int tas_type; + char tas_class[TA_STAT_STRLEN]; + unsigned char tas_flags; + void *tas_data; + size_t tas_data_size; + unsigned int tas_ndata; +}; + +struct tasSctl { + struct tasSstat *chain; +}; + +#include "continuity.h" +#include "mecha.h" + +tasTctl *tasGctl; +pthread_mutex_t tasMctl = PTHREAD_MUTEX_INITIALIZER; + +int tasFinit(void) +{ + tasGctl = (tasTctl *) malloc(sizeof(tasTctl)); + bzero(tasGctl, sizeof(tasTctl)); + return 0; +} + +tasTstat *tasFget_chain(void) +{ + return tasGctl->chain; +} + +tasTstat *tasFcreate(const char *module, int instance, const char *name, + const char *class, unsigned char type, + unsigned long ndata, unsigned char flag) +{ + tasTstat *tas; + int size; + + tas = (tasTstat *) malloc(sizeof(tasTstat)); + bzero(tas, sizeof(tasTstat)); + + strncpy(tas->tas_name, name, TA_STAT_STRLEN); + strncpy(tas->tas_module, module, TA_STAT_STRLEN); + strncpy(tas->tas_class, class, TA_STAT_STRLEN); + + tas->tas_instance = instance; + tas->tas_type = type; + tas->tas_flags = flag; + tas->tas_ndata = ndata; + + switch (type) { + case TA_STAT_INT: + size = ndata * sizeof(int32_t); + tas->tas_data = (int32_t *) malloc(size); + bzero(tas->tas_data, size); + break; + + case TA_STAT_UINT: + size = ndata * sizeof(uint32_t); + tas->tas_data = (uint32_t *) malloc(size); + bzero(tas->tas_data, size); + break; + + case TA_STAT_CHAR: + tas->tas_data = (char *) malloc(ndata); + bzero(tas->tas_data, ndata); + break; + } + + if (tas->tas_data == NULL) { + free(tas); + return NULL; + } + return tas; + +} + + +tasTstat *tasFstat_lookup(tasTctl * ctl, const char *module, + int instance, const char *name) +{ + tasTstat *p; + int match = 1; + + if (ctl->chain == NULL) + return NULL; + + p = ctl->chain; + + while (1) { + match = 1; + + if (module != NULL) + if (strcmp(p->tas_module, module) != 0) + match = 0; + + if (instance != -1) + if (p->tas_instance != instance) + match = 0; + + if (strcmp(p->tas_name, name) != 0) + match = 0; + + if (match == 1) + return p; + + if (p->tas_next == NULL) + break; + p = p->tas_next; + } + return NULL; +} + +tasTstat *tasFlookup(char *module, int instance, char *name) +{ + return tasFstat_lookup(tasGctl, module, instance, name); +} + + +void tasFstat_free(tasTstat * statp) +{ + + if (statp->tas_data != NULL) + free(statp->tas_data); + free(statp); + + return; +} + +void tasFstat_install(tasTstat * statp) +{ + pthread_mutex_lock(&tasMctl); + statp->tas_next = tasGctl->chain; + tasGctl->chain = statp; + pthread_mutex_unlock(&tasMctl); +} + +void tasFstat_delete(tasTstat * statp) +{ + tasTstat *p; + + pthread_mutex_lock(&tasMctl); + + if (tasGctl->chain == NULL) { + pthread_mutex_unlock(&tasMctl); + tasFstat_free(statp); + return; + } + if (tasGctl->chain == statp) { + tasGctl->chain = statp->tas_next; + pthread_mutex_unlock(&tasMctl); + tasFstat_free(statp); + return; + } + p = tasGctl->chain; + while (1) { + if (p->tas_next == statp) { + p->tas_next = statp->tas_next; + pthread_mutex_unlock(&tasMctl); + tasFstat_free(statp); + return; + } + if (p->tas_next == NULL) + break; + p = p->tas_next; + } + + pthread_mutex_unlock(&tasMctl); + tasFstat_free(statp); + return; +} + +int tasFstat_counter_add(const char *module, int instance, + const char *name, unsigned int value) +{ + tasTstat *p; + unsigned int *ip; + + p = tasFstat_lookup(tasGctl, module, instance, name); + if (p == NULL) { + p = tasFcreate(module, instance, name, "cnt", TA_STAT_UINT, 1, + (unsigned char) NULL); + ip = p->tas_data; + *ip = value; + tasFstat_install(p); + return value; + } + ip = (unsigned int *) p->tas_data; + *ip += value; + + return *ip; +} + +int tasFstat_counter_sub(const char *module, int instance, const char *name, + unsigned int value) +{ + tasTstat *p; + unsigned int *ip; + + p = tasFstat_lookup(tasGctl, module, instance, name); + if (p == NULL) { + p = tasFcreate(module, instance, name, "cnt", TA_STAT_UINT, 1, + (unsigned char) NULL); + ip = p->tas_data; + *ip = value; + tasFstat_install(p); + return value; + } + ip = (unsigned int *) p->tas_data; + *ip -= value; + + return *ip; +} + +int tasFstat_set(const char *module, int instance, const char *name, + unsigned int value) +{ + tasTstat *p; + unsigned int *ip; + + p = tasFstat_lookup(tasGctl, module, instance, name); + if (p == NULL) { + p = tasFcreate(module, instance, name, "cnt", TA_STAT_UINT, 1, + (unsigned char) NULL); + ip = p->tas_data; + *ip = value; + tasFstat_install(p); + return value; + } + ip = (unsigned int *) p->tas_data; + *ip = value; + + return *ip; +} diff --git a/mk4/continuity/cont/xfr.c b/mk4/continuity/cont/xfr.c new file mode 100644 index 0000000..9a1179c --- /dev/null +++ b/mk4/continuity/cont/xfr.c @@ -0,0 +1,146 @@ +/* + * $Header: /datum01/src/continuity/src/xfer.c,v 1.19.2.3 2002/09/16 15:15:31 + * aleigh Exp $ + */ + +/* + * Copyright (c) 1994, 2004 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Disclosure, copying, distribution, or transmission of this code without + * express permission is prohibited. + */ + +#include "continuity.h" +#include "mecha.h" + +#define CHUNK_SZ 10240 + +int xfrFfile(netTconn * conn, const char *path) +{ +#ifdef _LP64 + struct stat64 s; +#else + struct stat s; +#endif + int ret; + + ret = stat(path, &s); + + if (ret == -1) + return -1; + + ret = xfrFmmap(conn, path, &s); + return ret; + +} + +int xfrFis_extant(char *path) +{ + int ret; + +#ifdef _LP64 + struct stat64 s; +#else + struct stat s; +#endif + + ret = stat(path, &s); + + if (ret == 0) + return 1; + + return 0; +} + +/* + * -> mmap contains the mapping -> len the length + */ +int xfrFmmap(netTconn * conn, const char *fname, +#ifndef _LP64 + struct stat *sb +#else + struct stat64 *sb +#endif + ) +{ + char *map; +#ifdef DARWIN + size_t written = 0, ret; + size_t towrite = sb->st_size; +#else + off_t written = 0, ret; +#endif + + map = (char *) mmcFmap(fname, (struct stat *) sb, NULL); + + if (map == NULL) + return STATUS_ERROR; + + while (1) { +#ifdef DARWIN + if ((towrite - written) > CHUNK_SZ) { +#else + if ((sb->st_size - written) > CHUNK_SZ) { +#endif + ret = netFconn_write(conn, map + written, CHUNK_SZ); + } else { +#ifdef DARWIN + ret = netFconn_write(conn, map + written, (towrite - written)); +#else + ret = + netFconn_write(conn, map + written, + (sb->st_size - written)); +#endif + } + + if (ret == -1) { + return STATUS_ERROR; + } else { + written += ret; +#ifdef DARWIN + if (written >= towrite) +#else + if (written >= sb->st_size) +#endif + break; + } + } + return written; +} + +int xfrFmemory(netTconn * conn, char *p, size_t len) +{ + size_t written = 0; + char *wp; + ssize_t ret; + + wp = p; + + while (1) { + if (len - written < CHUNK_SZ) { + ret = netFconn_write(conn, wp, len - written); + + if (ret == -1) { + return written; + } + written += ret; + wp += ret; + } else { + ret = netFconn_write(conn, wp, CHUNK_SZ); + + if (ret == -1) { + return written; + } + written += ret; + wp += ret; + } + if (written == len) + break; + } + + return written; +} diff --git a/mk4/continuity/include/.cvsignore b/mk4/continuity/include/.cvsignore new file mode 100644 index 0000000..424c745 --- /dev/null +++ b/mk4/continuity/include/.cvsignore @@ -0,0 +1 @@ +*.h diff --git a/mk4/continuity/include/CVS/Entries b/mk4/continuity/include/CVS/Entries new file mode 100644 index 0000000..73ea853 --- /dev/null +++ b/mk4/continuity/include/CVS/Entries @@ -0,0 +1,8 @@ +/.cvsignore/1.1/Thu Mar 11 01:11:48 2004//Tmk4_mod6_rc2 +/config.h.in/1.10/Thu Jun 3 14:40:29 2004//Tmk4_mod6_rc2 +/continuity.h/1.75/Wed Jun 30 15:02:17 2004//Tmk4_mod6_rc2 +/csys.h/1.23/Thu May 20 20:09:46 2004//Tmk4_mod6_rc2 +/cwin32.h/1.3/Thu Dec 11 17:23:06 2003//Tmk4_mod6_rc2 +/mecha.h/1.134/Fri May 14 18:33:19 2004//Tmk4_mod6_rc2 +/mecha_dep.h/1.6/Tue Mar 16 02:30:46 2004//Tmk4_mod6_rc2 +D diff --git a/mk4/continuity/include/CVS/Repository b/mk4/continuity/include/CVS/Repository new file mode 100644 index 0000000..e5bd4c0 --- /dev/null +++ b/mk4/continuity/include/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/continuity/include diff --git a/mk4/continuity/include/CVS/Root b/mk4/continuity/include/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/continuity/include/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/continuity/include/CVS/Tag b/mk4/continuity/include/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/continuity/include/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/continuity/include/config.h.in b/mk4/continuity/include/config.h.in new file mode 100644 index 0000000..677c64d --- /dev/null +++ b/mk4/continuity/include/config.h.in @@ -0,0 +1,151 @@ +/* include/config.h.in. Generated from configure.in by autoheader. */ + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +#undef HAVE_DIRENT_H + +/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ +#undef HAVE_DOPRNT + +/* Define to 1 if you have the `getloadavg' function. */ +#undef HAVE_GETLOADAVG + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_KSTAT_H + +/* Define to 1 if you have the `aio' library (-laio). */ +#undef HAVE_LIBAIO + +/* Define to 1 if you have the `c' library (-lc). */ +#undef HAVE_LIBC + +/* Define to 1 if you have the `c_r' library (-lc_r). */ +#undef HAVE_LIBC_R + +/* Define to 1 if you have the `dl' library (-ldl). */ +#undef HAVE_LIBDL + +/* Define to 1 if you have the header file. */ +#undef HAVE_LIBGEN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LIBINTL_H + +/* Define to 1 if you have the `kstat' library (-lkstat). */ +#undef HAVE_LIBKSTAT + +/* Define to 1 if you have the `LiS' library (-lLiS). */ +#undef HAVE_LIBLIS + +/* Define to 1 if you have the `m' library (-lm). */ +#undef HAVE_LIBM + +/* Define to 1 if you have the `mtmalloc' library (-lmtmalloc). */ +#undef HAVE_LIBMTMALLOC + +/* Define to 1 if you have the `nsl' library (-lnsl). */ +#undef HAVE_LIBNSL + +/* Define to 1 if you have the `pthread' library (-lpthread). */ +#undef HAVE_LIBPTHREAD + +/* Define to 1 if you have the `resolv' library (-lresolv). */ +#undef HAVE_LIBRESOLV + +/* Define to 1 if you have the `socket' library (-lsocket). */ +#undef HAVE_LIBSOCKET + +/* Define to 1 if you have the `thread' library (-lthread). */ +#undef HAVE_LIBTHREAD + +/* Define to 1 if you have the header file. */ +#undef HAVE_MALLOC_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the `mmap' function. */ +#undef HAVE_MMAP + +/* Define to 1 if you have the header file, and it defines `DIR'. */ +#undef HAVE_NDIR_H + +/* Define to 1 if you have the `on_exit' function. */ +#undef HAVE_ON_EXIT + +/* Define to 1 if you have the `prctl' function. */ +#undef HAVE_PRCTL + +/* Define to 1 if you have the `pthread_rwlock_init' function. */ +#undef HAVE_PTHREAD_RWLOCK_INIT + +/* Define to 1 if you have the `rand_r' function. */ +#undef HAVE_RAND_R + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STROPTS_H + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +#undef HAVE_SYS_DIR_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_DLPI_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_LOCK_H + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +#undef HAVE_SYS_NDIR_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the `vprintf' function. */ +#undef HAVE_VPRINTF + +/* 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 + +/* Define as the return type of signal handlers (`int' or `void'). */ +#undef RETSIGTYPE + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define the real type of socklen_t */ +#undef socklen_t diff --git a/mk4/continuity/include/continuity.h b/mk4/continuity/include/continuity.h new file mode 100644 index 0000000..f0db063 --- /dev/null +++ b/mk4/continuity/include/continuity.h @@ -0,0 +1,144 @@ +/* Copyright (c) 2001, 2004 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH + * The copyright notice above does not evidence any + * actual or intended publication of such source code. + * + * Use, disclosure, copying, distribution, or transmission of + * this code without express permission is prohibited. + */ + +#ifndef CONTINUITY_H +#define CONTINUITY_H + +/* #define CONT_PROFILE */ + +#include "csys.h" +#include "mecha.h" + +#define BUILD_REV "mk4 mod6 rc3" +#define BUILD_LEV_LEN 12 +//#define BUILD_LEV_LEN 8 + +#ifdef PRODUCTION +#define PROD_NOTICE "Production" +#else +#define PROD_NOTICE "Development" +#endif + +#ifdef ONESHOT +#define BUILDMODE "One-Shot." +#else +#define BUILDMODE "Multi-Shot." +#endif + +#ifdef TA_64BIT +#define BUILD_STRING "Continuity Enterprise Edition - " BUILD_REV " - 64bit " PROD_NOTICE ", " BUILDMODE +#else +#define BUILD_STRING "Continuity Enterprise Edition - " BUILD_REV " - 32bit " PROD_NOTICE ", " BUILDMODE +#endif + +#define TA_LOG_OK 0 +#define TA_LOG_WARN 1 +#define TA_LOG_ERR 2 +#define TA_LOG_DIAG 3 +#define TA_LOG_AUX 4 + +#define STATUS_OK 1 +#define STATUS_ERROR 2 +#define STATUS_PROCEED 3 +#define STATUS_EXIT 4 +#define STATUS_RESTART 5 + +#ifdef __cplusplus +extern "C" { +#endif + +typedef int(*cont_handler)(void *, lstTset *); + +/* dis.c */ +typedef struct disSlistener disTlistener; + +int disFwait_for_startup(disTlistener * listener); +int disFsetup(disTlistener * listener); +int disFlisten_loop(disTlistener * listener); + +int ipv4_dispatcher(void *p, lstTset *opts); + int ipv4_openport(MECHA_UNUSED_ARGUMENT void *p, lstTset * opts); + + + /* continuity.c */ + const xmlTtag *conFget_config_basetag(void); + void conFwait_for_init (void); + const char *conFget_build (void); + void intr_handler (int sigraised); + int set_userid(void *p, lstTset *opts); + int conFsocketstash_update(int sd, int idx); + int conFsocketstash_find(int idx); + +/* tas.c */ +#define TA_STAT_STRLEN 32 +#define TA_STAT_INT 1 +#define TA_STAT_UINT 2 +#define TA_STAT_CHAR 3 +typedef struct tasSstat tasTstat; +typedef struct tasSctl tasTctl; +int tasFinit (void); +tasTstat *tasFget_chain (void); +tasTstat *tasFcreate (const char *module, int instance, const char *name, + const char *class, unsigned char type, + unsigned long ndata, unsigned char flag); +tasTstat *tasFstat_lookup (tasTctl * ctl, const char *module, + int instance, const char *name); +tasTstat *tasFlookup (char *module, int instance, char *name); +void tasFstat_free (tasTstat * statp); +void tasFstat_install (tasTstat * statp); +void tasFstat_delete (tasTstat * statp); +int tasFstat_counter_add (const char *module, int instance, const char *name, + unsigned int value); +int tasFstat_counter_sub (const char *module, int instance, const char *name, + unsigned int value); +int tasFstat_set (const char *module, int instance, const char *name, unsigned int value); + +/* xfr.c */ +int xfrFfile(netTconn *conn, const char *path); +int xfrFis_extant(char *path); +int xfrFmmap(netTconn *conn, const char *fname, +#ifndef _LP64 + struct stat *sb +#else + struct stat64 * sb +#endif +) ; +int xfrFmemory(netTconn *conn, char *p, size_t len); + +/* mmc.c */ +int mmcFclose(char *buf, int len); +int mmcFopen(char *filename, char **buf, int *len); +void* mmcFmap(const char* filename, struct stat* sbP, struct timeval* nowP ); +int mmcFinit(void); +void mmcFcleanup(void); +void mmcFcleanup_thr(void); +void mmc_unmap( void* addr, struct stat* sbP, struct timeval* nowP ); +void mmc_destroy( void ); + +/* dl.c */ +typedef struct dlSmap dlTmap; +typedef struct dlScategory dlTcategory; +typedef struct dlSentry dlTentry; + +void *dlFget_addr(const char *name); +int dlFpipeline_getid(const char *pipeline); +int dlFpipeline_exec(void *payload, int pipeline, const char *limit_name, const char *limit_value); +/* undoc */ +int dlFload_library (const char *shlib); +int dlFload_config(void); +int dlFop_show_dl_loads(netTconn *conn, int argc, char **argv); +int dlFop_show_dl_symbols(netTconn *conn, int argc, char **argv); +/* end undoc */ + +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/mk4/continuity/include/csys.h b/mk4/continuity/include/csys.h new file mode 100644 index 0000000..c1c5a6f --- /dev/null +++ b/mk4/continuity/include/csys.h @@ -0,0 +1,141 @@ +/* Copyright (c) 2001, 2004 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH + * The copyright notice above does not evidence any + * actual or intended publication of such source code. + * + * Use, disclosure, copying, distribution, or transmission of + * this code without express permission is prohibited. + */ + +#ifndef CSYS_H +#define CSYS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef WIN32 +#include "cwin32.h" +#else + +/* It is important that this comes first, because on Solaris + it's required to make 64-bit work properly. */ +#include + +#include "config.h" + +/* If we don't have pthread_rwlock_init() then we probably don't have + * pthread_rwlock() support. This is true on old OSX systems that we + * basically don't support, but also Solaris 2.6; rwlocks weren't implemented + * until Solaris 7 + */ + +#ifndef HAVE_PTHREAD_RWLOCK_INIT +#define pthread_rwlock_t pthread_mutex_t +#define PTHREAD_RWLOCK_INITIALIZER PTHREAD_MUTEX_INITIALIZER +#define pthread_rwlock_init pthread_mutex_init +#define pthread_rwlock_rdlock pthread_mutex_lock +#define pthread_rwlock_wrlock pthread_mutex_lock +#define pthread_rwlock_unlock pthread_mutex_unlock +#define pthread_rwlock_destory pthread_mutex_destroy +#endif + +#include +#include +#include + +/* Colliding namespace on OSX with Tcl */ +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_SYS_LOCK_H +#include +#endif + +#include + +#ifdef HAVE_STRING_H +#include +#endif + +#ifdef HAVE_STRINGS_H +#include +#endif + +#include +#include +#include +#include + +#ifdef HAVE_STDINT_H +#ifndef __USE_MISC +#define __USE_MISC +#endif +#include /* LINUX */ +#endif + +#ifdef LINUX +#include /* TCP_NODELAY */ +#include + +/* There is something wonky with this on my platform; + it's not included in unistd.h unless __USE_BSD or something + bizarre is defined, so I am just putting it here to get the + compiler to shut up. */ +extern int gethostname (char *__name, size_t __len); + +#endif + +#ifdef FREEBSD +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef SOLARIS +#include // Required on 2.6 for MAXDNAME +#include +#include +#include +#endif + +#ifdef DARWIN +#include +#endif + +#if defined(SOLARIS) +#define _Bool char +#define bool _Bool +#define true 1 +#define false 0 +#define __bool_true_false_are_defined 1 +#endif + +#if defined(LINUX) || defined(DARWIN) +#include +#endif + + +#endif /* WIN32 */ + +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/mk4/continuity/include/cwin32.h b/mk4/continuity/include/cwin32.h new file mode 100644 index 0000000..b1dd7c2 --- /dev/null +++ b/mk4/continuity/include/cwin32.h @@ -0,0 +1,41 @@ +/* Copyright (c) 1994,2003 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH + * The copyright notice above does not evidence any + * actual or intended publication of such source code. + * + * Use, disclosure, copying, distribution, or transmission of + * this code without express permission is prohibited. + */ + +#ifndef CWIN_H +#define CWIN_H + +#include +#include +#include +#include +#include +#include + +typedef unsigned int uint32_t; +typedef int int32_t; +typedef unsigned int time_t; +typedef unsigned short uint16_t; +typedef short int16_t; +typedef int ssize_t; +typedef unsigned char uint8_t; +typedef char int8_t; + +#define assert +#define vsnprintf _vsnprintf +#define snprintf _snprintf + +struct timezone { + int tz_minuteswest; + int tz_dsttime; +}; + +int gettimeofday(struct timeval * time_Info, struct timezone * timezone_Info); + +#endif diff --git a/mk4/continuity/include/mecha.h b/mk4/continuity/include/mecha.h new file mode 100644 index 0000000..5f5e8d8 --- /dev/null +++ b/mk4/continuity/include/mecha.h @@ -0,0 +1,586 @@ +/* $Id: mecha.h,v 1.134 2004/05/14 18:33:19 aleigh Exp $ */ + +/* Copyright (c) 2001, 2004 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH + * The copyright notice above does not evidence any + * actual or intended publication of such source code. + * + * Use, disclosure, copying, distribution, or transmission of + * this code without express permission is prohibited. + */ + +#ifndef MECHA_H +#define MECHA_H + +#include "csys.h" +#include "mecha_dep.h" /* Deprecated Interfaces */ + +#ifdef __GNUC__ +#define MECHA_UNUSED_ARGUMENT __attribute__((unused)) +#else +#define MECHA_UNUSED_ARGUMENT +#endif + +#ifdef __GNUC__ +#define MECHA_UNUSED __attribute__((unused)) +#else +#define MECHA_UNUSED +#endif + +#if !defined(TRUE) +#define TRUE 1 +#endif + +#if !defined(FALSE) +#define FALSE 0 +#endif + +typedef unsigned char BOOL; + +typedef void(*mecha_handler)(void *); + +void mecha_init(void); + +/* ast.c - Astronomical Functions */ +struct astSsunriset +{ + double length; /* 0-degree length of the day in hours */ + double rise; /* 0-degree rise time UT */ + double set; /* 0-degree set time UT */ + double zenith; /* Zenith time UT*/ + double status; /* Sun status */ + double civil_length; /* 6-degree length of day in hours*/ + double civil_start; /* 6-degree rise time UT */ + double civil_end; /* 6-degree set time UT */ + double civil_status; /* 6-degree sun status */ + double nautical_length; /* 12-degree length of day in hours */ + double nautical_start; /* 12-degree rise time UT */ + double nautical_end; /* 12-degree set time UT */ + double nautical_status; /* 12-degree sun status */ + double astro_length; /* 18-degree length of day in hours */ + double astro_start; /* 18-degree rise time UT */ + double astro_end; /* 18-degree set time UT */ + double astro_status; /* 18-degree sun status */ +}; +typedef struct astSsunriset astTsunriset; +void astFsunriset (astTsunriset * srs, int month, int day, int year, double lon, double lat); + +/* b64.c - Base64 Coder */ +int b64Fencode (unsigned char *bufin, unsigned int nbytes, char *bufcoded); +int b64Fdecode (const char *bufcoded, unsigned char *bufplain, int outbufsize); + +/* bsp.c - BSP Tree */ +typedef struct bspSnode bspTnode; + +int bspFadd (bspTnode * list, void *p, int high_key, int low_key); +void *bspFsearch (bspTnode * node, unsigned int x); +void bspFdestroy (bspTnode * node, void (*destructor) (void *)); +bspTnode *bspFinit (void); +void bspFbalance (bspTnode * node, unsigned int depth); + +/* undoc */ +unsigned int bspFcount (bspTnode * node); +void bspFsplit (bspTnode * node); +/* end undoc */ + +/* bus.c - Data bus */ +typedef struct busSbus busTbus; +busTbus *busFinit (void (*destructor) (void *)); +void busFfree (busTbus * bus); +int busFpush (busTbus * bus, void *data, size_t data_len); +int busFpull (busTbus * bus, void **data); + +/* crc.c - Cyclical Redundancy Check */ +uint32_t crcFcrc32 (const unsigned char *buf, unsigned len); + +/* dyn.c - Dynamic String BUffers */ +typedef struct dynSstring dynTstring; +dynTstring *dynFinit (void); +void dynFfree (dynTstring * ds); +size_t dynFappend (dynTstring * ds, const char *str, size_t len); +size_t dynFappend_string (dynTstring * ds, const dynTstring * src); +size_t dynFsappend (dynTstring * ds, const char *str); +size_t dynFappend_print (dynTstring * ds, const char *fmt, ...); +const char *dynFgetstr (const dynTstring * ds); +size_t dynFgetlen(const dynTstring *ds); +void dynFreset(dynTstring *ds); + +/* fle.c - File Operations */ +char *fleFload_file(const char *filename, size_t *len); +size_t fleFget_size(const char *filename); +int fleFset_close_exec (int fd); +void fleFpath_clean (char *pathname); +int fleFlock (const char *filename); +int fleFunlock (const char *filename); +int fleFsync_mem_to_file (char *filename, const char *memory, size_t len); +int fleFpath_simplify (const char *path, char *outpath, int len); +int fleFpath_combine (const char *path, int path_len, const char *relative, char *output, int output_len); +void fleFrotate(int count, const char *fn); +int fleFexist(const char *filename); + + + +/* hsh.c - Hashing & Hash Lists */ +typedef struct hshSiterator hshTiterator; +typedef struct hshSvoid_list hshTvoid_list; + +void hshFvoid_int_update(hshTvoid_list * list, const int key, void *data); +void hshFvoid_update(hshTvoid_list * list, const char *name, void *data); + +unsigned short int hshFraw_hash (const char *str, size_t len, + unsigned int buckets); +unsigned short int hshFraw_hashcode (const char *str, size_t len); +unsigned short int hshFhash (const char *str); +hshTvoid_list *hshFvoid_init (void (*destructor) (void *)); +hshTvoid_list *hshFvoid_int_init (void (*destructor) (void *)); +hshTvoid_list *hshFvoid_raw_init (void (*destructor) (void *), + void (*name_destructor) (void *), + int (name_comparator) (const void *s1, + const void *s2, + size_t len), + unsigned int buckets); +void hshFvoid_int_replace (hshTvoid_list * list, int key, void *data); +int hshFvoid_int_add (hshTvoid_list * list, int key, void *data); +void hshFvoid_replace (hshTvoid_list * list, const char *name, void *data); +int hshFvoid_add (hshTvoid_list * list, const char *name, void *data); +int hshFvoid_raw_add (hshTvoid_list * list, char *name, size_t name_len, + void *data, int replace); +void *hshFvoid_raw_find (hshTvoid_list * list, const char *name, + size_t name_len); +void *hshFvoid_find (hshTvoid_list * list, const char *name); +void *hshFvoid_int_find (hshTvoid_list * list, int key); + +int hshFvoid_contains (hshTvoid_list *list, const char *key); +int hshFvoid_int_contains (hshTvoid_list *list, int key); + +void hshFvoid_del (hshTvoid_list * list, const char *name); +void hshFvoid_int_del (hshTvoid_list * list, int key); +void hshFvoid_raw_del (hshTvoid_list * list, const char *name, + size_t name_len); +void *hshFvoid_remove (hshTvoid_list * list, const char *name); +void *hshFvoid_int_remove (hshTvoid_list * list, int key); +void * hshFvoid_raw_remove (hshTvoid_list * list, const char *name, size_t name_len); +void hshFvoid_destroy (hshTvoid_list *list); +void hshFvoid_free(hshTvoid_list *list); +hshTiterator *hshFiterator_init (hshTvoid_list * list); +int hshFiterator_next (hshTiterator * iterator); +void *hshFiterator_current_key (hshTiterator * iterator); +void *hshFiterator_current_value (hshTiterator * iterator); +void hshFiterator_free (hshTiterator * iterator); +void hshFiterator_reset (hshTiterator * iterator); +int hshFvoid_size (hshTvoid_list *list); +uint32_t hshFraw_hash32(const void *buf, size_t len, uint32_t buckets); +uint32_t hshFhash32(const char *str); +uint32_t hshFraw_hashcode32(const void *buf, size_t len); +void hshFvalue_destructor_set(hshTvoid_list *list, void (*destructor)(void *)); +/* nodoc */ +dynTstring *hshFdiag_output (hshTvoid_list *list); +/* end nodoc */ + +/* log.c - Message Logging */ +#define CONT_LOG_OK 0 +#define CONT_LOG_WARN 1 +#define CONT_LOG_ERROR 2 +#define CONT_LOG_DEBUG 3 + +#define logFmsg(...) logF_msg(__func__,__VA_ARGS__) + +void logF_msg (const char *func, int level, const char *m, ...); +void logFmsgid (int level, const char *module, int msg_id, ...); +void logFoutputfh_set(FILE *fh, int close_flag); +FILE *logFoutputfh_get(void); +int logFset_outputfile(const char *filename); +void logFset_rotatesize(size_t size); +void logFinit(void); + +/* lst.c - Linear Lists */ +typedef struct lstSset lstTset; +typedef struct lstSfield lstTfield; +lstTset *lstFset_init(void); +void lstFset_update (lstTset * set, const char *key, const char *value); +void lstFset_bupdate (lstTset * set, const char *key, size_t key_len, const char *value, size_t value_len); +/* undoc */ +lstTset *lstFset_create (const char *name); +size_t lstFset_get_vsize_cmp (lstTset * set, const char *key, + int (*cmp) (const char *s1, const char *s2)); +size_t lstFset_get_nsize_cmp (lstTset * set, const char *key, + int (*cmp) (const char *s1, const char *s2)); +/* end undoc */ +void lstFset_free (lstTset * set); +int lstFset_add (lstTset * set, const char *key, const char *value); +int lstFset_badd (lstTset * set, const char *key, size_t key_len, const char *value, size_t value_len); +int lstFset_nadd (lstTset * set, const char *key, int value); +/* return based on physical location */ +const char *lstFset_get_index (lstTset * set, int idx); +int lstFset_unique (lstTset * set, const char *key); +int lstFset_inique (lstTset * set, const char *key); +int lstFset_find (lstTset * set, const char *key); +int lstFset_ifind (lstTset * set, const char *key); +const char *lstFset_get (const lstTset * set, const char *key); +ssize_t lstFset_get_vsize (lstTset * set, const char *key); +ssize_t lstFset_get_nsize (lstTset * set, const char *key); +const char *lstFset_iget (lstTset * set, const char *key); +void lstFset_trunc (lstTset * set, int size); +void lstFset_delete (lstTset * set, int idx); +void lstFset_add_value (lstTset * set, int idx, const char *value); +void lstFset_delete_key (lstTset * set, const char *key); +void lstFset_idelete_key (lstTset * set, const char *key); +int lstFset_size (const lstTset * set); +void lstFset_merge (lstTset * high, const lstTset * low); +int lstFnth_find (const lstTset * list, int nth); +char *lstFset_pack (const lstTset * set, size_t * len); + +lstTset *lstFset_unpack (const char *pack); + +const char *lstFfield_value (const lstTfield *field); +int lstFfield_value_len (const lstTfield *field); + +const lstTfield *lstFset_get_field (lstTset *set, const char *key, int key_len); + +/* begin undoc */ +void lstFset_dump (char *pack); +int lstFpack (char *dest, char *src, int len, int class); +const char *lstFset_get_key_index (lstTset * set, int idx); +void lstFset_list_free (lstTset * sets); +lstTset *lstFset_list_find (lstTset ** sets, const char *name); +int lstFset_unique_cmp (lstTset * set, const char *key, + int (*cmp) (const char *s1, const char *s2)); +int lstFset_find_cmp (const lstTset * set, const char *key, + int (*cmp) (const char *s1, const char *s2)); +const char *lstFset_get_cmp (const lstTset * set, const char *key, + int (*cmp) (const char *s1, const char *s2)); +/* end undoc */ + +/* lst_void.c - Void Linear List */ +/* begin undoc */ +/* DEPRECATED INTERFACE DO NOT USE */ +typedef struct lstSlist lstTlist; +typedef struct lstSlist_elem lstTlist_elem; +void lstFlist_init(lstTlist * list, void (*destroy) (void *)); +void lstFlist_destroy(lstTlist * list); +lstTlist * lstFlist_create (void (*destroy) (void *)); +void lstFlist_free (lstTlist *list); +int lstFlist_add_next(lstTlist * list, lstTlist_elem * elem, void *data); +int lstFlist_add_prev(lstTlist * list, lstTlist_elem * elem, void *data); +int lstFlist_remove(lstTlist * list, lstTlist_elem * elem, void **data); +lstTlist_elem * lstFlist_next (lstTlist_elem *elem); +lstTlist_elem * lstFlist_prev (lstTlist_elem *elem); +void * lstFlist_data (lstTlist_elem *elem); +int lstFlist_is_head (lstTlist *list, lstTlist_elem *elem); +int lstFlist_is_head (lstTlist *list, lstTlist_elem *elem); +lstTlist_elem * lstFlist_head (lstTlist *list); +lstTlist_elem * lstFlist_tail (lstTlist *list); +int lstFlist_size (lstTlist *list); +int lstFlist_is_tail (lstTlist *list, lstTlist_elem *elem) ; +/* end undoc */ + +/* mem.c - Memory Operations */ +#ifndef WIN32 +#define memFclear bzero +#define memFcopy bcopy +#else +#define memFclear(a,b) memset(a,0,b) +#define memFcopy memcpy +#endif +#define memFfree free +#define memFalloc malloc +#define memFrealloc realloc +void *memFdup(const void *p, size_t len); + +/* rnd.c - Random Number Generator */ +void rndFinit (void); +void rndFrandom_bytes (unsigned char *buf, int len); +unsigned int rndFnumber (void); + +/* str.c - String Functions */ +lstTset *strFattrib_parser(const char *str); +void strFstrip_crlf (char *s, const size_t len); +void strFtoupper (char *s); +void strFtolower (char *s); +char *strFdup_size (const char *s, size_t * len); +char *strFcopy_size (const char *s, size_t * len); +char *strFcopy (const char *s); +void strFrealloc (char **strP, int *maxsizeP, int size); +const char *strFcasestr (const char *haystack, const char *needle); +int strFis_whitespace(char c); +int strFis_blank(char *s); +dynTstring *strFcollapse_whitespace (char *str); +unsigned int strFsplit (char *str, char **list, unsigned int list_size,const char delim, const char quotechar); +char *strFncopy(const char *s, size_t len); +const char *strFskip_whitespace(const char *p); +const char *strFskip_token(const char *p); + +/* tls.c - Thread Local Storage */ +int tlsFregister (void *(*clean_fn) (void *)); +char *tlsFadd_makeid (void *data, int class); +void *tlsFget (char *name, int class); +void tlsFdel (char *name, int class); +void tlsFclean (void); +/* undoc */ +void tlsFdestroy (void *p); +void tlsFinit (void); +void tlsFadd (void *data, char *name, int class); +/* end undoc */ + +/* utl.c - Utility Functions */ +typedef struct utlSswatch utlTswatch; +int utlFfd_printf (int fd, const char *fmt, ...); +unsigned int utlFtime (void); +volatile const struct tm *utlFlocaltime (void); +volatile const char *utlFcommonlog_time (void); +volatile const char *utlFlocal_time (void); +utlTswatch *utlFstart_swatch (void); +unsigned int utlFstop_swatch (utlTswatch * sw); +int utlFtv_sub (struct timeval *r, const struct timeval *x, const struct timeval *y); +int utlFip_to_str (unsigned int ip, char *buf, size_t buflen); +unsigned int utlFstr_to_ip (const char *ip); +int utlFisnum (const char c); +int utlFstr_has_alphas (const char *p); +void utlFtv_add (struct timeval *res, struct timeval *t1, struct timeval *t2); +long utlFtv_to_ms (struct timeval *tv); +int utlFurl_encode (dynTstring * dyn, const char *string); +int utlFurl_decode (dynTstring * dyn, const char *string); +int utlFhexdigit (char c); +uint32_t utlFgethostid (void); +size_t utlFhttp_time_print (time_t when, char *buf, size_t buflen); +time_t utlFhttp_time_parse (char *str); +int utlFgetuid (const char *username); +int utlFgetgid (const char *username); +int utlFget_pwname(const char *username, struct passwd *pw); +int utlFget_homedir(const char *username,char *dir,size_t dir_len); +void utlFhours_to_hourmin(double in_time, int *hours, int *mins); +double utlFhourmin_to_hours(int hours, int mins); +int utlFip_match(unsigned int ipa, unsigned int ipb, unsigned int netmask); +const char *utlFshort_to_str(unsigned short n); +int utlFip_validate(const char *addr); +unsigned int utlFatoui(const char *s); +void utlFhexdump(void *data, size_t size); + +/* undoc */ +int utlFclock_get (uint32_t * clock_high, uint32_t * clock_low, + uint16_t * ret_clock_seq); +/* end undoc */ + +/* uid.c - Unique ID Generator */ +int uidFgenerate_str (char *id, size_t len); + +/* thr.c - Threads (Pooling, Triggers) */ +typedef struct thrStpool thrTtpool; +typedef struct thrStrigger thrTtrigger; +thrTtpool *thrFinit (int num_threads, + int max_queue_size, int blocking_mode); +int thrFadd_work (thrTtpool * tpool, void (*routine) (void *), void *arg); +int thrFdestroy (thrTtpool * tpool, int finish); +int thrFsleep (int ms); +thrTtrigger *thrFgettrigger (void); +void thrFcheck_triggers (thrTtpool * tp); +int thrFtrigger_set (unsigned int delta, int fd); +int thrFtrigger_clear (void); +void thrFmod_init (void); +void thrFstat_thr (void *tp); + +/* qry.c - HTTP query parser */ +lstTset *qryFlst_parse(const char *query); +int qryFqualify(void); + +/* cfg.c - "XML"ish configuration parser */ +typedef struct xmlSiterator xmlTiterator; +typedef struct xmlSconfig xmlTconfig; +typedef struct xmlStag xmlTtag; + +xmlTtag *xmlFbase_tag(const xmlTconfig *config); +xmlTconfig *xmlFparse(const char *str); +xmlTconfig *xmlFload_file(const char *filename); + +const xmlTtag *xmlFfind_first_tag(const xmlTtag *tag, const char *name); +const xmlTtag *xmlFfind_first_tag_children(const xmlTtag *tag, const char *name); +const xmlTtag *xmlFfind_first_child(const xmlTtag *tag, const char *name); + +xmlTiterator *xmlFiterator_init(const xmlTtag *tag); +void xmlFiterator_free(xmlTiterator *iterator); +const xmlTtag *xmlFiterator_next(xmlTiterator *iterator); +const xmlTtag *xmlFiterator_next_name(xmlTiterator *iterator, const char *name); +xmlTiterator *xmlFiterate_children(const xmlTtag *tag); +void xmlFiterator_reset(xmlTiterator *iterator); +const xmlTtag *xmlFiterator_tag(xmlTiterator *it); + +const char *xmlFtag_get_name(const xmlTtag *tag, size_t *name_len); +const char *xmlFtag_get_value(const xmlTtag *tag, size_t *value_len); +const lstTset *xmlFtag_get_attribs(const xmlTtag *tag); +const char *xmlFtag_get_attrib_value(const xmlTtag *tag, const char *name); +const xmlTtag *xmlFtag_get_children(const xmlTtag *tag); +const char *xmlFtag_get_value_str(const xmlTtag *tag); +const char *xmlFtag_get_name_str(const xmlTtag *tag); +lstTset *xmlFcreate_list(const xmlTtag *tag, const char *tagname, const char *attribname); +const char *xmlFfirst_child_value(const xmlTtag *tag, const char *name, size_t *value_len); +const char *xmlFfirst_child_value_str (const xmlTtag *tag, const char *name); + +/* net.c */ +struct netSconn { + int sd; /* OS socket descriptor*/ + uint32_t cli_ipv4_addr; /* ipv4 address of the remote endpoint*/ + int (*io_close)(struct netSconn *conn); + ssize_t (*io_writev)(struct netSconn *conn, const struct iovec *iov, int iovcnt); + ssize_t (*io_read)(struct netSconn *conn, void *buf, size_t len); + ssize_t (*io_write)(struct netSconn *conn, const void *buf, size_t len); + void (*data_free)(void *data); + void *data; +}; +typedef struct netSconn netTconn; +typedef struct netSreader netTreader; + +int netFconn_close(netTconn *conn); +ssize_t netFconn_os_read(netTconn *conn, void *buf, size_t len); +ssize_t netFconn_os_write(netTconn *conn, const void *buf, size_t len); +int netFconn_os_close(netTconn *conn); +ssize_t netFconn_os_writev(netTconn *conn, const struct iovec *iov, int iovcnt); +ssize_t netFconn_write(netTconn *conn, const char *buf, ssize_t len); +netTreader *netFreader_init(void); +void netFreader_free(netTreader * reader); +int netFset_reuse(int sd); +int netFset_nodelay(int sd); +int netFipv4_listen_tcp(int port, unsigned int ip, int maxconnect); +ssize_t netFconn_read_line(netTconn * conn, netTreader * reader, char *buf, ssize_t len); +int netFisready(int fd); +int netFtcp_connect(char *addr, unsigned int port); +ssize_t netFconn_read(netTconn * conn, netTreader * reader, char *buf, ssize_t len); +ssize_t netFconn_write_two(netTconn * conn, const char *buf1, size_t buf1_len, const char *buf2, + size_t buf2_len); +int netFudp_send(int sd, const void *msg, size_t msg_len, unsigned int port, unsigned int ip); +int netFudp_recv(int sd, char *msg, size_t msg_len, struct sockaddr_in * sa, + size_t * sa_len); +int netFudp_open(uint16_t * port, int defport, char *service); +int netFudp_bcast_connect(void); +int netFconn_writef(netTconn * conn, const char *fmt,...); +int _netFconn_writef(netTconn * conn, const char *fmt, va_list * ap); +void netFconn_free(netTconn *conn); +netTconn *netFconn_make(int sd); + +int netFipv4_mcast_create(unsigned int port, char *group); + + /* pat.c - patterns */ +typedef struct patSstack patTstack; + +patTstack *patFstack_init(void (*destructor) (void *)); +void patFstack_free(patTstack *stack); +size_t patFstack_size(patTstack *stack); +void patFstack_append(patTstack *stack, const char *regexp, void *target); +void *patFstack_search(patTstack *stack, const char *needle) ; + +/* exp.c - Expressions */ +typedef void expTregexp; +int expFmatch(const char *pattern, const char *subject); +int expFmatch_len(const char *pattern, const char *subject, size_t subject_length); + +expTregexp *expFregexp_compile(const char *pattern); +void expFregexp_free(expTregexp *re); +int expFregexp_replace (const expTregexp * regexp, const char *subject, size_t subject_length, + const char *replace, size_t replace_length, char *output, size_t output_length); + +int expFregexp_match(const expTregexp *re, const char *subject); +int expFregexp_match_len(const expTregexp *regexp, const char *subject, size_t subject_length); +int expFapply(const char *pattern, const char *subject, lstTset * output); + +/* dic.c - Dictionary */ +typedef struct dicSdictionary dicTdictionary; + +dicTdictionary *dicFinit(void (*destructor) (void *), + int (*comparator) (const void *s1, + const void *s2, + size_t len)); +void dicFfree(dicTdictionary *d); +int dicFupdate(dicTdictionary *d, int idx, void *value, size_t value_len); +void *dicFfind(dicTdictionary *d, int idx); +int docFfind_index(dicTdictionary *d, void *value, size_t value_len, int *idx); +char *dicFchar_find(dicTdictionary *d, int idx); +int dicFchar_update(dicTdictionary *d, int idx, char *str, size_t str_len); +dicTdictionary *dicFchar_init(void); +int dicFchar_find_index(dicTdictionary *d, char *value, size_t value_len, int *idx); +void dicFuserdata_destructor_set(dicTdictionary *d, void (*destructor)(void *)); +void *dicFuserdata_find(dicTdictionary *d, int idx); +void dicFuserdata_update(dicTdictionary *d, int idx, void *data); + +/* sic.c - System functions */ +int sysFfs_info(lstTset * set); +int sysFget_load(double *one_min, double *five_min, double *fifteen_min); +unsigned int sysFboot_time(void); +int sysFmem_usage(uint32_t *pages_total, uint32_t *pages_free, + uint32_t *phys_mem, uint32_t *availr_mem, + uint32_t *free_mem); +int sysFcpu_usage(uint32_t *idle_time, uint32_t *user_time, + uint32_t *kernel_time, uint32_t *wait_time); +int sysFnet_usage(uint32_t *obytes, uint32_t *ibytes, + uint32_t *opkts, uint32_t *ipkts); + +/* cv - CeeValues */ + +#define CV_EMPTY 0 +#define CV_STRING 1 +#define CV_OBJECT 2 +#define CV_FLOAT 3 +#define CV_INTEGER 4 + +typedef struct cSval cTval; +typedef struct cSarray cTarray; +typedef struct cSassoc cTassoc; + +int cFval_type_get(cTval *v); +cTval *cFval_init(void); +void cFval_empty(cTval *v) ; +void cFval_free(cTval *v); +void cFval_assign_string(cTval *v, char *str, size_t len); +void cFval_assign_object(cTval *v, void *obj, size_t size); +void cFval_assign_object_tors(cTval *v, + void (*obj_destructor)(void *, size_t), + void *(*obj_duplicator)(void *, size_t), + int (*obj_comparator)(void *, void *, size_t)); +void cFval_assign_float(cTval *v, double value); +cTval *cFval_copy(cTval *v); +void cFval_assign_string_copy(cTval *v, const char *str, size_t len); +long long cFval_get_integer(cTval *v); +double cFval_get_float(cTval *v); +const char *cFval_get_string(cTval *v, size_t *size); +ssize_t cFval_get_string_copy(cTval *v, char *buf, size_t buf_size); +void cFval_used(cTval *v); + +#define CVNEW(v) x=cFval_init() + +#define CFREE(v) cFval_free(v) + +#define CUSE(v) cFval_use(v) + +#define CVNULL(v) cFval_empty(v) + +#define CVNEWSTRN(v,s,l) \ + v=cFval_init(); \ + cFval_assign_string(v,s,l) + +#define CVNEWSTR(v,s) CVNEWSTRN(v,s) + +#define CVNEWSTRCPYN(v,s,l) \ + v=cFval_init(); \ + cFval_assign_string_copy(v,s,l) + +#define CVNEWSTRCPY(v,s) CVNEWSTRCPYN(v,s,strlen(s)) + + +#define CNEWFLOAT(v,f) \ + v=cFval_init(); \ + cFval_assign_float(v,f) + +#define CNEWOBJ(v,o) \ + v=cFval_init(); \ + cFval_assign_object(o) + +#define CNEWINT(v,i) \ + v=cFval_init(); \ + cFval_assign_integer(i) + +cTarray *cFarray_new(void); +void cFarray_push(cTarray *array, cTval *val); +cTval *cFarray_pop(cTarray *array); +void *cFarray_foreach(cTarray *array, void *(*callback)(cTval *v)); +void cFarray_free(cTarray *array); + +#endif diff --git a/continuity/mecha_dep.h b/mk4/continuity/include/mecha_dep.h similarity index 100% rename from continuity/mecha_dep.h rename to mk4/continuity/include/mecha_dep.h diff --git a/mk4/continuity/install-sh b/mk4/continuity/install-sh new file mode 100644 index 0000000..e9de238 --- /dev/null +++ b/mk4/continuity/install-sh @@ -0,0 +1,251 @@ +#!/bin/sh +# +# install - install a program, script, or datafile +# This comes from X11R5 (mit/util/scripts/install.sh). +# +# Copyright 1991 by the Massachusetts Institute of Technology +# +# Permission to use, copy, modify, distribute, and sell this software and its +# documentation for any purpose is hereby granted without fee, 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 M.I.T. not be used in advertising or +# publicity pertaining to distribution of the software without specific, +# written prior permission. M.I.T. makes no representations about the +# suitability of this software for any purpose. It is provided "as is" +# without express or implied warranty. +# +# 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 "install: no input file specified" + exit 1 +else + true +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d $dst ]; then + instcmd=: + chmodcmd="" + else + instcmd=mkdir + 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 -o -d $src ] + then + true + else + echo "install: $src does not exist" + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "install: no destination specified" + exit 1 + else + true + 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 + true + 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 + true + fi + + pathcomp="${pathcomp}/" +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd $dst && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; 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 + true + fi + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + + $doit $instcmd $src $dsttmp && + + trap "rm -f ${dsttmp}" 0 && + +# 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 true;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && + +# Now rename the file to the real destination. + + $doit $rmcmd -f $dstdir/$dstfile && + $doit $mvcmd $dsttmp $dstdir/$dstfile + +fi && + + +exit 0 diff --git a/mk4/continuity/lib/.cvsignore b/mk4/continuity/lib/.cvsignore new file mode 100644 index 0000000..9b493d3 --- /dev/null +++ b/mk4/continuity/lib/.cvsignore @@ -0,0 +1 @@ +env.mk diff --git a/mk4/continuity/lib/CVS/Entries b/mk4/continuity/lib/CVS/Entries new file mode 100644 index 0000000..fb47aaf --- /dev/null +++ b/mk4/continuity/lib/CVS/Entries @@ -0,0 +1,4 @@ +/.cvsignore/1.1/Thu Mar 11 01:11:48 2004//Tmk4_mod6_rc2 +/build.mk/1.10/Fri May 14 19:12:09 2004//Tmk4_mod6_rc2 +/env.mk.in/1.5/Fri May 14 19:12:09 2004//Tmk4_mod6_rc2 +D diff --git a/mk4/continuity/lib/CVS/Repository b/mk4/continuity/lib/CVS/Repository new file mode 100644 index 0000000..bb2f3ec --- /dev/null +++ b/mk4/continuity/lib/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/continuity/lib diff --git a/mk4/continuity/lib/CVS/Root b/mk4/continuity/lib/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/continuity/lib/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/continuity/lib/CVS/Tag b/mk4/continuity/lib/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/continuity/lib/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/continuity/lib/build.mk b/mk4/continuity/lib/build.mk new file mode 100644 index 0000000..9fd872e --- /dev/null +++ b/mk4/continuity/lib/build.mk @@ -0,0 +1,173 @@ + +################################################################################ +## +## check to make SOURCES and TARGET is properly set +## +################################################################################ + +ifndef SOURCES +$(error SOURCES variable must be defined to be the sources you want to include in the build.) +endif + +ifndef TARGET +$(error TARGET must be defined to be the name of the module to build.) +endif + + +################################################################################ +## +## make sure CONTINUITY is properly configured +## +################################################################################ + +ifndef CONTINUITY +$(error CONTINUITY must be defined to point to the root of the continuity build.) +endif + +ifeq ($shell(test -d $(CONTINUITY)/continuity/lib && echo found),found) +CONTINUITY := $(CONTINUITY)/continuity +endif + +include $(CONTINUITY)/lib/env.mk + +################################################################################ +## +## Targets +## +################################################################################ + +ifndef TARGETTYPE +TARGETTYPE = module +endif + +ifneq (,$(findstring module,$(TARGETTYPE))) +SHARED_TARGET = mod$(TARGET).so +ALL_TARGETS += $(SHARED_TARGET) +endif + +ifneq (,$(findstring shared,$(TARGETTYPE))) +SHARED_TARGET = lib$(TARGET).so +ALL_TARGETS += $(SHARED_TARGET) +endif + +ifneq (,$(findstring static,$(TARGETTYPE))) +STATIC_TARGET = lib$(TARGET).a +ALL_TARGETS += $(STATIC_TARGET) +endif + +ifneq (,$(findstring executable,$(TARGETTYPE))) +EXECUTABLE_TARGET = $(TARGET) +ALL_TARGETS += $(EXECUTABLE_TARGET) +endif + +################################################################################ +## +## Dependancy mapping +## +################################################################################ + +DEPDIR = .deps +df = $(*D)/$(DEPDIR)/$(*F) + +DEPENDFLAGS = -MD -MP -MF $(df).d + +MAKE_DEP_DIR = [ -d "$(*D)$(DEPDIR)" ] || mkdir -p "$(*D)/$(DEPDIR)" + +DEP_FILES = $(foreach dep,$(SOURCES),$(dir $(dep))$(DEPDIR)/$(notdir $(dep:%.c=%.d))) + +################################################################################ +## +## Cleare defaults we don't want +## +################################################################################ + +.SUFFIXES: +.SUFFIXES: .o .c .h + +.a: +%.a: + + +################################################################################ +## +## setup variables +## +################################################################################ + +OBJECTS = $(SOURCES:%.c=%.o) + +CFLAGS += -I$(CONTINUITY)/include +CFLAGS += $(INCLUDES) $(LOCAL_CFLAGS) $(OPT_CFLAGS) + +LIBS += $(LOCAL_LIBS) + +# +# i decided this isn't really needed +# -eric 3.11.2004 +# +# EXPANDED_STATIC_LIBS = $(STATIC_LIBS:%=-Wl,--whole-archive % -Wl,--no-whole-archive) + +EXPANDED_STATIC_LIBS = $(STATIC_LIBS) $(WHOLE_STATIC_LIBS:%=-Wl,--whole-archive % -Wl,--no-whole-archive) + + +MAKEFILES = $(CONTINUITY)/lib/env.mk $(CONTINUITY)/lib/build.mk Makefile + + +################################################################################ +## +## define targets +## +################################################################################ + +all: $(ALL_TARGETS) install + +$(EXECUTABLE_TARGET): $(OBJECTS) $(STATIC_LIBS) $(MAKEFILES) $(WHOLE_STATIC_LIBS) + $(CC) $(LD_FLAGS) $(OBJECTS) $(EXPANDED_STATIC_LIBS) $(LIBS) -o $@ + +$(SHARED_TARGET): $(OBJECTS) $(STATIC_LIBS) $(MAKEFILES) $(WHOLE_STATIC_LIBS) + $(LD_SHARECMD) $(LD_FLAGS) $(PRE_BUILD) $(OBJECTS) $(EXPANDED_STATIC_LIBS) $(LIBS) $(POST_BUILD) -o $@ + +$(STATIC_TARGET): $(OBJECTS) $(MAKEFILES) + $(RM) $@ + $(AR) crs $@ $(OBJECTS) + +%.o: %.c $(MAKEFILES) + @$(MAKE_DEP_DIR) + $(CC) $(DEPENDFLAGS) $(CFLAGS) -c $< -o $@ + +ifneq ($(SHARED_TARGET),) +$(CONTINUITY)/lib/$(SHARED_TARGET): $(SHARED_TARGET) + @echo "$< -> $@" + @$(RM) $@ + @cp $< $@ +endif + +ifneq ($(STATIC_TARGET),) +$(CONTINUITY)/lib/$(STATIC_TARGET): $(STATIC_TARGET) + @echo "$< -> $@" + @$(RM) $@ + @cp $< $@ +endif + +ifneq ($(EXECUTABLE_TARGET),) +$(CONTINUITY)/bin/$(EXECUTABLE_TARGET): $(EXECUTABLE_TARGET) + @echo "$< -> $@" + @$(RM) $@ + @cp $< $@ +endif + +install: $(CONTINUITY)/lib/$(SHARED_TARGET) $(CONTINUITY)/lib/$(STATIC_TARGET) $(CONTINUITY)/bin/$(EXECUTABLE_TARGET) + +#install: $(ALL_TARGETS) +# @for file in $(ALL_TARGETS); do \ +# echo "$$file -> $(CONTINUITY)/lib/$$file"; \ +# $(RM) $(CONTINUITY)/lib/$$file; \ +# cp $$file $(CONTINUITY)/lib/$$file; \ +# done + +clean: + $(RM) $(OBJECTS) $(DEP_FILES) + +#ifneq ($(MAKECMDGOALS),clean) +#-include $(DEP_FILES) +#endif diff --git a/mk4/continuity/lib/env.mk.in b/mk4/continuity/lib/env.mk.in new file mode 100644 index 0000000..00ee102 --- /dev/null +++ b/mk4/continuity/lib/env.mk.in @@ -0,0 +1,25 @@ +# $Id: env.mk.in,v 1.5 2004/05/14 19:12:09 eric Exp $ + +CC=@CC@ +CFLAGS=@ARCH_CFLAGS@ @OPT_CFLAGS@ -D_REENTRANT -DTHR_POOL +CONT_FLAGS=@ARCH_CFLAGS@ @OPT_CFLAGS@ -D_REENTRANT -DTHR_POOL + +LD_SHARECMD=@LDSHARED@ +LIBS=@LIBS@ +LD_FLAGS=@LD_FLAGS@ + +MAKEDEPEND=@MAKEDEPEND@ +DEPFLAGS=@DEPFLAGS@ + +AR_CMD=@AR_CMD@ + +CCVER=WS6U1 +COMPOBJ=$(CONTINUITY_HOME)/lib/$(CCVER) +COMPOBJS32=$(COMPOBJ)/crti.o $(COMPOBJ)/crt1.o $(COMPOBJ)/crtn.o + +BUILD_CMD=@BUILD_CMD@ +PRE_BUILD=@PRE_BUILD@ +POST_BUILD=@POST_BUILD@ + +MODTCL_TCLOPT=@MODTCL_TCLOPT@ + diff --git a/mk4/continuity/mecha/CVS/Entries b/mk4/continuity/mecha/CVS/Entries new file mode 100644 index 0000000..0a0a000 --- /dev/null +++ b/mk4/continuity/mecha/CVS/Entries @@ -0,0 +1,34 @@ +/Makefile.in/1.20/Fri May 14 18:30:26 2004//Tmk4_mod6_rc2 +/ast.c/1.8/Fri Apr 30 13:41:56 2004//Tmk4_mod6_rc2 +/b64.c/1.9/Fri Apr 30 13:41:56 2004//Tmk4_mod6_rc2 +/bsp.c/1.18/Fri Apr 30 13:41:56 2004//Tmk4_mod6_rc2 +/bus.c/1.10/Fri Apr 30 13:41:56 2004//Tmk4_mod6_rc2 +/crc.c/1.8/Fri Apr 30 13:41:56 2004//Tmk4_mod6_rc2 +/cv.c/1.4/Fri May 14 06:20:32 2004//Tmk4_mod6_rc2 +/dic.c/1.1/Fri Apr 30 13:41:56 2004//Tmk4_mod6_rc2 +/dyn.c/1.18/Fri Apr 30 13:41:56 2004//Tmk4_mod6_rc2 +/dyn.h/1.5/Wed Mar 17 19:26:08 2004//Tmk4_mod6_rc2 +/exp.c/1.9/Fri Apr 30 13:41:56 2004//Tmk4_mod6_rc2 +/fle.c/1.18/Tue May 11 20:39:12 2004//Tmk4_mod6_rc2 +/hsh.c/1.24/Thu May 27 14:31:42 2004//Tmk4_mod6_rc2 +/hsh_dep.c/1.9/Thu Mar 18 15:04:15 2004//Tmk4_mod6_rc2 +/log.c/1.8/Fri Apr 30 13:41:56 2004//Tmk4_mod6_rc2 +/lst.c/1.31/Fri Apr 30 13:41:56 2004//Tmk4_mod6_rc2 +/lst.h/1.6/Wed Mar 17 19:26:08 2004//Tmk4_mod6_rc2 +/lst_void.c/1.12/Fri Apr 30 13:41:56 2004//Tmk4_mod6_rc2 +/mecha.c/1.2/Fri May 14 18:32:51 2004//Tmk4_mod6_rc2 +/mem.c/1.9/Fri Apr 30 13:41:56 2004//Tmk4_mod6_rc2 +/net.c/1.14/Thu May 27 13:32:22 2004//Tmk4_mod6_rc2 +/net.h/1.2/Wed Mar 17 19:26:08 2004//Tmk4_mod6_rc2 +/pat.c/1.6/Fri Apr 30 13:41:56 2004//Tmk4_mod6_rc2 +/qry.c/1.9/Fri Apr 30 13:41:56 2004//Tmk4_mod6_rc2 +/rnd.c/1.8/Fri Apr 30 13:41:56 2004//Tmk4_mod6_rc2 +/str.c/1.21/Fri Apr 30 13:41:56 2004//Tmk4_mod6_rc2 +/sys.c/1.2/Thu May 20 19:39:25 2004//Tmk4_mod6_rc2 +/thr.c/1.24/Thu May 27 13:55:00 2004//Tmk4_mod6_rc2 +/tls.c/1.9/Fri Apr 30 13:41:56 2004//Tmk4_mod6_rc2 +/uid.c/1.9/Fri Apr 30 13:41:56 2004//Tmk4_mod6_rc2 +/utl.c/1.31/Thu May 13 14:11:25 2004//Tmk4_mod6_rc2 +/w32.c/1.5/Fri Apr 30 13:41:56 2004//Tmk4_mod6_rc2 +/xml.c/1.21/Fri Apr 30 13:41:56 2004//Tmk4_mod6_rc2 +D diff --git a/mk4/continuity/mecha/CVS/Repository b/mk4/continuity/mecha/CVS/Repository new file mode 100644 index 0000000..99e351e --- /dev/null +++ b/mk4/continuity/mecha/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/continuity/mecha diff --git a/mk4/continuity/mecha/CVS/Root b/mk4/continuity/mecha/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/continuity/mecha/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/continuity/mecha/CVS/Tag b/mk4/continuity/mecha/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/continuity/mecha/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/continuity/mecha/Makefile.in b/mk4/continuity/mecha/Makefile.in new file mode 100644 index 0000000..d2e14ea --- /dev/null +++ b/mk4/continuity/mecha/Makefile.in @@ -0,0 +1,31 @@ +# $Header: /san01/cvs/ashpool/csrc/continuity/mecha/Attic/Makefile.in,v 1.20 2004/05/14 18:30:26 aleigh Exp $ + +SRCS=ast.c b64.c bsp.c bus.c crc.c dyn.c fle.c hsh.c hsh_dep.c log.c lst.c \ +rnd.c str.c thr.c tls.c uid.c utl.c lst_void.c qry.c xml.c w32.c mem.c \ +exp.c net.c pat.c dic.c sys.c cv.c mecha.c +OBJS=ast.o b64.o bsp.o bus.o crc.o dyn.o fle.o hsh.o hsh_dep.o log.o lst.o \ +rnd.o str.o thr.o tls.o uid.o utl.o lst_void.o qry.o xml.o w32.o mem.o \ +exp.o net.o pat.o dic.o sys.o cv.o mecha.o +PCRE_OBJS=../pcre/pcreposix.o ../pcre/pcre.o ../pcre/get.o + +CFLAGS=-I../include @ARCH_CFLAGS@ @OPT_CFLAGS@ -D_REENTRANT -DTHR_POOL @BUILD_CFLAGS@ +LD_SHARECMD= @LDSHARED@ +CC=@CC@ +AR_CMD=@AR_CMD@ +BUILDMODE=@BUILDMODE@ +MAKEDEPEND=@MAKEDEPEND@ + +world: $(OBJS) $(PCRE_OBJS) + $(AR_CMD) mechanism.a $(OBJS) $(PCRE_OBJS) + ranlib mechanism.a + cp mechanism.a ../lib + +clean: + rm -rf ../lib/mechanism.a $(OBJS) + +count: + wc -l `find . -name '*.[ch]'` + +depend: + $(MAKEDEPEND) @DEPFLAGS@ -I ../include $(SRCS) + diff --git a/mk4/continuity/mecha/ast.c b/mk4/continuity/mecha/ast.c new file mode 100644 index 0000000..27d9e47 --- /dev/null +++ b/mk4/continuity/mecha/ast.c @@ -0,0 +1,431 @@ +/* + * $Header: /san01/cvs/ashpool/csrc/continuity/mecha/Attic/ast.c,v 1.8 2004/04/30 13:41:56 aleigh Exp $ + */ + +/* + * Copyright (c) 1994, 2004 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Disclosure, copying, distribution, or transmission of of this code without + * express permission is prohibited. + */ + +/* + * Original Algorithm: Written as DAYLEN.C, 1989-08-16 Modified to + * SUNRISET.C, 1992-12-01 (c) Paul Schlyter, 1989, 1992 Released to the + * public domain by Paul Schlyter, December 1992 + */ + +#include "mecha.h" + +/* A macro to compute the number of days elapsed since 2000 Jan 0.0 */ +/* (which is equal to 1999 Dec 31, 0h UT) */ + +#define days_since_2000_Jan_0(y,m,d) \ + (367L*(y)-((7*((y)+(((m)+9)/12)))/4)+((275*(m))/9)+(d)-730530L) + +/* Some conversion factors between radians and degrees */ +#ifndef PI +#define PI 3.1415926535897932384 +#endif +#define RADEG ( 180.0 / PI ) +#define DEGRAD ( PI / 180.0 ) + +/* The trigonometric functions in degrees */ +#define sind(x) sin((x)*DEGRAD) +#define cosd(x) cos((x)*DEGRAD) +#define tand(x) tan((x)*DEGRAD) +#define atand(x) (RADEG*atan(x)) +#define asind(x) (RADEG*asin(x)) +#define acosd(x) (RADEG*acos(x)) +#define atan2d(y,x) (RADEG*atan2(y,x)) + +/* Following are some macros around the "workhorse" function __daylen__ */ +/* They mainly fill in the desired values for the reference altitude */ +/* below the horizon, and also selects whether this altitude should */ +/* refer to the Sun's center or its upper limb. */ +/* This macro computes the length of the day, from sunrise to sunset. */ +/* Sunrise/set is considered to occur when the Sun's upper limb is */ +/* 35 arc minutes below the horizon (this accounts for the refraction */ +/* of the Earth's atmosphere). */ +#define day_length(year,month,day,lon,lat) \ + __daylen__( year, month, day, lon, lat, -35.0/60.0, 1 ) + +/* This macro computes the length of the day, including civil twilight. */ +/* Civil twilight starts/ends when the Sun's center is 6 degrees below */ +/* the horizon. */ + +#define day_civil_twilight_length(year,month,day,lon,lat) \ + __daylen__( year, month, day, lon, lat, -6.0, 0 ) +/* This macro computes the length of the day, incl. nautical twilight. */ +/* Nautical twilight starts/ends when the Sun's center is 12 degrees */ +/* below the horizon. */ + +#define day_nautical_twilight_length(year,month,day,lon,lat) \ + __daylen__( year, month, day, lon, lat, -12.0, 0 ) +/* This macro computes the length of the day, incl. astronomical twilight. */ +/* Astronomical twilight starts/ends when the Sun's center is 18 degrees */ +/* below the horizon. */ + +#define day_astronomical_twilight_length(year,month,day,lon,lat) \ + __daylen__( year, month, day, lon, lat, -18.0, 0 ) +/* This macro computes times for sunrise/sunset. */ +/* Sunrise/set is considered to occur when the Sun's upper limb is */ +/* 35 arc minutes below the horizon (this accounts for the refraction */ +/* of the Earth's atmosphere). */ + +#define sun_rise_set(year,month,day,lon,lat,rise,set) \ + __sunriset__( year, month, day, lon, lat, -35.0/60.0, 1, rise, set ) +/* This macro computes the start and end times of civil twilight. */ +/* Civil twilight starts/ends when the Sun's center is 6 degrees below */ +/* the horizon. */ + +#define civil_twilight(year,month,day,lon,lat,start,end) \ + __sunriset__( year, month, day, lon, lat, -6.0, 0, start, end ) +/* This macro computes the start and end times of nautical twilight. */ +/* Nautical twilight starts/ends when the Sun's center is 12 degrees */ +/* below the horizon. */ + +#define nautical_twilight(year,month,day,lon,lat,start,end) \ + __sunriset__( year, month, day, lon, lat, -12.0, 0, start, end ) +/* This macro computes the start and end times of astronomical twilight. */ +/* Astronomical twilight starts/ends when the Sun's center is 18 degrees */ +/* below the horizon. */ + +#define astronomical_twilight(year,month,day,lon,lat,start,end) \ + __sunriset__( year, month, day, lon, lat, -18.0, 0, start, end ) +/* Function prototypes */ + +static double __daylen__(int year, int month, int day, double lon, + double lat, double altit, int upper_limb); + +static int __sunriset__(int year, int month, int day, double lon, + double lat, double altit, int upper_limb, + double *rise, double *set); + +static void sunpos(double d, double *lon, double *r); + +static void sun_RA_dec(double d, double *RA, double *dec, double *r); + +static double revolution(double x); + +static double rev180(double x); + +static double GMST0(double d); + +void astFsunriset(astTsunriset * srs, int month, int day, int year, + double lon, double lat) +{ + srs->length = day_length(year, month, day, lon, lat); + srs->civil_length = + day_civil_twilight_length(year, month, day, lon, lat); + srs->nautical_length = + day_nautical_twilight_length(year, month, day, lon, lat); + srs->astro_length = + day_astronomical_twilight_length(year, month, day, lon, lat); + + srs->status = + sun_rise_set(year, month, day, lon, lat, &srs->rise, &srs->set); + srs->civil_status = + civil_twilight(year, month, day, lon, lat, &srs->civil_start, + &srs->civil_end); + srs->nautical_status = + nautical_twilight(year, month, day, lon, lat, &srs->nautical_start, + &srs->nautical_end); + srs->astro_status = + astronomical_twilight(year, month, day, lon, lat, + &srs->astro_start, &srs->astro_end); + + srs->zenith = (srs->rise + srs->set) / 2.0; +} + + +/* The "workhorse" function for sun rise/set times */ + +static int __sunriset__(int year, int month, int day, double lon, + double lat, double altit, int upper_limb, + double *trise, double *tset) +/***************************************************************************/ +/* Note: year,month,date = calendar date, 1801-2099 only. */ +/* Eastern longitude positive, Western longitude negative */ +/* Northern latitude positive, Southern latitude negative */ +/* The longitude value IS critical in this function! */ +/* altit = the altitude which the Sun should cross */ +/* Set to -35/60 degrees for rise/set, -6 degrees */ +/* for civil, -12 degrees for nautical and -18 */ +/* degrees for astronomical twilight. */ +/* upper_limb: non-zero -> upper limb, zero -> center */ +/* Set to non-zero (e.g. 1) when computing rise/set */ +/* times, and to zero when computing start/end of */ +/* twilight. */ +/* *rise = where to store the rise time */ +/* *set = where to store the set time */ +/* Both times are relative to the specified altitude, */ +/* and thus this function can be used to compute */ +/* various twilight times, as well as rise/set times */ +/* Return value: 0 = sun rises/sets this day, times stored at */ +/* *trise and *tset. */ +/* +1 = sun above the specified "horizon" 24 hours. */ +/* *trise set to time when the sun is at south, */ +/* minus 12 hours while *tset is set to the south */ +/* time plus 12 hours. "Day" length = 24 hours */ +/* -1 = sun is below the specified "horizon" 24 hours */ +/* "Day" length = 0 hours, *trise and *tset are */ +/* both set to the time when the sun is at south. */ +/* */ +/**********************************************************************/ +{ + double d, /* Days since 2000 Jan 0.0 (negative before) */ + sr, /* Solar distance, astronomical units */ + sRA, /* Sun's Right Ascension */ + sdec, /* Sun's declination */ + sradius, /* Sun's apparent radius */ + t, /* Diurnal arc */ + tsouth, /* Time when Sun is at south */ + sidtime; /* Local sidereal time */ + + int rc = 0; /* Return cde from function - usually 0 */ + + /* Compute d of 12h local mean solar time */ + d = days_since_2000_Jan_0(year, month, day) + 0.5 - lon / 360.0; + + /* Compute local sidereal time of this moment */ + sidtime = revolution(GMST0(d) + 180.0 + lon); + + /* Compute Sun's RA + Decl at this moment */ + sun_RA_dec(d, &sRA, &sdec, &sr); + + /* Compute time when Sun is at south - in hours UT */ + tsouth = 12.0 - rev180(sidtime - sRA) / 15.0; + + /* Compute the Sun's apparent radius, degrees */ + sradius = 0.2666 / sr; + + /* Do correction to upper limb, if necessary */ + if (upper_limb) + altit -= sradius; + + /* Compute the diurnal arc that the Sun traverses to reach */ + /* the specified altitude altit: */ + { + double cost; + cost = (sind(altit) - sind(lat) * sind(sdec)) / + (cosd(lat) * cosd(sdec)); + if (cost >= 1.0) + rc = -1, t = 0.0; /* Sun always below altit */ + else if (cost <= -1.0) + rc = +1, t = 12.0; /* Sun always above altit */ + else + t = acosd(cost) / 15.0; /* The diurnal arc, hours */ + } + + /* Store rise and set times - in hours UT */ + *trise = tsouth - t; + *tset = tsouth + t; + + return rc; +} /* __sunriset__ */ + + + +/* The "workhorse" function */ + + +static double __daylen__(int year, int month, int day, double lon, + double lat, double altit, int upper_limb) +/**********************************************************************/ +/* Note: year,month,date = calendar date, 1801-2099 only. */ +/* Eastern longitude positive, Western longitude negative */ +/* Northern latitude positive, Southern latitude negative */ +/* The longitude value is not critical. Set it to the correct */ +/* longitude if you're picky, otherwise set to to, say, 0.0 */ +/* The latitude however IS critical - be sure to get it correct */ +/* altit = the altitude which the Sun should cross */ +/* Set to -35/60 degrees for rise/set, -6 degrees */ +/* for civil, -12 degrees for nautical and -18 */ +/* degrees for astronomical twilight. */ +/* upper_limb: non-zero -> upper limb, zero -> center */ +/* Set to non-zero (e.g. 1) when computing day length */ +/* and to zero when computing day+twilight length. */ +/**********************************************************************/ +{ + double d, /* Days since 2000 Jan 0.0 (negative before) */ + obl_ecl, /* Obliquity (inclination) of Earth's axis */ + sr, /* Solar distance, astronomical units */ + slon, /* True solar longitude */ + sin_sdecl, /* Sine of Sun's declination */ + cos_sdecl, /* Cosine of Sun's declination */ + sradius, /* Sun's apparent radius */ + t; /* Diurnal arc */ + + /* Compute d of 12h local mean solar time */ + d = days_since_2000_Jan_0(year, month, day) + 0.5 - lon / 360.0; + + /* Compute obliquity of ecliptic (inclination of Earth's axis) */ + obl_ecl = 23.4393 - 3.563E-7 * d; + + /* Compute Sun's position */ + sunpos(d, &slon, &sr); + + /* Compute sine and cosine of Sun's declination */ + sin_sdecl = sind(obl_ecl) * sind(slon); + cos_sdecl = sqrt(1.0 - sin_sdecl * sin_sdecl); + + /* Compute the Sun's apparent radius, degrees */ + sradius = 0.2666 / sr; + + /* Do correction to upper limb, if necessary */ + if (upper_limb) + altit -= sradius; + + /* Compute the diurnal arc that the Sun traverses to reach */ + /* the specified altitude altit: */ + { + double cost; + cost = (sind(altit) - sind(lat) * sin_sdecl) / + (cosd(lat) * cos_sdecl); + if (cost >= 1.0) + t = 0.0; /* Sun always below altit */ + else if (cost <= -1.0) + t = 24.0; /* Sun always above altit */ + else + t = (2.0 / 15.0) * acosd(cost); /* The diurnal arc, hours */ + } + return t; +} /* __daylen__ */ + + +/* This function computes the Sun's position at any instant */ + +static void sunpos(double d, double *lon, double *r) +/******************************************************/ +/* Computes the Sun's ecliptic longitude and distance */ +/* at an instant given in d, number of days since */ +/* 2000 Jan 0.0. The Sun's ecliptic latitude is not */ +/* computed, since it's always very near 0. */ +/******************************************************/ +{ + double M, /* Mean anomaly of the Sun */ + w, /* Mean longitude of perihelion */ + /* Note: Sun's mean longitude = M + w */ + e, /* Eccentricity of Earth's orbit */ + E, /* Eccentric anomaly */ + x, y, /* x, y coordinates in orbit */ + v; /* True anomaly */ + + /* Compute mean elements */ + M = revolution(356.0470 + 0.9856002585 * d); + w = 282.9404 + 4.70935E-5 * d; + e = 0.016709 - 1.151E-9 * d; + + /* Compute true longitude and radius vector */ + E = M + e * RADEG * sind(M) * (1.0 + e * cosd(M)); + x = cosd(E) - e; + y = sqrt(1.0 - e * e) * sind(E); + *r = sqrt(x * x + y * y); /* Solar distance */ + v = atan2d(y, x); /* True anomaly */ + *lon = v + w; /* True solar longitude */ + if (*lon >= 360.0) + *lon -= 360.0; /* Make it 0..360 degrees */ +} + +static void sun_RA_dec(double d, double *RA, double *dec, double *r) +{ + double lon, obl_ecl, x, y, z; + + /* Compute Sun's ecliptical coordinates */ + sunpos(d, &lon, r); + + /* Compute ecliptic rectangular coordinates (z=0) */ + x = *r * cosd(lon); + y = *r * sind(lon); + + /* Compute obliquity of ecliptic (inclination of Earth's axis) */ + obl_ecl = 23.4393 - 3.563E-7 * d; + + /* Convert to equatorial rectangular coordinates - x is unchanged */ + z = y * sind(obl_ecl); + y = y * cosd(obl_ecl); + + /* Convert to spherical coordinates */ + *RA = atan2d(y, x); + *dec = atan2d(z, sqrt(x * x + y * y)); + +} /* sun_RA_dec */ + + +/******************************************************************/ +/* This function reduces any angle to within the first revolution */ +/* by subtracting or adding even multiples of 360.0 until the */ +/* result is >= 0.0 and < 360.0 */ +/******************************************************************/ + +#define INV360 ( 1.0 / 360.0 ) + +static double revolution(double x) +/*****************************************/ +/* Reduce angle to within 0..360 degrees */ +/*****************************************/ +{ + return (x - 360.0 * floor(x * INV360)); +} /* revolution */ + +static double rev180(double x) +/*********************************************/ +/* Reduce angle to within +180..+180 degrees */ +/*********************************************/ +{ + return (x - 360.0 * floor(x * INV360 + 0.5)); +} /* revolution */ + + +/*******************************************************************/ +/* This function computes GMST0, the Greenwich Mean Sidereal Time */ +/* at 0h UT (i.e. the sidereal time at the Greenwhich meridian at */ +/* 0h UT). GMST is then the sidereal time at Greenwich at any */ +/* time of the day. I've generalized GMST0 as well, and define it */ +/* as: GMST0 = GMST - UT -- this allows GMST0 to be computed at */ +/* other times than 0h UT as well. While this sounds somewhat */ +/* contradictory, it is very practical: instead of computing */ +/* GMST like: */ +/* */ +/* GMST = (GMST0) + UT * (366.2422/365.2422) */ +/* */ +/* where (GMST0) is the GMST last time UT was 0 hours, one simply */ +/* computes: */ +/* */ +/* GMST = GMST0 + UT */ +/* */ +/* where GMST0 is the GMST "at 0h UT" but at the current moment! */ +/* Defined in this way, GMST0 will increase with about 4 min a */ +/* day. It also happens that GMST0 (in degrees, 1 hr = 15 degr) */ +/* is equal to the Sun's mean longitude plus/minus 180 degrees! */ +/* (if we neglect aberration, which amounts to 20 seconds of arc */ +/* or 1.33 seconds of time) */ +/* */ +/*******************************************************************/ + +static double GMST0(double d) +{ + double sidtim0; + /* Sidtime at 0h UT = L (Sun's mean longitude) + 180.0 degr */ + /* L = M + w, as defined in sunpos(). Since I'm too lazy to */ + /* add these numbers, I'll let the C compiler do it for me. */ + /* Any decent C compiler will add the constants at compile */ + /* time, imposing no runtime or code overhead. */ + sidtim0 = revolution((180.0 + 356.0470 + 282.9404) + + (0.9856002585 + 4.70935E-5) * d); + return sidtim0; +} /* GMST0 */ + +#ifdef NOTDEF +int main() +{ + astTsunriset srs; + + astFsunriset(&srs, 4, 23, 1979, 49, -123); +} +#endif diff --git a/mk4/continuity/mecha/b64.c b/mk4/continuity/mecha/b64.c new file mode 100644 index 0000000..fa0692e --- /dev/null +++ b/mk4/continuity/mecha/b64.c @@ -0,0 +1,216 @@ +/* + * $Header: /san01/cvs/ashpool/csrc/continuity/mecha/Attic/b64.c,v 1.9 2004/04/30 13:41:56 aleigh Exp $ + */ + +/* + * Copyright (c) 1994, 2004 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Disclosure, copying, distribution, or transmission of this code without + * express permission is prohibited. + */ + +#include "mecha.h" + +/* + * MODULE HTUU.c + * + * UENCODE AND UUDECODE + * + * ACKNOWLEDGEMENT: This code is taken from rpem distribution, and was + * originally written by Mark Riordan. + * + * AUTHORS: MR Mark Riordan riordanmr@clvax1.cl.msu.edu AL Ari + * Luotonen luotonen@dxcern.cern.ch + * + * HISTORY: Added as part of the WWW library and edited to conform with the WWW + * project coding standards by: AL 5 Aug 1993 Originally written by: + * MR 12 Aug 1990 Original header text: + * ------------------------------------------------------------- File + * containing routines to convert a buffer of bytes to/from RFC 1113 + * printable encoding format. + * + * This technique is similar to the familiar Unix uuencode format in that it + * maps 6 binary bits to one ASCII character (or more aptly, 3 binary bytes + * to 4 ASCII characters). However, RFC 1113 does not use the same mapping + * to printable characters as uuencode. + * + * Mark Riordan 12 August 1990 and 17 Feb 1991. This code is hereby placed in + * the public domain. + * ------------------------------------------------------------- + * + * BUGS: + * + */ + + +/* + * htuu.c -- + * + * Uuencoding and decoding routines. + * + * + */ + + +static char six2pr[64] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' +}; + +static unsigned char pr2six[256]; + + +/*--- function HTUU_encode ----------------------------------------------- + * + * Encode a single line of binary data to a standard format that + * uses only printing ASCII characters (but takes up 33% more bytes). + * + * Entry bufin points to a buffer of bytes. If nbytes is not + * a multiple of three, then the byte just beyond + * the last byte in the buffer must be 0. + * nbytes is the number of bytes in that buffer. + * This cannot be more than 48. + * bufcoded points to an output buffer. Be sure that this + * can hold at least 1 + (4*nbytes)/3 characters. + * + * Exit bufcoded contains the coded line. The first 4*nbytes/3 bytes + * contain printing ASCII characters representing + * those binary bytes. This may include one or + * two '=' characters used as padding at the end. + * The last byte is a zero byte. + * Returns the number of ASCII characters in "bufcoded". + */ +int b64Fencode(unsigned char *bufin, unsigned int nbytes, char *bufcoded) +{ + /* ENC is the basic 1 character encoding function to make a char printing */ +#define ENC(c) six2pr[c] + + register char *outptr = bufcoded; + unsigned int i; + + assert(bufin != NULL); + assert(bufcoded != NULL); + + for (i = 0; i < nbytes; i += 3) { + /* c1 */ + *(outptr++) = ENC(*bufin >> 2); + /* c2 */ + *(outptr++) = ENC(((*bufin << 4) & 060) | ((bufin[1] >> 4) & 017)); + /* c3 */ + *(outptr++) = + ENC(((bufin[1] << 2) & 074) | ((bufin[2] >> 6) & 03)); + /* c4 */ + *(outptr++) = ENC(bufin[2] & 077); + + bufin += 3; + } + + /* + * If nbytes was not a multiple of 3, then we have encoded too many + * characters. Adjust appropriately. + */ + if (i == nbytes + 1) { + /* There were only 2 bytes in that last group */ + outptr[-1] = '='; + } else if (i == nbytes + 2) { + /* There was only 1 byte in that last group */ + outptr[-1] = '='; + outptr[-2] = '='; + } + *outptr = '\0'; + return (outptr - bufcoded); +} + + +/*--- function HTUU_decode ------------------------------------------------ + * + * Decode an ASCII-encoded buffer back to its original binary form. + * + * Entry bufcoded points to a uuencoded string. It is + * terminated by any character not in + * the printable character table six2pr, but + * leading whitespace is stripped. + * bufplain points to the output buffer; must be big + * enough to hold the decoded string (generally + * shorter than the encoded string) plus + * as many as two extra bytes used during + * the decoding process. + * outbufsize is the maximum number of bytes that + * can fit in bufplain. + * + * Exit Returns the number of binary bytes decoded. + * bufplain contains these bytes. + */ +int b64Fdecode(const char *bufcoded, unsigned char *bufplain, + int outbufsize) +{ + /* single character decode */ +#define DEC(c) pr2six[(int)c] +#define MAXVAL 63 + + static int first = 1; + + int nbytesdecoded, j; + register const char *bufin = bufcoded; + register unsigned char *bufout = bufplain; + register int nprbytes; + + assert(bufcoded != NULL); + assert(bufplain != NULL); + /* + * If this is the first call, initialize the mapping table. This code + * should work even on non-ASCII machines. + */ + if (first) { + first = 0; + for (j = 0; j < 256; j++) + pr2six[j] = MAXVAL + 1; + + for (j = 0; j < 64; j++) + pr2six[(int) six2pr[j]] = (unsigned char) j; + } + /* Strip leading whitespace. */ + + while (*bufcoded == ' ' || *bufcoded == '\t') + bufcoded++; + + /* + * Figure out how many characters are in the input buffer. If this would + * decode into more bytes than would fit into the output buffer, adjust + * the number of input bytes downwards. + */ + bufin = bufcoded; + while (pr2six[(int) *(bufin++)] <= MAXVAL); + nprbytes = bufin - bufcoded - 1; + nbytesdecoded = ((nprbytes + 3) / 4) * 3; + if (nbytesdecoded > outbufsize) { + nprbytes = (outbufsize * 4) / 3; + } + bufin = bufcoded; + + while (nprbytes > 0) { + *(bufout++) = + (unsigned char) (DEC(*bufin) << 2 | DEC(bufin[1]) >> 4); + *(bufout++) = + (unsigned char) (DEC(bufin[1]) << 4 | DEC(bufin[2]) >> 2); + *(bufout++) = (unsigned char) (DEC(bufin[2]) << 6 | DEC(bufin[3])); + bufin += 4; + nprbytes -= 4; + } + + if (nprbytes & 03) { + if (pr2six[(int) bufin[-2]] > MAXVAL) { + nbytesdecoded -= 2; + } else { + nbytesdecoded -= 1; + } + } + return (nbytesdecoded); +} diff --git a/mk4/continuity/mecha/bsp.c b/mk4/continuity/mecha/bsp.c new file mode 100644 index 0000000..afc9754 --- /dev/null +++ b/mk4/continuity/mecha/bsp.c @@ -0,0 +1,294 @@ +/* + * $Header: /san01/cvs/ashpool/csrc/continuity/mecha/Attic/bsp.c,v 1.18 2004/04/30 13:41:56 aleigh Exp $ + */ + +/* + * Copyright (c) 1994, 2004 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Use, disclosure, copying, distribution, or transmission of this code without + * express permission is prohibited. + */ + +#include "mecha.h" + +#undef BSP_DEBUG +#undef BSP_DEBUG_LOTS + +struct bspSentry { + unsigned int l_key; /* the lowest value of this key range */ + unsigned int h_key; /* the highest value of this key range */ + void *p; + int is_copy; /* 1 if p is a copy and shouldn't be + * destructed */ + struct bspSentry *next; +}; +typedef struct bspSentry bspTentry; + +struct bspSnode { + unsigned int split; /* the key value on which the nodes are split */ + struct bspSnode *high; /* The next list, high */ + struct bspSnode *low; /* The next list, low */ + bspTentry *ents; +}; + +static void bspFadd_entry(bspTnode * node, bspTentry * ent); +static void bspF_balance(bspTnode * node, unsigned int count, + unsigned int depth); +static bspTentry *bspFdup_entry(bspTentry * ent); + +void bspFdestroy(bspTnode * node, void (*destructor) (void *)) +{ + bspTentry *e, *ne; + + assert(node != NULL); + + /* Destroy any member entries */ + + for (e = node->ents; e != NULL; e = ne) { + ne = e->next; + if (e->p != NULL) { + if (destructor != NULL && e->is_copy == 0) + destructor(e->p); + } + free(e); + } + + if (node->high != NULL) + bspFdestroy(node->high, destructor); + if (node->low != NULL) + bspFdestroy(node->low, destructor); + + free(node); +} + +static void bspFadd_entry(bspTnode * node, bspTentry * ent) +{ + assert(node != NULL); + assert(ent != NULL); + ent->next = node->ents; + node->ents = ent; +} + +static bspTentry *bspFdup_entry(bspTentry * ent) +{ + bspTentry *e; + + assert(ent != NULL); + + e = (bspTentry *) malloc(sizeof(bspTentry)); + assert(e != NULL); + + memFcopy(ent, e, sizeof(bspTentry)); + + e->next = NULL; + return e; +} + +/* + * Allocate and return an empty bspTnode + */ +bspTnode *bspFinit(void) +{ + bspTnode *p; + + p = (bspTnode *) malloc(sizeof(bspTnode)); + assert(p != NULL); + memFclear(p, sizeof(bspTnode)); + + return p; +} + +/* + * The the given node and split it into two nodes based on the median value. + */ +void bspFsplit(bspTnode * node) +{ + unsigned int max = 0, min = 0, size = 0; + bspTentry *ent, *tmpent, *next; + + assert(node != NULL); + + /* Determine the min/max range of the low keys */ + for (ent = node->ents; ent != NULL; ent = ent->next) { +#ifdef BSP_DEBUG_LOTS + logFmsg(3,"bspFsplit: entry: %u low key: %u min/max: %u/%u", size, ent->l_key, min, max); +#endif + if (ent->l_key < min || min == 0) + min = ent->l_key; + if (ent->l_key > max || max == 0) + max = ent->l_key; + size++; + } + + /* Calculate the splitpoint */ + node->split = min + ((max - min) / 2); + +#ifdef BSP_DEBUG + logFmsg(3,"bspFsplit: Split point calculated: %u from %u / %u. I have %u elements.", node->split, min, max, size); +#endif + + node->high = bspFinit(); + node->low = bspFinit(); + + ent = node->ents; + while (1) { + int e; + + /* + * e0, Load the range low e1, Load the range high e2, Split the range + * into two ranges and load high and low + */ + + if (ent->l_key < node->split) + e = 0; + else + e = 1; + + if (ent->l_key < node->split && ent->h_key > node->split) + e = 2; + + next = ent->next; + + if (e == 0) { + bspFadd_entry(node->low, ent); + } + if (e == 1) { + bspFadd_entry(node->high, ent); + } + if (e == 2) { + tmpent = bspFdup_entry(ent); + tmpent->h_key = (node->split - 1); + tmpent->is_copy = 1; + bspFadd_entry(node->low, tmpent); + + ent->l_key = node->split; + bspFadd_entry(node->high, ent); + } + if (next == NULL) + break; + ent = next; + } + + /* This is intentional */ + node->ents = NULL; +} + +/* + * Count the number of entries in the given node. + */ +unsigned int bspFcount(bspTnode * node) +{ + bspTentry *ent; + unsigned int size = 0; + + assert(node != NULL); + + if (node->ents == NULL) + return 0; + + for (ent = node->ents; ent != NULL; ent = ent->next) { + size++; + } + + return size; +} + +/* + * Balance an entire tree, up to the given depth. Size indicates the number + * of entries that a given node must have before it is split. Let depth be 0 + * for the first invocation. + */ + +void bspFbalance(bspTnode * node, unsigned int count) +{ + assert(node != NULL); + bspF_balance(node, count, 0); +} + +static void bspF_balance(bspTnode * node, unsigned int size, + unsigned int depth) +{ + unsigned int count; + + assert(node != NULL); + assert(depth<20); + + depth++; + + count=bspFcount(node); +#ifdef BSP_DEBUG + logFmsg(3,"bspF_balance: Will split if %u > %u", count, size); +#endif + + if (count > size) { + /* Split this node */ + bspFsplit(node); + bspF_balance(node->high, size, depth); + bspF_balance(node->low, size, depth); + } +} + +int bspFadd(bspTnode * list, void *p, int high_key, int low_key) +{ + bspTentry *ep; + + assert(list != NULL); + assert(p != NULL); + + ep = (bspTentry *) malloc(sizeof(bspTentry)); + + assert(ep != NULL); + + ep->l_key = low_key; + ep->h_key = high_key; + ep->p = p; + ep->next = list->ents; + list->ents = ep; + + return 0; +} + +/* + * Searches for key in the BSP range *list. Returns NULL if the value is not + * found in any of the ranges. + */ + +void *bspFsearch(bspTnode * node, unsigned int x) +{ + bspTentry *e; + bspTnode *n; + + assert(node != NULL); + + n = node; + + while (1) { + if (n->ents == NULL) { + /* Transverse */ + if (x >= n->split) { + if (n->high == NULL) + return NULL; + n = n->high; + } else { + if (n->low == NULL) + return NULL; + n = n->low; + } + } else { + if (n->ents == NULL) + return NULL; + e = n->ents; + while (1) { + if (e->l_key <= x && e->h_key >= x) + return e->p; + if (e->next == NULL) + return NULL; + e = e->next; + } + } + } +} diff --git a/mk4/continuity/mecha/bus.c b/mk4/continuity/mecha/bus.c new file mode 100644 index 0000000..4188947 --- /dev/null +++ b/mk4/continuity/mecha/bus.c @@ -0,0 +1,135 @@ +/* + * $Header: /san01/cvs/ashpool/csrc/continuity/mecha/Attic/bus.c,v 1.10 2004/04/30 13:41:56 aleigh Exp $ + */ + +/* + * Copyright (c) 1994, 2004 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Use, disclosure, copying, distribution, or transmission of this code without + * express permission is prohibited. + */ + +#include "mecha.h" + +struct busSelem { + long msg_type; + /* unsigned int time; */ + void *data; + size_t data_len; + struct busSelem *next; +}; +typedef struct busSelem busTelem; + +struct busSbus { + pthread_rwlock_t lock; + struct busSelem *msgs; + struct busSelem *last_msg; + void (*destructor) (void *); +}; + +busTbus *busFinit(void (*destructor) (void *)) +{ + busTbus *bus; + + bus = (busTbus *) malloc(sizeof(busTbus)); + assert(bus != NULL); + + memFclear(bus, sizeof(busTbus)); + + bus->msgs = NULL; + bus->last_msg = NULL; + bus->destructor = destructor; + + if (pthread_rwlock_init(&bus->lock, NULL) == -1) { + return NULL; + } + return bus; +} + +void busFfree(busTbus * bus) +{ + busTelem *e, *np; + + assert(bus != NULL); + + pthread_rwlock_wrlock(&bus->lock); + + e = bus->msgs; + + while (1) { + bus->destructor(e->data); + np = e->next; + free(e); + if (np == NULL) + break; + e = np; + } + + free(bus); +} + +int busFpush(busTbus * bus, void *data, size_t data_len) +{ + busTelem *elem; + + assert(bus != NULL); + assert(data != NULL); + + elem = (busTelem *) malloc(sizeof(busTelem)); + + assert(elem != NULL); + + elem->data = data; + elem->data_len = data_len; + elem->next = NULL; + + if (pthread_rwlock_wrlock(&bus->lock) == -1) + return -1; + + if (bus->last_msg == NULL) { + bus->msgs = bus->last_msg = elem; + } else { + bus->last_msg->next = elem; + bus->last_msg = elem; + } + + pthread_rwlock_unlock(&bus->lock); + + return 0; +} + +int busFpull(busTbus * bus, void **data) +{ + busTelem *e; + size_t len; + + assert(bus != NULL); + assert(data != NULL); + + if (pthread_rwlock_wrlock(&bus->lock) == -1) + return -1; + + if (bus->msgs == NULL) { + pthread_rwlock_unlock(&bus->lock); + return 0; + } + e = bus->msgs; + if (bus->last_msg == e) { + bus->last_msg = bus->msgs = NULL; + } else { + bus->msgs = e->next; + } + + pthread_rwlock_unlock(&bus->lock); + + *data = e->data; + len = e->data_len; + + free(e); + + return len; +} diff --git a/mk4/continuity/mecha/crc.c b/mk4/continuity/mecha/crc.c new file mode 100644 index 0000000..ee1d2b5 --- /dev/null +++ b/mk4/continuity/mecha/crc.c @@ -0,0 +1,94 @@ +/* + * $Header: /san01/cvs/ashpool/csrc/continuity/mecha/Attic/crc.c,v 1.8 2004/04/30 13:41:56 aleigh Exp $ + */ + +/* + * Copyright (c) 1994, 2004 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Disclosure, copying, distribution, or transmission of this code without + * express permission is prohibited. + */ + +#include "mecha.h" + +static uint32_t crc_table[256] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL +}; + +#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); +#define DO2(buf) DO1(buf); DO1(buf); +#define DO4(buf) DO2(buf); DO2(buf); +#define DO8(buf) DO4(buf); DO4(buf); + +uint32_t crcFcrc32(const unsigned char *buf, unsigned len) +{ + uint32_t crc = 0xffffffffL; + + assert(buf != NULL); + + while (len >= 8) { + DO8(buf); + len -= 8; + } + if (len) + do { + DO1(buf); + } + while (--len); + return crc ^ 0xffffffffL; +} diff --git a/mk4/continuity/mecha/cv.c b/mk4/continuity/mecha/cv.c new file mode 100644 index 0000000..44faf29 --- /dev/null +++ b/mk4/continuity/mecha/cv.c @@ -0,0 +1,381 @@ +/* + * Copyright (c) 1994, 2004 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Use, disclosure, copying, distribution, or transmission of this code without + * express permission is prohibited. + */ + +#include "mecha.h" + +struct cSval { + int type; + + char *str_ptr; + size_t str_len; + + double dbl; + long long integer; + + float flt; + + void (*obj_destruct)(void *, size_t); + void *(*obj_copy)(void *, size_t); + int (*obj_compare)(void *, void *, size_t); + void *obj_ptr; + size_t obj_size; + + size_t refcount; +}; + +int cFval_type_get(cTval *v) +{ + assert(v!=NULL); + return v->type; +} + +void cFval_used(cTval *v) { + assert(v!=NULL); + v->refcount++; +} + +cTval *cFval_init(void) +{ + cTval *v = (cTval *)malloc(sizeof(cTval)); + + assert(v!=NULL); + + v->type=CV_EMPTY; + v->refcount=0; + return v; +} + +void cFval_empty(cTval *v) +{ + assert(v!=NULL); + + switch(v->type) { + case CV_EMPTY: + return; + + case CV_STRING: + if(v->str_ptr!=NULL) { + free(v->str_ptr); + } + break; + + case CV_OBJECT: + if(v->obj_ptr!=NULL && v->obj_destruct!=NULL) { + v->obj_destruct(v->obj_ptr, v->obj_size); + } + v->obj_destruct=NULL; + break; + + /* CV_FLOAT: Do nothing */ + /* CV_INTEGER: Do nothing */ + } + + v->type=CV_EMPTY; +} + +void cFval_free(cTval *v) +{ + assert(v!=NULL); + + if(v->refcount>1) { + v->refcount--; + return; + } + + cFval_empty(v); + + free(v); +} + +void cFval_assign_string(cTval *v, char *str, size_t len) +{ + assert(v!=NULL); + + cFval_empty(v); + + if(str==NULL) { + v->type=CV_EMPTY; + return; + } + + v->type=CV_STRING; + v->str_ptr=str; + v->str_len=len; +} + +void cFval_assign_string_copy(cTval *v, const char *str, size_t len) +{ + assert(v!=NULL); + + cFval_empty(v); + + v->type=CV_STRING; + v->str_ptr=strFncopy(str, len); + v->str_len=len; +} + +void cFval_assign_object(cTval *v, void *obj, size_t size) +{ + assert(v!=NULL); + + cFval_empty(v); + + v->type=CV_OBJECT; + v->obj_ptr=obj; + v->obj_size=size; +} + +void cFval_assign_object_tors(cTval *v, + void (*obj_destructor)(void *, size_t), + void *(*obj_duplicator)(void *, size_t), + int (*obj_comparator)(void *, void *, size_t)) +{ + assert(v!=NULL); + + v->obj_destruct=obj_destructor; + v->obj_copy=obj_duplicator; + v->obj_compare=obj_comparator; +} + +void cFval_assign_float(cTval *v, double value) +{ + assert(v!=NULL); + + cFval_empty(v); + + v->type=CV_FLOAT; + v->dbl=value; +} + +void cFval_assign_integer(cTval *v, long long value) +{ + assert(v!=NULL); + + cFval_empty(v); + + v->type=CV_INTEGER; + v->integer=value; +} + +long long cFval_get_integer(cTval *v) +{ + assert(v!=NULL); + + /* todo: support object converter -aleigh */ + switch(v->type) { + case CV_INTEGER: + return v->integer; + case CV_FLOAT: + return (long long) v->dbl; + case CV_STRING: + return atoll(v->str_ptr); + default: + return 0; + } +} + +double cFval_get_float(cTval *v) +{ + assert(v!=NULL); + + switch(v->type) { + case CV_INTEGER: + return (double) v->integer; + case CV_FLOAT: + return v->dbl; + case CV_STRING: + return (double)atoll(v->str_ptr); + + default: + return 0; + } + + /* todo: Support object converter -aleigh */ +} + +/* Get a const char pointer to the string stored in the cval. + * No conversion to other types is supported because that would + * require the function to return orphaned memory. + */ +const char *cFval_get_string(cTval *v, size_t *size) +{ + assert(v!=NULL); + + if(v->type==CV_STRING) { + *size=v->str_len; + return v->str_ptr; + } + + return NULL; +} + +ssize_t cFval_get_string_copy(cTval *v, char *buf, size_t buf_size) +{ + assert(v!=NULL); + + switch(v->type) { + case CV_INTEGER: + return snprintf(buf,buf_size,"%Ld",v->integer); + case CV_FLOAT: + return snprintf(buf,buf_size,"%e",v->dbl); + case CV_STRING: + if(buf_sizestr_len) { + memFcopy(v->str_ptr,buf,buf_size-1); + buf[buf_size]=0; + return buf_size; + } else { + memFcopy(v->str_ptr,buf,v->str_len); + return v->str_len; + } + default: + return -1; + } +} + +cTval *cFval_copy(cTval *v) +{ + cTval *new=cFval_init(); + + assert(v!=NULL); + assert(new!=NULL); + + switch(v->type) { + case CV_STRING: + new->type=CV_STRING; + new->str_ptr=strFncopy(v->str_ptr,v->str_len); + new->str_len=v->str_len; + break; + case CV_OBJECT: + new->type=CV_OBJECT; + + if(v->obj_copy==NULL) { + new->obj_ptr=v->obj_ptr; + } else { + new->obj_ptr=v->obj_copy(v->obj_ptr,v->obj_size); + } + + new->obj_size=v->obj_size; + new->obj_destruct=v->obj_destruct; + new->obj_copy=v->obj_copy; + new->obj_compare=v->obj_compare; + break; + case CV_FLOAT: + new->type=CV_FLOAT; + new->dbl=v->dbl; + break; + } + return new; +} + +struct cSarray +{ + cTval **vals; + size_t size; + size_t count; +}; + +cTarray *cFarray_new(void) +{ + cTarray *array; + + array=(cTarray *)malloc(sizeof(cTarray)); + assert(array!=NULL); + + array->count=array->size=0; + + return array; +} + +void cFarray_push(cTarray *array, cTval *val) +{ + assert(array!=NULL); + assert(val!=NULL); + + if(array->size==0) { + array->vals=malloc(sizeof(void *)); + assert(array->vals!=NULL); + + array->size=1; + array->vals[0]=val; + array->count++; + } else { + array->size++; + + array->vals=realloc(array->vals,array->size*sizeof(void *)); + assert(array->vals!=NULL); + + array->vals[array->size]=val; + array->count++; + } + val->refcount++; +} + +cTval *cFarray_pop(cTarray *array) +{ + cTval *val; + + assert(array!=NULL); + + if(array->count==0) return NULL; + + int c=0; + for(int i=0;icount;i++) { + if(array->vals[i]!=NULL) { + c++; + } + + if(c==array->count) { + val=array->vals[i]; + array->vals[i]=NULL; + array->count--; + val->refcount--; + return val; + } + } + assert(1!=1); +} + +void *cFarray_foreach(cTarray *array, void *(*callback)(cTval *v)) +{ + void *userdata; + + for(int i=0;isize;i++) { + if(array->vals[i]!=NULL) { + userdata=callback(array->vals[i]); + if(userdata!=NULL) { + return userdata; + } + } + } + return NULL; +} + +void cFarray_free(cTarray *array) { + for(int i=0;isize;i++) { + if(array->vals[i]!=NULL) { + cFval_free(array->vals[i]); + } + } + free(array->vals); + free(array); +} + +struct cSassoc { + cTarray *names; + cTarray *values; + + hshTlist *forward; + hshTlist *reverse; + + size_t count; +}; + + diff --git a/mk4/continuity/mecha/dic.c b/mk4/continuity/mecha/dic.c new file mode 100644 index 0000000..64cd81b --- /dev/null +++ b/mk4/continuity/mecha/dic.c @@ -0,0 +1,134 @@ +/* + * $Header: /san01/cvs/ashpool/csrc/continuity/mecha/Attic/dic.c,v 1.1 2004/04/30 13:41:56 aleigh Exp $ + */ + +/* + * Copyright (c) 2004 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Use, disclosure, copying, distribution, or transmission of this code without + * express permission is prohibited. + */ + +#include "mecha.h" + +/* + * String values are copied into the dictionary so that they may be freed + * by the calling program. They are free'd with the destruction of the + * forward list; the reverse list does not destroy the keys. + */ +struct dicSdictionary { + /* int -> name */ + hshTvoid_list *forward; + /* name -> int */ + hshTvoid_list *reverse; + /* int -> data */ + hshTvoid_list *userdata; + + void(*userdata_destructor)(void *); +}; + +dicTdictionary *dicFinit(void (*destructor) (void *), + int (*comparator) (const void *s1, + const void *s2, + size_t len)) { + dicTdictionary *d; + + d=(dicTdictionary *)malloc(sizeof(dicTdictionary)); + + assert(d!=NULL); + + /* The forward list will be responsible for destroying + * the values placed into the dictionary, so we will + * give it a destructor + */ + d->forward=hshFvoid_int_init(destructor); + assert(d->forward!=NULL); + + d->reverse=hshFvoid_raw_init(NULL,NULL,comparator,16); + assert(d->reverse!=NULL); + + d->userdata=hshFvoid_int_init(NULL); + assert(d->userdata!=NULL); + + return d; +} + +void dicFuserdata_update (dicTdictionary *d, int idx, void *data) { + hshFvoid_int_update(d->userdata,idx,data); +} + +void *dicFuserdata_find(dicTdictionary *d, int idx) { + return hshFvoid_int_find(d->userdata,idx); +} + +void dicFuserdata_destructor_set(dicTdictionary *d, void (*destructor)(void *)) { + assert(d!=NULL); + hshFvalue_destructor_set(d->userdata,destructor); +} + +void dicFfree(dicTdictionary *d) { + hshFvoid_destroy(d->forward); + hshFvoid_destroy(d->reverse); + hshFvoid_destroy(d->userdata); + free(d); +} + +int dicFupdate(dicTdictionary *d, int idx, void *value, size_t value_len) { + assert(d!=NULL); + assert(value!=NULL); + + hshFvoid_int_update(d->forward,idx,value); + hshFvoid_raw_add(d->reverse,value,value_len,(void *)idx,1); + + return 0; +} + +void *dicFfind(dicTdictionary *d, int idx) { + assert(d!=NULL); + assert(d->forward!=NULL); + + return hshFvoid_int_find(d->forward,idx); +} + +int docFfind_index(dicTdictionary *d, void *value, size_t value_len, int *idx) { + void *p; + + assert(d!=NULL); + assert(d->reverse!=NULL); + assert(value!=NULL); + + p=hshFvoid_raw_find(d->reverse, value, value_len); + + if(p==NULL) { + return -1; + } + + *idx=(int)p; + return 0; +} + +char *dicFchar_find(dicTdictionary *d, int idx) { + assert(d!=NULL); + + return (char *)hshFvoid_int_find(d->forward,idx); +} + +int dicFchar_update(dicTdictionary *d, int idx, char *str, size_t str_len) { + assert(d!=NULL); + assert(str!=NULL); + + return dicFupdate(d,idx,(void *)strFncopy(str,str_len),str_len); +} + +dicTdictionary *dicFchar_init(void) { + return dicFinit(free,strncmp); +} + +int dicFchar_find_index(dicTdictionary *d, char *value, size_t value_len, int *idx) { + return docFfind_index(d,(void *)value,value_len,idx); +} + diff --git a/mk4/continuity/mecha/dyn.c b/mk4/continuity/mecha/dyn.c new file mode 100644 index 0000000..fdcda91 --- /dev/null +++ b/mk4/continuity/mecha/dyn.c @@ -0,0 +1,165 @@ +/* + * $Header: /san01/cvs/ashpool/csrc/continuity/mecha/Attic/dyn.c,v 1.18 2004/04/30 13:41:56 aleigh Exp $ + */ + +/* + * Copyright (c) 1994, 2004 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Disclosure, copying, distribution, or transmission of this code without + * express permission is prohibited. + */ + +#define DYN_CHUNK_SZ 1024 + +#include "mecha.h" +#include "dyn.h" + +void dynFreset(dynTstring * ds) +{ + assert(ds != NULL); + ds->strlen = 0; +} + +void dynFfree(dynTstring * ds) +{ + assert(ds); + + if (ds->str != NULL) + free(ds->str); + free(ds); +} + +dynTstring *dynFinit(void) +{ + dynTstring *p; + + p = (dynTstring *) malloc(sizeof(dynTstring)); + + p->str = NULL; + p->len = 0; + p->strlen = 0; + + return p; +} + +static int dynFalloc(dynTstring * ds, int size) +{ + char *p; + + assert(ds != NULL); + + if (ds->str != NULL) { + p = (char *) realloc(ds->str, ds->len + size); + if (p == NULL) + return -1; + + ds->str = p; + ds->len += size; + } else { + ds->str = (char *) malloc(size); + if (ds->str == NULL) + return -1; + + ds->len = size; + + /* make the first byte empty */ + ds->str[0] = 0; + } + return 0; +} + +size_t dynFappend(dynTstring * ds, const char *str, size_t len) +{ + assert(ds != NULL); + assert(str != NULL); + + /* we want to be able to put a NULL at the end */ + if (ds->strlen + len + 1 > ds->len) { + size_t required = len - (ds->len - ds->strlen); + required += DYN_CHUNK_SZ; + dynFalloc(ds, ds->len + required); + } + memcpy(ds->str + ds->strlen, str, len); + ds->strlen += len; + + /* make the end of the string empty */ + ds->str[ds->strlen] = 0; + + return len; +} + +size_t dynFappend_string(dynTstring * ds, const dynTstring * src) +{ + assert(ds != NULL); + assert(src != NULL); + + return (dynFappend(ds, src->str, src->strlen)); +} + +size_t dynFsappend(dynTstring * ds, const char *str) +{ + assert(ds != NULL); + assert(str != NULL); + return dynFappend(ds, str, strlen(str)); +} + +size_t dynFappend_print(dynTstring * ds, const char *fmt, ...) +{ + va_list ap; + char *buf; + size_t size = 1024; + char stack_buf[1024]; + int nchars; + + assert(ds != NULL); + assert(fmt != NULL); + + buf = stack_buf; + size = sizeof(stack_buf); + + assert(buf != NULL); + + va_start(ap, fmt); + + while (1) { + nchars = vsnprintf(buf, size, fmt, ap); + + if (nchars > -1 && nchars < (int) size) + break; + if (nchars > -1) + size = nchars + 1; + else + size *= 2; + + if (buf == stack_buf) { + buf = (char *) malloc(size); + } else { + buf = (char *) realloc(buf, size); + } + } + + va_end(ap); + + dynFappend(ds, buf, nchars); + + if (buf != stack_buf) { + free(buf); + } + return (0); +} + +const char *dynFgetstr(const dynTstring * ds) +{ + assert(ds != NULL); + return ds->str; +} + +size_t dynFgetlen(const dynTstring * ds) +{ + assert(ds != NULL); + return ds->strlen; +} diff --git a/mk4/continuity/mecha/dyn.h b/mk4/continuity/mecha/dyn.h new file mode 100644 index 0000000..82dca6e --- /dev/null +++ b/mk4/continuity/mecha/dyn.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 1994, 2003 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Use, disclosure, copying, distribution, or transmission of of this code + * without express permission is prohibited. + */ + + +#ifndef _DYN_H +#define _DYN_H + +struct dynSstring { + char *str; + size_t len; + size_t strlen; +}; + +#endif diff --git a/mk4/continuity/mecha/exp.c b/mk4/continuity/mecha/exp.c new file mode 100644 index 0000000..5aec598 --- /dev/null +++ b/mk4/continuity/mecha/exp.c @@ -0,0 +1,312 @@ +/* + * $Header: /san01/cvs/ashpool/csrc/continuity/mecha/Attic/exp.c,v 1.9 2004/04/30 13:41:56 aleigh Exp $ + */ + +/* + * Copyright (c) 2004 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Disclosure, copying, distribution, or transmission of of this code without + * express permission is prohibited. + */ + +#include "mecha.h" +#include "../pcre/pcre.h" + +#define OVECCOUNT 30 /* should be a multiple of 3 */ + +void expFregexp_free(expTregexp * re) +{ + pcre_free(re); +} + +expTregexp *expFregexp_compile(const char *pattern) +{ + pcre *re; + const char *error; + int erroffset; + + re = pcre_compile(pattern, /* the pattern */ + 0, /* default options */ + &error, /* for error message */ + &erroffset, /* for error offset */ + NULL); /* use default character tables */ + return (expTregexp *) re; +} + +int expFregexp_match(const expTregexp * regexp, const char *subject) +{ + return expFregexp_match_len(regexp, subject, strlen(subject)); +} + +/* + * Parts of this code derived from code written by Henry Spencer. + * + * The rest is written by Eric Lindvall. + * + */ +int expFregexp_replace(const expTregexp * regexp, const char *subject, + size_t subject_length, const char *replace, + MECHA_UNUSED_ARGUMENT size_t replace_length, char *output, + size_t output_length) +{ + pcre *re = (pcre *) regexp; + int ovector[OVECCOUNT]; + int rc; + register const char *src; + register char *dst; + register char c; + + rc = pcre_exec((pcre *) re, /* the compiled pattern */ + NULL, /* no extra data - we didn't study the + * pattern */ + subject, /* the subject string */ + subject_length, /* the length of the subject */ + 0, /* start at offset 0 in the subject */ + 0, /* default options */ + ovector, /* output vector for substring information */ + OVECCOUNT); /* number of elements in the output vector */ + + if (rc < 0) { + switch (rc) { + case PCRE_ERROR_NOMATCH: + return 0; + default: + return -1; + } + } + + src = replace; + dst = output; + + while ((c = *src++) != '\0' && output_length > 0) { + register int no; + + if (c == '&') { + no = 0; + } else if ((c == '\\' || c == '$') && '0' <= *src && *src <= '9') { + no = *src++ - '0'; + } else { + no = -1; + } + + if (no < 0) { /* Ordinary character. */ + if (c == '\\' && (*src == '\\' || *src == '&')) { + c = *src++; + } + *dst++ = c; + output_length--; + } else if (no <= rc) { + int len = + pcre_copy_substring(subject, ovector, rc, no, dst, + output_length); + + if (len < 0) { + return (len); + } + output_length -= len; + dst += len; + } + } + + if (output_length < 1) { + return (-1); + } + *dst++ = '\0'; + output_length--; + + return 1; +} + +int expFregexp_match_len(const expTregexp * regexp, const char *subject, + size_t subject_length) +{ + pcre *re = (pcre *) regexp; + int ovector[OVECCOUNT]; + int rc; + + rc = pcre_exec((pcre *) re, /* the compiled pattern */ + NULL, /* no extra data - we didn't study the + * pattern */ + subject, /* the subject string */ + subject_length, /* the length of the subject */ + 0, /* start at offset 0 in the subject */ + 0, /* default options */ + ovector, /* output vector for substring information */ + OVECCOUNT); /* number of elements in the output vector */ + + if (rc < 0) { + switch (rc) { + case PCRE_ERROR_NOMATCH: + return 0; + default: + return -1; + } + } + return 1; +} + +int expFmatch(const char *pattern, const char *subject) +{ + + assert(pattern!=NULL); + assert(subject!=NULL); + + return expFmatch_len(pattern, subject, strlen(subject)); +} + +int expFmatch_len(const char *pattern, const char *subject, + size_t subject_length) +{ + pcre *re; + const char *error; + int erroffset; + int ovector[OVECCOUNT]; + int rc; + + assert(pattern!=NULL); + assert(subject!=NULL); + + /************************************************************************* + * Now we are going to compile the regular expression pattern, and handle * + * and errors that are detected. * + *************************************************************************/ + + re = pcre_compile(pattern, /* the pattern */ + 0, /* default options */ + &error, /* for error message */ + &erroffset, /* for error offset */ + NULL); /* use default character tables */ + + if (re == NULL) { + return -1; + } + + /************************************************************************* + * If the compilation succeeded, we call PCRE again, in order to do a * + * pattern match against the subject string. This just does ONE match. If * + * further matching is needed, it will be done below. * + *************************************************************************/ + + rc = pcre_exec(re, /* the compiled pattern */ + NULL, /* no extra data - we didn't study the + * pattern */ + subject, /* the subject string */ + subject_length, /* the length of the subject */ + 0, /* start at offset 0 in the subject */ + 0, /* default options */ + ovector, /* output vector for substring information */ + OVECCOUNT); /* number of elements in the output vector */ + + pcre_free(re); + + if (rc < 0) { + switch (rc) { + case PCRE_ERROR_NOMATCH: + return 0; + default: + return -1; + } + } + return 1; +} + +int expFapply(const char *pattern, const char *subject, lstTset * output) +{ + pcre *re; + const char *error; + int erroffset; + int ovector[OVECCOUNT]; + int subject_length; + int rc, i; + + assert(pattern != NULL); + assert(subject != NULL); + assert(output != NULL); + + subject_length = (int) strlen(subject); + + /************************************************************************* + * Now we are going to compile the regular expression pattern, and handle * + * and errors that are detected. * + *************************************************************************/ + + re = pcre_compile(pattern, /* the pattern */ + 0, /* default options */ + &error, /* for error message */ + &erroffset, /* for error offset */ + NULL); /* use default character tables */ + + /* Compilation failed: print the error message and exit */ + + if (re == NULL) { + return -1; + } + /************************************************************************* + * If the compilation succeeded, we call PCRE again, in order to do a * + * pattern match against the subject string. This just does ONE match. If * + * further matching is needed, it will be done below. * + *************************************************************************/ + + rc = pcre_exec(re, /* the compiled pattern */ + NULL, /* no extra data - we didn't study the + * pattern */ + subject, /* the subject string */ + subject_length, /* the length of the subject */ + 0, /* start at offset 0 in the subject */ + 0, /* default options */ + ovector, /* output vector for substring information */ + OVECCOUNT); /* number of elements in the output vector */ + + /* Matching failed: handle error cases */ + + if (rc < 0) { + switch (rc) { + case PCRE_ERROR_NOMATCH: + return 0; + default: + return -1; + } + } + + /************************************************************************* + * We have found the first match within the subject string. If the output * + * vector wasn't big enough, set its size to the maximum. Then output any * + * substrings that were captured. * + *************************************************************************/ + + /* The output vector wasn't big enough */ + + if (rc == 0) { + rc = OVECCOUNT / 3; + /* Output vector not big enough */ + return -2; + } + /* + * Show substrings stored in the output vector by number. Obviously, in a + * real application you might want to do things other than print them. + */ + + for (i = 0; i < rc; i++) { + char *substring_start = (char *) subject + ovector[2 * i]; + int substring_length = ovector[2 * i + 1] - ovector[2 * i]; + char back; + + logFmsg(3, "length is %d", substring_length); + + back = substring_start[substring_length + 1]; + substring_start[substring_length + 1] = '\0'; + + lstFset_add(output, utlFshort_to_str(i), substring_start); + + substring_start[substring_length + 1] = back; + + /* printf("%2d: %.*s\n", i, substring_length, substring_start); */ + + } + + return 1; +} diff --git a/mk4/continuity/mecha/fle.c b/mk4/continuity/mecha/fle.c new file mode 100644 index 0000000..06089f9 --- /dev/null +++ b/mk4/continuity/mecha/fle.c @@ -0,0 +1,303 @@ +/* + * $Header: /san01/cvs/ashpool/csrc/continuity/mecha/Attic/fle.c,v 1.18 2004/05/11 20:39:12 aleigh Exp $ + */ + +/* + * Copyright (c) 1994, 2004 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Disclosure, copying, distribution, or transmission of this code without + * express permission is prohibited. + */ + +#include "mecha.h" + +#define MAX_LINKS 32 /* Maximum number of links we are willing to + * recurse */ + +int fleFset_close_exec(int fd) +{ + int fd_flags; + + /* Set the socket to nonblocking */ + if ((fd_flags = fcntl(fd, F_GETFD)) == -1) { + perror("fcntl"); + return -1; + } + fd_flags |= FD_CLOEXEC; + + if (fcntl(fd, F_SETFD, fd_flags) == -1) { + perror("fcntl"); + return -1; + } + return (0); +} + +int fleFpath_combine(const char *path, int path_len, const char *relative, + char *output, int output_len) +{ + int second_length = 0; + + if (output_len < path_len) { + path_len = output_len; + } + memcpy(output, path, path_len); + + /* make sure we even have room to do anything else */ + if (path_len == output_len) { + /* + * should we return what we could do or return -1 because we couldn't + * combine them? + * + * -eric@5stops.com - 1.29.2004 + * + */ + return (path_len); + } + if (output[path_len - 1] == '/') { + output[--path_len] = 0; + } + second_length = + fleFpath_simplify(relative, output + path_len, + output_len - path_len); + + if (output[path_len] != '/') { + if (output_len <= (path_len + second_length + 1)) { + second_length = output_len - path_len - 2; + } + memmove(output + path_len + 1, output + path_len, second_length); + + output[path_len++] = '/'; + + output[path_len + second_length] = 0; + } + return (path_len + second_length); +} + +int fleFpath_simplify(const char *path, char *outpath, int len) +{ + const char *cur_path; + char *cur_outpath; + + assert(path != NULL); + assert(outpath != NULL); + + cur_path = path; + cur_outpath = outpath; + + while (*cur_path != 0 && (cur_outpath - outpath) < (len - 1)) { + if (*cur_path == '/') { + if (cur_path[1] == '.' + && (cur_path[2] == 0 || cur_path[2] == '/')) { + cur_path += 2; + + continue; + } else if (cur_path[1] == '/') { + cur_path++; + + continue; + } else if (cur_path[1] == '.' && cur_path[2] == '.' && + (cur_path[3] == 0 || cur_path[3] == '/')) { + while (cur_outpath > outpath && *(--cur_outpath) != '/'); + + if (cur_outpath == outpath) { + *cur_outpath = '/'; + } + cur_path += 3; + + continue; + } + } + *cur_outpath++ = *cur_path++; + } + + *cur_outpath = 0; + + return ((int) (cur_outpath - outpath)); +} + +void fleFpath_clean(char *pathname) +{ + char *cleanpath, c; + + assert(pathname != NULL); + + cleanpath = pathname; + while ((c = *pathname++)) { + if (c == '/') { + while (1) { + if (*pathname == '/') + pathname++; + else if (*pathname == '.' && *(pathname + 1) == '/') + pathname += 2; + else if (*pathname == '.' && *(pathname + 1) == '.' && + *(pathname + 2) == '/') { + pathname += 3; + } else + break; + } + c = '/'; + } + *cleanpath++ = c; + } + *cleanpath = '\0'; +} + +int fleFlock(const char *filename) +{ + char lockpath[1024]; + int fd; + + assert(filename != NULL); + + snprintf(lockpath, sizeof(lockpath), "%s.lock", filename); + + fd = open(lockpath, O_CREAT | O_EXCL | O_WRONLY, 0644); + + if (fd < 0) + return 0; + + close(fd); + + return 1; +} + +int fleFunlock(const char *filename) +{ + char lockpath[1024]; + + assert(filename != NULL); + + snprintf(lockpath, sizeof(lockpath), "%s.lock", filename); + + if (unlink(lockpath) < 0) + return 0; + return 1; +} + +int fleFsync_mem_to_file(char *filename, const char *memory, size_t len) +{ + int fd; + char *map; + + assert(filename != NULL); + assert(memory != NULL); + + fd = open(filename, O_RDWR, 0644); + if (fd < 0) + return -1; + + map = mmap((void *) 0, len, (PROT_READ | PROT_WRITE), 0, fd, 0); + assert(map != NULL); + + close(fd); + + if (map == MAP_FAILED) + return -1; + + memFcopy(memory, map, len); + + munmap(map, len); + + return len; +} + +int fleFexist(const char *filename) { +#ifndef _LP64 + struct stat sb; +#else + struct stat64 sb; +#endif + + assert(filename!=NULL); + + if(stat(filename,&sb)==0) { + return 1; + } + + return 0; +} + +/* How can this return -1 if it's not a ssize_t? -aleigh */ +size_t fleFget_size(const char *filename) +{ +#ifndef _LP64 + struct stat sb; +#else + struct stat64 sb; +#endif + + assert(filename != NULL); + + if (stat(filename, &sb) < 0) + return -1; + + return sb.st_size; +} + +char *fleFload_file(const char *filename, size_t * len) +{ + int fd; + size_t size; + char *map; + char *target; + + assert(filename != NULL); + assert(len != NULL); + + fd = open(filename, O_RDONLY, 0644); + if (fd < 0) + return NULL; + + size = fleFget_size(filename); + + map = mmap(0, size, PROT_READ, MAP_SHARED, fd, 0); + + close(fd); + + assert(map != NULL); + + if (map == MAP_FAILED) { + return NULL; + } + target = (char *) malloc(size); + memFcopy(map, target, size); + + *len = size; + + munmap(map, size); + + return target; +} + +void fleFrotate(int count, const char *fn) { + int i; + char buf1[1024]; + char buf2[1024]; + + assert(fn!=NULL); + assert(count>0); + + for(i=count;i>0;i--) { + snprintf(buf1,1024,"%s.%d", fn, i); + + /* The last file we just delete. */ + if(i==count) { + unlink(buf1); + continue; + } + + /* The first file we get from *fn */ + if(i==1) { + snprintf(buf1,1024,"%s.%d",fn,1); + rename(fn,buf1); + break; + } + + snprintf(buf2,1024,"%s.%d",fn,i-1); + rename(buf2,buf1); + } +} diff --git a/mk4/continuity/mecha/hsh.c b/mk4/continuity/mecha/hsh.c new file mode 100644 index 0000000..db80aca --- /dev/null +++ b/mk4/continuity/mecha/hsh.c @@ -0,0 +1,837 @@ +/* + * $Header: /san01/cvs/ashpool/csrc/continuity/mecha/Attic/hsh.c,v 1.24 2004/05/27 14:31:42 aleigh Exp $ + */ + +/* + * Copyright (c) 1994, 2004 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Use, disclosure, copying, distribution, or transmission of this code without + * express permission is prohibited. + */ + +/* + * TA/hashlist general purpose hasing algorithm system. Alex Leigh, + * 1994,1997,1999, 2000 $Id: hsh.c,v 1.24 2004/05/27 14:31:42 aleigh Exp $ + */ + +/* + * hsh provides a general purpose, efficient data storage and retrieval + * system. The alogrithm can store an arbitrary list of sequential + * name/keyvalue pairs, each list being keyed by a character string. + * + */ + +#include "mecha.h" + +/* double-check to make sure hashing is working properly */ +#undef VALIDATING_HASH + +#define DEFAULT_HSH_SIZE 16 + +/* + * the maximum number of elements in the hashtable that are allowed for the + * hashtable to use a linear search to find. + */ +#define LINEAR_SEARCH_MAX_COUNT 0 + +unsigned int hshGrand8[256] = + { 16838, 5758, 10113, 17515, 31051, 5627, 23010, + 7419, 16212, 4086, 2749, 12767, 9084, 12060, + 32225, 17543, 25089, 21183, 25137, 25566, 26966, 4978, + 20495, 10311, 11367, 30054, 17031, 13145, 19882, 25736, + 30524, 28505, 28394, 22102, 24851, 19067, 12754, 11653, + 6561, 27096, 13628, 15188, 32085, 4143, 6967, 31406, + 24165, 13403, 25562, 24834, 31353, 920, 10444, 24803, + 7962, 19318, 1422, 31327, 10457, 1945, 14479, 29983, + 18751, 3894, 18670, 8259, 16248, 7757, 15629, 13306, + 28606, 13990, 11738, 12516, 1414, 5262, 17116, 22825, + 3181, 13134, 25343, 8022, 11233, 7536, 9760, 9979, + 29071, 1201, 21336, 13061, 22160, 24005, 30729, 7644, + 27475, 31693, 25514, 14139, 22088, 26521, 5202, 9171, 4434, + 28317, 24582, 6815, 4586, 9653, 26306, 7174, 18451, 23448, + 6473, 32434, 8193, 14110, 24748, 28210, 29320, 32049, + 12956, 14162, 4166, 14997, 7793, 32310, 21391, 19799, + 7926, 14905, 25885, 2582, 15610, 5000, 8052, 30965, 20120, + 32380, 15639, 26204, 24385, 12475, 15725, 17265, 3214, + 19471, 11376, 4697, 25543, 23297, 14619, 23087, 3123, + 31549, 18065, 24256, 18973, 20901, 25613, 6157, 9899, + 9267, 22413, 9598, 18526, 13711, 10046, 14566, 18536, + 15988, 19878, 13626, 4273, 8387, 1171, 32017, 3752, 12388, + 21191, 11483, 18122, 11744, 18528, 15585, 5363, 20159, + 5641, 18176, 9575, 28578, 27363, 27685, 29344, 19489, + 17713, 5511, 21461, 22626, 8645, 3496, 26703, 6270, 13870, + 11529, 27499, 4500, 8607, 5808, 15725, 12457, 16542, 16474, + 11531, 17222, 3952, 17024, 19894, 24015, 18247, 11276, + 26278, 19365, 8746, 21976, 18092, 25851, 29088, 29163, + 2231, 26233, 29732, 21106, 5411, 9874, 5448, 9344, 27589, + 17574, 1191, 6789, 695, 11735, 20364, 17040, 17892, 5035, + 26979, 1092, 850, 12390, 20195, 668, 20531, 29989, 12281, 23902 +}; + +int hshGprimes[] = { 11, 19, 37, 73, 109, 163, 251, 367, 557, + 823, 1237, 1861, 2777, 4177, 6247, 9371, 14057, 21089, + 31627, 47431, 71143, 106721, 160073, 240101, 360163, + 540217, 810343, 1215497, 1823231, 2734867, 4102283, + 6153409, 9230113, 13845163, -1 +}; + +struct hshSvoid_node { + char *name; + unsigned short int hashcode; + + size_t name_len; + void *data; + struct hshSvoid_node *next; +}; +typedef struct hshSvoid_node hshTvoid_node; + +struct hshSvoid_list { + struct hshSvoid_node **nodes; + void (*destructor) (void *); + void (*name_destructor) (void *); + int (*name_comparator) (const void *s1, const void *s2, size_t len); + unsigned int serial; + + unsigned int size; + unsigned int count; + float load_factor; + unsigned int collisions; + unsigned int threshold; +}; + +struct hshSiterator { + unsigned int serial; + unsigned int count; + struct hshSvoid_list *list; + hshTvoid_node *node; +}; + +static int hshFvoid_next_size(int size); +static void hshFvoid_resize(hshTvoid_list * list); +static void hshFvoid_adjust_threshold(hshTvoid_list * list); +static hshTvoid_node *_hshFvoid_raw_find(hshTvoid_list * list, + const char *name, + size_t name_len); +static void _hshFvoid_node_free(hshTvoid_list * list, hshTvoid_node * node, + int free_value); +static void *_hshFvoid_raw_remove(hshTvoid_list * list, const char *name, + size_t name_len, int free_value); + +void hshFvalue_destructor_set(hshTvoid_list *list, void (*destructor)(void *)) { + assert(list!=NULL); + + list->destructor=destructor; +} + +/* + * aleigh- calculate the hash value for a given string. This hash value is + * based on the random set. Assuming the set is sufficiently random, the data + * should distribute in a random way throughout the hashspace. + */ +unsigned short int hshFraw_hash(const char *str, size_t len, + unsigned int buckets) +{ + return (hshFraw_hashcode(str, len) % buckets); +} + +unsigned short int hshFraw_hashcode(const char *str, size_t len) +{ + unsigned short int h; + unsigned char h1, h2; + size_t pos = 0; + + assert(str != NULL); + + h1 = *str; + h2 = *(str + 1); + str++; + pos++; + + if (pos != len) + while (1) { + h1 = hshGrand8[h1 ^ *str]; + h2 = hshGrand8[h2 ^ *str]; + str++; + pos++; + if (pos == len) + break; + } + + h = ((unsigned short int) h1 << 8) | (unsigned short int) h2; + return (h); +} + +unsigned short int hshFhash(const char *str) +{ + assert(str != NULL); + return hshFraw_hash(str, strlen(str), DEFAULT_HSH_SIZE); +} + +/**********************************************************************/ + +/* + * VOID hash list implementation This is the currently recommended + * implementation, because it uses less space in memory and is slightly + * faster. + */ + +hshTvoid_list *hshFvoid_init(void (*destructor) (void *)) +{ + return hshFvoid_raw_init(destructor, free, memcmp, DEFAULT_HSH_SIZE); +} + +hshTvoid_list *hshFvoid_int_init(void (*destructor) (void *)) +{ + return hshFvoid_raw_init(destructor, free, memcmp, DEFAULT_HSH_SIZE); +} + +hshTvoid_list *hshFvoid_raw_init(void (*destructor) (void *), + void (*name_destructor) (void *), + int (name_comparator) (const void *s1, + const void *s2, + size_t len), + unsigned int buckets) +{ + hshTvoid_list *list; + + list = (hshTvoid_list *) malloc(sizeof(hshTvoid_list)); + memFclear(list, sizeof(hshTvoid_list)); + list->destructor = destructor; + list->name_destructor = name_destructor; + list->name_comparator = name_comparator; + list->load_factor = 0.75; + list->count = 0; + + list->nodes = + (hshTvoid_node **) malloc(sizeof(hshTvoid_node) * buckets); + memFclear(list->nodes, sizeof(hshTvoid_node) * buckets); + list->size = buckets; + + hshFvoid_adjust_threshold(list); + + return list; +} + +static int hshFvoid_next_size(int size) +{ + int i; + + size *= 2; + + for (i = 0; hshGprimes[i] != -1; i++) { + if (size <= hshGprimes[i]) { + return (hshGprimes[i]); + } + } + + /* + * if we don't have a prime number big enough, just double the size and + * go with that -- we should fix this. + */ + return (size); +} + +static void hshFvoid_resize(hshTvoid_list * list) +{ + int new_size = hshFvoid_next_size(list->size); + int collisions = 0; + size_t i; + struct hshSvoid_node **nodes; + + nodes = (hshTvoid_node **) calloc(new_size, sizeof(hshTvoid_node)); + + for (i = 0; i < list->size; i++) { + hshTvoid_node *node = list->nodes[i]; + + while (node != NULL) { + hshTvoid_node *next_node = node->next; + int hash = node->hashcode % new_size; + + node->next = NULL; + + if (nodes[hash] == NULL) { + nodes[hash] = node; + } else { + node->next = nodes[hash]; + nodes[hash] = node; + + collisions++; + } + + node = next_node; + } + } + + free(list->nodes); + + list->nodes = nodes; + list->size = new_size; + list->collisions = collisions; + list->serial++; + + hshFvoid_adjust_threshold(list); +} + +static void hshFvoid_adjust_threshold(hshTvoid_list * list) +{ + list->threshold = (int) (((float) list->size) * list->load_factor); + + if (list->threshold >= list->size) { + list->threshold = list->size - 1; + } +} + +int hshFvoid_size(hshTvoid_list * list) +{ + return (list->count); +} + +/* Deprecated */ +void hshFvoid_int_replace(hshTvoid_list *list, const int key, void *data) { + hshFvoid_int_update(list,key,data); +} + +void hshFvoid_int_update(hshTvoid_list * list, const int key, void *data) +{ + char *p = malloc(sizeof(int)); + + memcpy(p, &key, sizeof(int)); + hshFvoid_raw_add(list, p, sizeof(int), data, 1); +} + +int hshFvoid_int_add(hshTvoid_list * list, const int key, void *data) +{ + char *p = malloc(sizeof(int)); + + memcpy(p, &key, sizeof(int)); + return (hshFvoid_raw_add(list, p, sizeof(int), data, 0)); +} + +/* Deprecated */ +void hshFvoid_replace(hshTvoid_list * list, const char *name, void *data) { + hshFvoid_update(list,name,data); +} + +void hshFvoid_update(hshTvoid_list * list, const char *name, void *data) +{ + char *p = strdup(name); + + hshFvoid_raw_add(list, p, strlen(name), data, 1); +} + +int hshFvoid_add(hshTvoid_list * list, const char *name, void *data) +{ + char *p = strdup(name); + + return (hshFvoid_raw_add(list, p, strlen(name), data, 0)); +} + +int hshFvoid_raw_add(hshTvoid_list * list, char *name, size_t name_len, + void *data, int replace) +{ + unsigned short int hash, hashcode; + hshTvoid_node *node; + + if (list->count >= list->threshold) { + hshFvoid_resize(list); + } + hashcode = hshFraw_hashcode(name, name_len); + + hash = hashcode % list->size; + + if (list->nodes[hash] != NULL) { + hshTvoid_node *curNode, *prevNode; + + for (curNode = prevNode = list->nodes[hash]; curNode != NULL; + prevNode = curNode, curNode = curNode->next) { + if (curNode->name_len == name_len && + list->name_comparator(curNode->name, name, + name_len) == 0) { + /* + * if we aren't looking to replace the node, if the node + * already exists, we just return that we didn't add anything + */ + if (replace == 0) { + return (0); + } else { + /* + * if we're supposed to replace the node, we have to + * delete the node if it exists + */ + if (list->nodes[hash] == curNode) { + list->nodes[hash] = curNode->next; + } else { + prevNode->next = curNode->next; + } + + _hshFvoid_node_free(list, curNode, 1); + } + + break; + } + } + } + node = (hshTvoid_node *) malloc(sizeof(hshTvoid_node)); + node->hashcode = hashcode; + node->data = data; + node->name = name; + node->name_len = name_len; + node->next = NULL; + + if (list->nodes[hash] == NULL) { + list->nodes[hash] = node; + } else { + node->next = list->nodes[hash]; + list->nodes[hash] = node; + list->collisions++; + } + + list->serial++; + list->count++; + + return (1); +} + +static hshTvoid_node *_hshFvoid_raw_find_hash(hshTvoid_list * list, + const char *name, + size_t name_len) +{ + unsigned short int hash; + hshTvoid_node *node; + + assert(name != NULL); + + hash = hshFraw_hash(name, name_len, list->size); + + if (list->nodes[hash] == NULL) + return NULL; + + for (node = list->nodes[hash]; node != NULL; node = node->next) { + if (node->name_len == name_len) { + if (list->name_comparator(node->name, name, name_len) == 0) + return node; + } + } + + return NULL; +} + + +static hshTvoid_node *_hshFvoid_raw_find_linear(hshTvoid_list * list, + const char *name, + size_t name_len) +{ + size_t i; + hshTvoid_node *node; + + assert(name != NULL); + + for (i = 0; i < list->size; i++) { + for (node = list->nodes[i]; node != NULL; node = node->next) { + if (node->name_len == name_len) { + if (list->name_comparator(node->name, name, name_len) == 0) + return node; + } + } + } + + return NULL; +} + +static hshTvoid_node *_hshFvoid_raw_find(hshTvoid_list * list, + const char *name, size_t name_len) +{ + hshTvoid_node *node; + + assert(name != NULL); + + if (list->count == 0) { + return (NULL); + } +#ifdef VALIDATING_HASH + { + hshTvoid_node *linear_node, *hash_node; + + linear_node = _hshFvoid_raw_find_linear(list, name, name_len); + hash_node = _hshFvoid_raw_find_hash(list, name, name_len); + + + assert(linear_node == hash_node); + + node = hash_node; + } +#else + if (list->count <= LINEAR_SEARCH_MAX_COUNT) { + node = _hshFvoid_raw_find_linear(list, name, name_len); + } else { + node = _hshFvoid_raw_find_hash(list, name, name_len); + } +#endif + + return (node); +} + +void *hshFvoid_find(hshTvoid_list * list, const char *name) +{ + return hshFvoid_raw_find(list, name, strlen(name)); +} + +void *hshFvoid_int_find(hshTvoid_list * list, int key) +{ + return hshFvoid_raw_find(list, (char *) &key, sizeof(int)); +} + +void *hshFvoid_raw_find(hshTvoid_list * list, const char *name, + size_t name_len) +{ + hshTvoid_node *node; + + assert(list != NULL); + assert(name != NULL); + + node = _hshFvoid_raw_find(list, name, name_len); + if (node == NULL) + return node; + return node->data; +} + +int hshFvoid_contains(hshTvoid_list * list, const char *key) +{ + hshTvoid_node *node = _hshFvoid_raw_find(list, key, strlen(key)); + + if (node != NULL) { + return (1); + } else { + return (0); + } +} + +int hshFvoid_int_contains(hshTvoid_list * list, int key) +{ + hshTvoid_node *node = + _hshFvoid_raw_find(list, (char *) &key, sizeof(int)); + + if (node != NULL) { + return (1); + } else { + return (0); + } +} + +static void _hshFvoid_node_free(hshTvoid_list * list, hshTvoid_node * node, + int free_data) +{ + assert(node->name != NULL); + assert(node->data != NULL); + + if (free_data && list->destructor != NULL && node->data != NULL) { + list->destructor(node->data); + } + if (list->name_destructor != NULL && node->name != NULL) { + list->name_destructor(node->name); + } + free(node); +} + +void hshFvoid_del(hshTvoid_list * list, const char *name) +{ + hshFvoid_raw_del(list, name, strlen(name)); +} + +void hshFvoid_int_del(hshTvoid_list * list, int key) +{ + hshFvoid_raw_del(list, (char *) &key, sizeof(int)); +} + +void hshFvoid_raw_del(hshTvoid_list * list, const char *name, + size_t name_len) +{ + _hshFvoid_raw_remove(list, name, name_len, 1); +} + +void *hshFvoid_remove(hshTvoid_list * list, const char *name) +{ + return (hshFvoid_raw_remove(list, name, strlen(name))); +} + +void *hshFvoid_int_remove(hshTvoid_list * list, int key) +{ + return (hshFvoid_raw_remove(list, (char *) &key, sizeof(int))); +} + +void *hshFvoid_raw_remove(hshTvoid_list * list, const char *name, + size_t name_len) +{ + return (_hshFvoid_raw_remove(list, name, name_len, 0)); +} + +static void *_hshFvoid_raw_remove(hshTvoid_list * list, const char *name, + size_t name_len, int free_value) +{ + hshTvoid_node *p, *last; + unsigned short int hash; + void *data = NULL; + + assert(list != NULL); + assert(name != NULL); + + hash = hshFraw_hash(name, name_len, list->size); + + list->serial++; + + if (list->nodes[hash] == NULL) + return (NULL); + + for (p = last = list->nodes[hash]; p != NULL; last = p, p = p->next) { + if (p->name_len == name_len && + list->name_comparator(p->name, name, name_len) == 0) { + if (list->nodes[hash] == p) { + /* First entry */ + list->nodes[hash] = p->next; + break; + } else { + last->next = p->next; + break; + } + } + } + + if (p != NULL) { + if (free_value) { + data = NULL; + } else { + data = p->data; + } + + _hshFvoid_node_free(list, p, free_value); + + list->count--; + } + return (data); +} + +void hshFvoid_free(hshTvoid_list *list) { + hshFvoid_destroy(list); +} + +/* DEPRECATED */ +void hshFvoid_destroy(hshTvoid_list * list) +{ + size_t i = 0; + + for (i = 0; i < list->size; i++) { + hshTvoid_node *node = list->nodes[i]; + + while (node != NULL) { + hshTvoid_node *next = node->next; + + _hshFvoid_node_free(list, node, 1); + + node = next; + } + } + + free(list->nodes); + + free(list); +} + + +hshTiterator *hshFiterator_init(hshTvoid_list * list) +{ + hshTiterator *it; + + assert(list != NULL); + + it = (hshTiterator *) malloc(sizeof(hshTiterator)); + + it->list = list; + it->count = 0; + it->serial = list->serial; + it->node = NULL; + + return it; + +} + +int hshFiterator_next(hshTiterator * iterator) +{ + assert(iterator != NULL); + + if (iterator->serial != iterator->list->serial) + return -2; + + if (iterator->node != NULL) { + if (iterator->node->next != NULL) { + iterator->node = iterator->node->next; + return 1; + } else { + iterator->count++; + iterator->node = NULL; + } + } + for (; iterator->count < iterator->list->size; iterator->count++) { + iterator->node = iterator->list->nodes[iterator->count]; + if (iterator->node == NULL) + continue; + return 1; + } + + return 0; +} + +void *hshFiterator_current_key(hshTiterator * iterator) +{ + assert(iterator != NULL); + assert(iterator->node != NULL); + + return iterator->node->name; +} + +void *hshFiterator_current_value(hshTiterator * iterator) +{ + assert(iterator != NULL); + assert(iterator->node->data != NULL); + + return iterator->node->data; +} + + +void hshFiterator_free(hshTiterator * iterator) +{ + assert(iterator != NULL); + + free(iterator); +} + +void hshFiterator_reset(hshTiterator * iterator) +{ + iterator->count = 0; + iterator->serial = iterator->list->serial; + iterator->node = NULL; +} + +dynTstring *hshFdiag_output(hshTvoid_list * list) +{ + dynTstring *string = dynFinit(); + + dynFappend_print(string, "hash diag %p:\n", list); + + dynFappend_print(string, " serial: %d size: %d count: %d\n", + list->serial, list->size, list->count); + + dynFappend_print(string, + " load_factor: %.2f collisions: %d threshold: %d\n", + list->load_factor, list->collisions, list->threshold); + + dynFsappend(string, " elems:\n"); + + { + unsigned int i; + + for (i = 0; i < list->size; i++) { + hshTvoid_node *node; + + for (node = list->nodes[i]; node != NULL; node = node->next) { + dynFappend_print(string, " %d] %s: hashcode: %d\n", + i, node->name, node->hashcode); + } + } + } + + return (string); +} + +/* + * 32 bit magic FNV-1a prime + */ +#define FNV_32_PRIME ((uint32_t)0x01000193) +#define FNV1_32_INIT ((uint32_t)0x811c9dc5) +#define FNV1_32A_INIT FNV1_32_INIT + +uint32_t hshFraw_hash32(const void *buf, size_t len, uint32_t buckets) +{ + return hshFraw_hashcode32(buf, len) % buckets; +} + +/* + * fnv_32a_buf - perform a 32 bit Fowler/Noll/Vo FNV-1a hash on a buffer + * + * input: buf - start of buffer to hash len - length of buffer in octets + * hval - previous hash value or 0 if first call + * + * returns: 32 bit hash as a static hash type + * + * NOTE: To use the recommended 32 bit FNV-1a hash, use FNV1_32A_INIT as the + * hval arg on the first call to either fnv_32a_buf() or fnv_32a_str(). + */ +uint32_t hshFraw_hashcode32(const void *buf, size_t len) +{ + uint32_t hval = FNV1_32A_INIT; + unsigned char *bp = (unsigned char *) buf; /* start of buffer */ + unsigned char *be = bp + len; /* beyond end of buffer */ + + /* + * FNV-1a hash each octet in the buffer + */ + while (bp < be) { + + /* xor the bottom with the current octet */ + hval ^= (uint32_t) * bp++; + + /* multiply by the 32 bit FNV magic prime mod 2^32 */ +#if defined(NO_FNV_GCC_OPTIMIZATION) + hval *= FNV_32_PRIME; +#else + hval += + (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + + (hval << 24); +#endif + } + + /* return our new hash value */ + return hval; +} + + +/* + * fnv_32a_str - perform a 32 bit Fowler/Noll/Vo FNV-1a hash on a string + * + * input: str - string to hash hval - previous hash value or 0 if first + * call + * + * returns: 32 bit hash as a static hash type + * + * NOTE: To use the recommended 32 bit FNV-1a hash, use FNV1_32A_INIT as the + * hval arg on the first call to either fnv_32a_buf() or fnv_32a_str(). + */ +uint32_t hshFhash32(const char *str) +{ + uint32_t hval = FNV1_32A_INIT; + unsigned char *s = (unsigned char *) str; /* unsigned string */ + + /* + * FNV-1a hash each octet in the buffer + */ + while (*s) { + + /* xor the bottom with the current octet */ + hval ^= (uint32_t) * s++; + + /* multiply by the 32 bit FNV magic prime mod 2^32 */ +#if defined(NO_FNV_GCC_OPTIMIZATION) + hval *= FNV_32_PRIME; +#else + hval += + (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + + (hval << 24); +#endif + } + + /* return our new hash value */ + return hval; +} diff --git a/mk4/continuity/mecha/hsh_dep.c b/mk4/continuity/mecha/hsh_dep.c new file mode 100644 index 0000000..7bc812d --- /dev/null +++ b/mk4/continuity/mecha/hsh_dep.c @@ -0,0 +1,267 @@ +/* + * $Header: /cvsroot/csrc/continuity/mecha/hsh_dep.c,v 1.7 2004/01/23 + * 15:38:14 aleigh Exp $ + */ + +/* + * Copyright (c) 1994, 2004 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Use, disclosure, copying, distribution, or transmission of this code without + * express permission is prohibited. + */ + +/* + * TA/hashlist general purpose hasing algorithm system. Alex Leigh, + * 1994,1997,1999, 2000 $Id: hsh_dep.c,v 1.9 2004/03/18 15:04:15 aleigh Exp $ + */ + +/* + * hsh provides a general purpose, efficient data storage and retrieval + * system. The alogrithm can store an arbitrary list of sequential + * name/keyvalue pairs, each list being keyed by a character string. + * + */ + +#include "../include/csys.h" + +struct hshSentry { + char *name; + char *value; + struct hshSentry *next; +}; +typedef struct hshSentry hshTentry; + +struct hshSnode { + struct hshSentry *entry; + char *name; + struct hshSnode *next; +}; +typedef struct hshSnode hshTnode; + +struct hshShash { + struct hshSnode *t; +}; +typedef struct hshShash hshThash; + +struct hshSlist { + struct hshSnode *nodes[65536]; + int ref; +}; +typedef struct hshSlist hshTlist; + +#define _HSH_DEP_C +#include "../include/mecha.h" + +/***************** + * Tradidtional hash list implementation DEPRECATED + * This interface has worked well for a long time, but was originally + * designed to do something else, as evidenced by all the now + * reundant structures. Use of the void interface is therefore + * encouraged. + *****************/ + +hshTnode *hshFlist_node_find(hshTlist * list, char *name) +{ + return list->nodes[hshFhash(name)]; +} + +/* + * Search a node for a given entry and return a pointer to it. + */ +hshTentry *hshFnode_find_entry(hshTnode * node, char *str) +{ + hshTentry *e; + + if (node->entry == NULL) + return NULL; + + e = node->entry; + + while (1) { + if (strcmp(str, e->name) == 0) + return e; + if (e->next == NULL) + break; + e = e->next; + } + return NULL; +} + +hshTentry *hshFlist_find_entry(hshTlist * list, char *nname, char *ename) +{ + hshTnode *n; + hshTentry *e; + + n = (hshTnode *) hshFlist_node_find(list, nname); + + + if (n == NULL) + return NULL; + + e = (hshTentry *) hshFnode_find_entry(n, ename); + + return e; + +} + +char *hshFnode_find_value(hshTnode * node, char *str) +{ + hshTentry *e; + + + e = hshFnode_find_entry(node, str); + if (e == NULL) + return NULL; + return e->value; +} + +/* + * aleigh- Free a hashlist entry structure. The structure should already be + * unreferenced, or you'll break any pre-existing references to it. + */ +void hshFentry_free(hshTentry * entry) +{ + if (entry->name != NULL) + free(entry->name); + if (entry->value != NULL) + free(entry->value); + free(entry); +} + +/* + * aleigh- Free a node, and any entries that may be associated with it. You + * better be sure all the references are gone to the node. + */ +void hshFnode_free(hshTnode * node) +{ + hshTentry *p, *np = NULL; + + p = node->entry; + + while (1) { + if (p == NULL) + break; + np = p->next; + hshFentry_free(p); + p = np; + } + + if (node->entry != NULL) + hshFentry_free(node->entry); + free(node); +} + +/* + * aleigh- Create a hash node out of system memory via malloc(). The node is + * the root unit of the hashlist. + */ +hshTnode *hshFnode_create(char *name) +{ + hshTnode *n; + + n = (hshTnode *) malloc(sizeof(hshTnode)); + /* memFclear(n, sizeof(hshTnode)); */ + memFclear(n, sizeof(hshTnode)); + + n->name = (char *) malloc(strlen(name) + 1); + memFclear(n->name, strlen(name) + 1); + memFcopy(name, n->name, strlen(name)); + + return n; +} + +void hshFnode_entry_add(hshTnode * n, hshTentry * e) +{ + e->next = n->entry; + n->entry = e; +} + +hshTnode *hshFnode_entry_alloc(void) +{ + hshTnode *n; + + n = (hshTnode *) malloc(sizeof(hshTnode)); + memFclear(n, sizeof(hshTnode)); + + return n; +} + +hshTentry *hshFnode_entry_insert(hshTnode * node, char *n, char *v) +{ + hshTentry *e; + + e = (hshTentry *) malloc(sizeof(hshTentry)); + memFclear(e, sizeof(hshTentry)); + + e->name = (char *) malloc(strlen(n) + 1); + memFclear(e->name, strlen(n) + 1); + e->value = (char *) malloc(strlen(v) + 1); + memFclear(e->value, strlen(v) + 1); + + memFcopy(n, e->name, strlen(n)); + memFcopy(v, e->value, strlen(v)); + + hshFnode_entry_add(node, e); + + return e; +} + +hshTentry *hshFlist_entry_insert(hshTlist * list, char *l, char *n, + char *v) +{ + hshTnode *node; + hshTentry *entry; + + node = hshFlist_node_find(list, l); + if (node == NULL) { + node = hshFnode_create(l); + hshFlist_node_add(list, node); + } + entry = hshFnode_entry_insert(node, n, v); + + return entry; +} + +hshTlist *hshFlist_create(void) +{ + hshTlist *p; + + p = (hshTlist *) malloc(sizeof(hshTlist)); + memFclear(p, sizeof(hshTlist)); + /* memFclear(p, sizeof(hshTlist)); */ + + return p; +} + +void hshFlist_node_add(hshTlist * list, hshTnode * node) +{ + unsigned int hash; + + hash = hshFhash(node->name); + + if (list->nodes[hash] == NULL) { + list->nodes[hash] = node; + } else { + node->next = list->nodes[hash]; + list->nodes[hash] = node; + } +} + +void hashFlist_dump(hshTlist * list, unsigned int len) +{ + struct hshSnode *n; + size_t i; + + for (i = 0; i < len; i++) { + n = list->nodes[i]; + if (n->name == NULL) { + printf("node %d - (NULL)\n", i); + } else { + printf("node %d - %s\n", i, n->name); + } + } +} diff --git a/mk4/continuity/mecha/log.c b/mk4/continuity/mecha/log.c new file mode 100644 index 0000000..edaa2d2 --- /dev/null +++ b/mk4/continuity/mecha/log.c @@ -0,0 +1,254 @@ +/* + * $Header: /san01/cvs/ashpool/csrc/continuity/mecha/Attic/log.c,v 1.8 2004/04/30 13:41:56 aleigh Exp $ + */ + +/* + * Copyright (c) 1994, 2004 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Disclosure, copying, distribution, or transmission of of this code without + * express permission is prohibited. + */ + +#include "mecha.h" + +#define _LOG_ROTATECOUNT 5 +#define _LOG_ROTATETHRESH 100 + +static FILE *logGoutfh; + +/* Should we fclose() the filehandle? 0 for stdout */ +static int logGshould_close=0; + +static int logGwritten=0; + +/* The output filename if not stdout */ +static char *logGoutfn=NULL; + +static pthread_mutex_t logLrotate=PTHREAD_MUTEX_INITIALIZER; + +/* The size all the log files will be allowed to grow to, in + * bytes. Each individual log file will then rotate at around + * (logGrotatesize/_LOG_ROTATECOUNT) + */ +static size_t logGrotatesize=0; + +static void logFrotate_check(void); +void logFoutputfh_set(FILE *fh, int close_flag); + +const char *messages[] = { + "Unknown Internal Error", + "Interrupt handler caught signal, Exiting.", + "Could not open module configuration file. Exiting.", + "Calling 3rd party dispatcher. [d: %s]", + "Unable to map 3rd party dispatcher. [d: %s]", + "netFipv4_listen_tcp failed. [e: %d]", + /* 5 */ + "Starting IPv4 listen loop. [tid: 0x%x] [handler: 0x%x]", + "lsnFipv4_listen_loop: accept() took EINTR.", + "lsnFipv4_listen_loop: accept: %s", + "Thread pool full. Closing connection.", + "Thread pool created. [threads: %d] [queue: %d] [blocking: %d]", + /* 10 */ + "dlFread_entry: sscanf() returned other than 2. [s: %d] [e: %d]", + "stat() failed. [f: %s] [e: %d]", + "Internal Error: %s", + "open() failed. [f: %s] [e: %d]", + "Memory exhausted: %s", + /* 15 */ + "mmap() failed. [e: %d] %s", + "read() failed. [e: %d] %s", + "munmap() failed. [e: %d] %s", + "write() failed. [e: %d] %s" +}; + +static int logFreopen(void); + +void logFinit(void) { + logGoutfh=stdout; +} + +static void logFrotate_check(void) { + size_t filesize; + static int working=0; + + if(logGwritten<_LOG_ROTATETHRESH || working==1) { + return; + } + + if(logGrotatesize==0||logGoutfn==NULL) { + return; + } + + pthread_mutex_lock(&logLrotate); + + /* The point of this is to just help prevent other threads + * from backing up and trying to acquire the lock when we are clearly + * on the case. + */ + working=1; + + filesize=fleFget_size(logGoutfn); + + if(filesize>(logGrotatesize/_LOG_ROTATECOUNT)) { + fleFrotate(_LOG_ROTATECOUNT,logGoutfn); + logFreopen(); + logGwritten=0; + } + + logGwritten=0; + + pthread_mutex_unlock(&logLrotate); + + working=0; +} + +void logFset_rotatesize(size_t size) { + logGrotatesize=size; +} + +static int logFreopen(void) { + FILE *fh; + + assert(logGoutfn!=NULL); + + fh=fopen(logGoutfn,"a"); + if(fh==NULL) { + return -1; + } + + logFoutputfh_set(fh,logGshould_close); + + return 0; +} + +/* + * MT UNSAFE + */ +int logFset_outputfile(const char *filename) { + FILE *nh; + + assert(filename!=NULL); + + nh=fopen(filename,"a"); + if(nh==NULL) { + return -1; + } + + logFoutputfh_set(nh,logGshould_close); + logGoutfn=strFcopy(filename); + + assert(logGoutfn!=NULL); + + logGshould_close=1; + + return 0; +} + +/* + * MT Safe; result is volitile + */ +FILE *logFoutputfh_get(void) { + return logGoutfh; +} + +/* + * MT Unsafe + */ +void logFoutputfh_set(FILE *fh, int close_flag) { + FILE *oldfh = logGoutfh; + + logGoutfh=fh; + + /* We do it this way to minimize the race */ + if(close_flag==1) { + fclose(oldfh); + } +} + +/* + * MT Safe + */ +void logFmsgid(int level, const char *module, int msg_id, ...) +{ + va_list ap; + const char *m = messages[msg_id]; + + va_start(ap, msg_id); + + logGwritten++; + logFrotate_check(); + + switch (level) { + case 0: + fprintf(logGoutfh,"%s/ OK: %s-%05d ", utlFlocal_time(), module, msg_id); + vfprintf(logGoutfh,m, ap); + fprintf(logGoutfh,"\n"); + fflush(logGoutfh); + break; + case 1: + fprintf(logGoutfh,"%s/WARN: %s-%05d ", utlFlocal_time(), module, msg_id); + vfprintf(logGoutfh,m, ap); + fprintf(logGoutfh,"\n"); + fflush(logGoutfh); + break; + case 2: + fprintf(logGoutfh,"%s/ ERR: %s-%05d ", utlFlocal_time(), module, msg_id); + vfprintf(logGoutfh,m, ap); + fprintf(logGoutfh,"\n"); + fflush(logGoutfh); + break; + case 3: + fprintf(logGoutfh,"%s/DIAG: %s-%05d ", utlFlocal_time(), module, msg_id); + vfprintf(logGoutfh,m, ap); + fprintf(logGoutfh,"\n"); + fflush(logGoutfh); + break; + } +} + +/* + * MT Safe + */ +void logF_msg(const char *func, int level, const char *m, ...) +{ + va_list ap; + + logGwritten++; + logFrotate_check(); + + va_start(ap, m); + + switch (level) { + case 0: + fprintf(logGoutfh, "%s/ OK: %s: ", utlFlocal_time(), func); + vfprintf(logGoutfh,m, ap); + fprintf(logGoutfh,"\n"); + fflush(logGoutfh); + break; + + case 1: + fprintf(logGoutfh,"%s/WARN: %s: ", utlFlocal_time(), func); + vfprintf(logGoutfh,m, ap); + fprintf(logGoutfh,"\n"); + fflush(logGoutfh); + break; + + case 2: + fprintf(logGoutfh,"%s/ ERR: %s: ", utlFlocal_time(), func); + vfprintf(logGoutfh,m, ap); + fprintf(logGoutfh,"\n"); + fflush(logGoutfh); + break; + + case 3: + fprintf(logGoutfh,"%s/DIAG: %s: ", utlFlocal_time(), func); + vfprintf(logGoutfh,m, ap); + fprintf(logGoutfh,"\n"); + fflush(logGoutfh); + break; + } +} diff --git a/mk4/continuity/mecha/lst.c b/mk4/continuity/mecha/lst.c new file mode 100644 index 0000000..1d69155 --- /dev/null +++ b/mk4/continuity/mecha/lst.c @@ -0,0 +1,701 @@ +/* + * $Header: /san01/cvs/ashpool/csrc/continuity/mecha/Attic/lst.c,v 1.31 2004/04/30 13:41:56 aleigh Exp $ + */ + +/* + * Copyright (c) 1994, 2004 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Disclosure, copying, distribution, or transmission of this code without + * express permission is prohibited. + */ + +#include "mecha.h" + +#define FALSE 0 +#define TRUE 1 + +#define STREQ(a,b) (((*a) == (*b)) && (strcmp((a),(b)) == 0)) +#define STRIEQ(a,b) (strcasecmp((a),(b)) == 0) + +#include "lst.h" + +static int lstFset_find_cmp_len(const lstTset * set, const char *key, + int key_len, int (*cmp) (const char *s1, + const char *s2)); + +void lstFset_bupdate(lstTset * set, const char *key, size_t key_len, + const char *value, size_t value_len) +{ + assert(set != NULL); + assert(key != NULL); + assert(value != NULL); + + lstFset_delete_key(set, key); + lstFset_badd(set, key, key_len, value, value_len); +} + +void lstFset_update(lstTset * set, const char *key, const char *value) +{ + assert(set != NULL); + assert(key != NULL); + assert(value != NULL); + + lstFset_delete_key(set, key); + lstFset_add(set, key, value); +} + +lstTset *lstFset_init(void) +{ + lstTset *s; + + s = (lstTset *) malloc(sizeof(lstTset)); + + assert(s != NULL); + + memFclear(s, sizeof(lstTset)); + + return s; +} + +lstTset *lstFset_create(const char *name) +{ + lstTset *s; + + s = (lstTset *) malloc(sizeof(lstTset)); + + assert(s != NULL); + + s->size = 0; + s->maxsize = 10; /* default set size */ + + if (name != NULL) + s->name = strFcopy(name); + + s->fields = (lstTfield *) malloc(sizeof(lstTfield) * s->maxsize); + + assert(s->fields != NULL); + + memFclear(s->fields, sizeof(lstTfield) * s->maxsize); + + return s; +} + +void lstFset_free(lstTset * set) +{ + int i; + + if (set != NULL) { + if (set->fields != NULL) { + for (i = 0; i < set->size; i++) { + if (set->fields[i].name != NULL) + free(set->fields[i].name); + if (set->fields[i].value != NULL) + free(set->fields[i].value); + } + free(set->fields); + } + if (set->name != NULL) + free(set->name); + free(set); + } +} + +int lstFset_add(lstTset * set, const char *key, const char *value) +{ + int idx; + + assert(set != NULL); + assert(key != NULL); + + if (value == NULL) { + return -1; + } + idx = set->size; + set->size++; + + if (set->size >= set->maxsize) { + set->maxsize = set->size * 2; + set->fields = + (lstTfield *) realloc(set->fields, + sizeof(lstTfield) * set->maxsize); + } + /* initialize values */ + set->fields[idx].n_len = 0; + set->fields[idx].v_len = 0; + + set->fields[idx].name = strFcopy_size(key, &set->fields[idx].n_len); + set->fields[idx].value = strFcopy_size(value, &set->fields[idx].v_len); + + return idx; +} + + +int lstFset_badd(lstTset * set, const char *key, size_t key_len, + const char *value, size_t value_len) +{ + int idx; + + assert(set != NULL); + assert(key != NULL); + + if (value == NULL) { + return -1; + } + idx = set->size; + set->size++; + + if (set->size >= set->maxsize) { + set->maxsize = set->size * 2; + set->fields = + (lstTfield *) realloc(set->fields, + sizeof(lstTfield) * set->maxsize); + } + set->fields[idx].name = (char *) memFdup(key, key_len); + set->fields[idx].n_len = key_len; + set->fields[idx].value = (char *) memFdup(value, value_len); + set->fields[idx].v_len = value_len; + + return idx; +} + +int lstFset_nadd(lstTset * set, const char *key, int value) +{ + char buf[16]; + + assert(set != NULL); + assert(key != NULL); + + snprintf(buf, sizeof(buf), "%d", value); + return lstFset_add(set, key, buf); +} + + +int lstFset_unique_cmp(lstTset * set, const char *key, + int (*cmp) (const char *s1, const char *s2)) +{ + int i; + char *name; + int found; + + assert(set != NULL); + assert(key != NULL); + assert(cmp != NULL); + + found = 0; + for (i = 0; i < set->size; ++i) { + name = set->fields[i].name; + if ((key == NULL && name == NULL) || + (key != NULL && name != NULL && ((*cmp) (key, name)) == 0)) { + + if (found) { + return FALSE; + } + found = 1; + } + } + return TRUE; +} + +const char *lstFset_get_index(lstTset * set, int idx) +{ + assert(set != NULL); + if (idx >= set->size) + return NULL; + return set->fields[idx].value; +} + +const char *lstFset_get_key_index(lstTset * set, int idx) +{ + assert(set != NULL); + if (idx >= set->size) + return NULL; + return set->fields[idx].name; +} + +int lstFset_find_cmp(const lstTset * set, const char *key, + int (*cmp) (const char *s1, const char *s2)) +{ + int i; + + assert(set != NULL); + assert(key != NULL); + assert(cmp != NULL); + + for (i = 0; i < set->size; ++i) { + char *name = set->fields[i].name; + + if ((key == NULL && name == NULL) || + (key != NULL && name != NULL && ((*cmp) (key, name)) == 0)) { + + return i; + } + } + + return -1; +} + +static int lstFset_find_cmp_len(const lstTset * set, const char *key, + int key_len, int (*cmp) (const char *s1, + const char *s2)) +{ + int i; + + assert(set != NULL); + assert(key != NULL); + assert(cmp != NULL); + + for (i = 0; i < set->size; ++i) { + char *name = set->fields[i].name; + int name_len = set->fields[i].n_len; + + if ((key == NULL && name == NULL) || + (key != NULL && name != NULL && + key_len == name_len && ((*cmp) (key, name)) == 0)) { + + return i; + } + } + + return -1; +} + + +const char *lstFset_get_cmp(const lstTset * set, const char *key, + int (*cmp) (const char *s1, const char *s2)) +{ + int i; + + if (set == NULL) + return NULL; + + assert(key != NULL); + assert(cmp != NULL); + + i = lstFset_find_cmp(set, key, cmp); + + if (i == -1) + return NULL; + + return set->fields[i].value; +} + + +size_t lstFset_get_vsize_cmp(lstTset * set, const char *key, + int (*cmp) (const char *s1, const char *s2)) +{ + int i; + + i = lstFset_find_cmp(set, key, cmp); + if (i == -1) + return -1; + + return set->fields[i].v_len; +} + +size_t lstFset_get_nsize_cmp(lstTset * set, const char *key, + int (*cmp) (const char *s1, const char *s2)) +{ + int i; + + i = lstFset_find_cmp(set, key, cmp); + if (i == -1) + return -1; + + return set->fields[i].n_len; +} + +/* Check to see if a key in a set is unique (case sensitive) */ +int lstFset_unique(lstTset * set, const char *key) +{ + return lstFset_unique_cmp(set, key, + (int (*)(const char *, const char *)) + strcmp); +} + +/* Check if a key in a set is unique (case insensitive) */ +int lstFset_inique(lstTset * set, const char *key) +{ + return lstFset_unique_cmp(set, key, + (int (*)(const char *, const char *)) + strcasecmp); +} + +/* Locate the idx of a field in a set (sensitive) */ +int lstFset_find(lstTset * set, const char *key) +{ + return lstFset_find_cmp(set, key, + (int (*)(const char *, const char *)) strcmp); +} + +/* Locate the idx of a field in a set (insensitive) */ +int lstFset_ifind(lstTset * set, const char *key) +{ + return lstFset_find_cmp(set, key, + (int (*)(const char *, const char *)) + strcasecmp); +} + +/* Return the value associated with a key, sensitive */ +const char *lstFset_get(const lstTset * set, const char *key) +{ + return lstFset_get_cmp(set, key, + (int (*)(const char *, const char *)) strcmp); +} + +ssize_t lstFset_get_vsize(lstTset * set, const char *key) +{ + return lstFset_get_vsize_cmp(set, key, + (int (*)(const char *, const char *)) + strcmp); +} + +ssize_t lstFset_get_nsize(lstTset * set, const char *key) +{ + return lstFset_get_nsize_cmp(set, key, + (int (*)(const char *, const char *)) + strcmp); +} + +const lstTfield *lstFset_get_field(lstTset * set, const char *key, + int key_len) +{ + int i; + + if (set == NULL) + return NULL; + + assert(key != NULL); + + i = lstFset_find_cmp_len(set, key, key_len, strcmp); + + if (i == -1) + return NULL; + + return ((const lstTfield *) &set->fields[i]); +} + +/* Return the value associated with a key, insensitive */ +const char *lstFset_iget(lstTset * set, const char *key) +{ + return lstFset_get_cmp(set, key, + (int (*)(const char *, const char *)) + strcasecmp); +} + +/* Remove all tuples after 'size' */ +void lstFset_trunc(lstTset * set, int size) +{ + if (size < set->size) { + int i; + + for (i = size; i < set->size; i++) { + free(set->fields[i].name); + free(set->fields[i].value); + } + set->size = size; + } +} + +/* Delete a tuple from a set */ +void lstFset_delete(lstTset * set, int idx) +{ + if ((idx != -1) && (idx < set->size)) { + free(set->fields[idx].name); + free(set->fields[idx].value); + + set->fields[idx].name = set->fields[set->size - 1].name; + set->fields[idx].n_len = set->fields[set->size - 1].n_len; + set->fields[idx].value = set->fields[set->size - 1].value; + set->fields[idx].v_len = set->fields[set->size - 1].v_len; + + set->size--; + } +} + +/* Set the value for a given tuple */ +void lstFset_add_value(lstTset * set, int idx, const char *value) +{ + if ((idx != -1) && (idx < set->size)) { + free(set->fields[idx].value); + if (*value == 0) + set->fields[idx].value = strFcopy("(null)"); + else + set->fields[idx].value = strFcopy(value); + } +} + + +void lstFset_delete_key(lstTset * set, const char *key) +{ + lstFset_delete(set, lstFset_find(set, key)); +} + +void lstFset_idelete_key(lstTset * set, const char *key) +{ + lstFset_delete(set, lstFset_ifind(set, key)); +} + +lstTset *lstFset_list_find(lstTset ** sets, const char *name) +{ + while (*sets != NULL) { + if (name == NULL) { + if ((*sets)->name == NULL) { + return (*sets); + } + } else { + if ((*sets)->name != NULL && STREQ((*sets)->name, name)) { + + return (*sets); + } + } + ++sets; + } + return NULL; +} + +/* + * You could be outside, right now. + */ + +void lstFset_list_free(lstTset * sets) +{ + lstTset **s; + + s = (lstTset **) sets; + while (*s != NULL) { + lstFset_free((lstTset *) * s); + s++; + } + free(sets); +} + +void lstFset_merge(lstTset * high, const lstTset * low) +{ + int i, j; + + for (i = 0; i < low->size; ++i) { + j = lstFset_find(high, low->fields[i].name); + if (j == -1) { + lstFset_add(high, low->fields[i].name, low->fields[i].value); + } + } +} + +/* + * return the size, in bytes, of all the name and value data without the list + * overhead. + */ +int lstFset_size(const lstTset * set) +{ + int i; + int size = 0; + + if (set->size == 0) + return 0; + + /* Calculate the size of the list */ + for (i = 0; i < set->size; i++) { + if (set->fields[i].value != NULL && set->fields[i].name != NULL) { + size += strlen(set->fields[i].value); + size += strlen(set->fields[i].name); + } + } + + return size; + +} + +/* + * Return the physical idx location of the nth item in the list. + */ +int lstFnth_find(const lstTset * list, int nth) +{ + int i; + int found = -1; + + for (i = 0; i < list->size; i++) { + if (list->fields[i].name != NULL && list->fields[i].value != NULL) + found++; + if (found == nth) + return i; + } + return -1; +} + +const char *lstFfield_value(const lstTfield * field) +{ + return (field->value); +} + +int lstFfield_value_len(const lstTfield * field) +{ + return (field->v_len); +} + + +/********************************************************/ + +/* + * This code originates with the TA/Velocity telemetry engine. The packs were + * used to transfer lists of telemetry elements between hosts, but, they have + * far more potential general use. + */ + + +#define TA_INT8 1 +#define TA_INT16 2 +#define TA_CHAR8 3 +#define TA_MARKER 4 + +struct pckSelem { + uint16_t len; + uint8_t class; +}; + +int lstFpack(char *dest, char *src, int len, int class) +{ + char *wp; + struct pckSelem bar; + + wp = dest; + + memFclear(&bar,sizeof(struct pckSelem)); + + bar.len = len; + bar.class = class; + + memFcopy(&bar, wp, sizeof(struct pckSelem)); + wp += sizeof(struct pckSelem); + + memFcopy(src, wp, len); + + return len + sizeof(struct pckSelem); +} + +/* + * mowin down MC's, like I'm mowin the lawn but now, I'd like to ask you how, + * you like the feel of the bass in your face in the crowd + */ + +void lstFset_dump(char *pack) +{ + char *pp; + struct pckSelem bar; + + pp = pack; + + while (1) { + memFcopy(pp, &bar, sizeof(struct pckSelem)); + pp += sizeof(struct pckSelem); + + printf("len: %d class: %d\n", bar.len, bar.class); + if (bar.class == TA_MARKER) + break; + pp += bar.len; + } +} + +/* + * It's not paranoia to think that everyone is out to get you. They are, + * that's just common sense. Paranoia is thinking that they are conspiring. + */ + +lstTset *lstFset_unpack(const char *pack) +{ + const char *pp; + struct pckSelem bar; + char nbuf[256], vbuf[256]; + lstTset *set; + + pp = pack; + + set = lstFset_create("pack"); + + while (1) { + memFcopy(pp, &bar, sizeof(struct pckSelem)); + if (bar.class == TA_MARKER) + break; + pp += sizeof(struct pckSelem); + + memFclear(&nbuf, 256); /* TODO: lame */ + memFcopy(pp, &nbuf, bar.len); + pp += bar.len; + + memFcopy(pp, &bar, sizeof(struct pckSelem)); + if (bar.class == TA_MARKER) + break; + pp += sizeof(struct pckSelem); + + memFclear(&vbuf, 256); /* TODO: lame */ + memFcopy(pp, &vbuf, bar.len); + pp += bar.len; + + lstFset_add(set, (char *) &nbuf, (char *) &vbuf); + } + + return set; +} + +/* + * Pack a set into a single message for transport. Returns the packed string + * in allocated space. + */ + +char *lstFset_pack(const lstTset * set, size_t * len) +{ + char *pack, *pp; + int i; + int size; + int ret; + struct pckSelem bar; + + assert(set!=NULL); + + size = lstFset_size(set); + + if (size == 0) + return NULL; + + /* + * The size of the pack is going to be the payload, plus four bytes per + * tuple + */ + + size += ((sizeof(struct pckSelem) * 2) * set->size); + size += sizeof(struct pckSelem); /* For marker */ + + /* 4 int 16 per tuple and 2int16 for marker */ + + pack = (char *) malloc(size); + + memFclear(pack, size); + + pp = pack; + + for (i = 0; i < set->size; i++) { + if (set->fields[i].name != NULL && set->fields[i].value != NULL) { + ret = + lstFpack(pp, set->fields[i].name, + strlen(set->fields[i].name), TA_CHAR8); + pp += ret; + ret = + lstFpack(pp, set->fields[i].value, + strlen(set->fields[i].value), TA_CHAR8); + pp += ret; + } + } + + /* Insert marker */ + memFclear(&bar,sizeof(struct pckSelem)); + bar.len = 0; + bar.class = TA_MARKER; + memFcopy(&bar, pp, sizeof(struct pckSelem)); + + *len = size; + + return pack; +} diff --git a/mk4/continuity/mecha/lst.h b/mk4/continuity/mecha/lst.h new file mode 100644 index 0000000..98dab87 --- /dev/null +++ b/mk4/continuity/mecha/lst.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 1994, 2003 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Use, disclosure, copying, distribution, or transmission of this code without + * express permission is prohibited. + */ + +#ifndef _LST_H +#define _LST_H + +struct lstSfield { + char *name; + char *value; + size_t n_len; + size_t v_len; +}; +/* typedef struct lstSfield lstTfield; */ + +struct lstSset { + char *name; + int size; + int maxsize; + lstTfield *fields; +}; + +#endif diff --git a/mk4/continuity/mecha/lst_void.c b/mk4/continuity/mecha/lst_void.c new file mode 100644 index 0000000..d35aa5d --- /dev/null +++ b/mk4/continuity/mecha/lst_void.c @@ -0,0 +1,235 @@ +/* + * $Header: /san01/cvs/ashpool/csrc/continuity/mecha/Attic/lst_void.c,v 1.12 2004/04/30 13:41:56 aleigh Exp $ + */ + +/* + * Copyright (c) 1994, 2004 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Disclosure, copying, distribution, or transmission of this code without + * express permission is prohibited. + */ + +#include "mecha.h" + +struct lstSlist_elem { + void *data; + lstTlist_elem *next; + lstTlist_elem *prev; +}; + +struct lstSlist { + int size; + + void (*destroy) (void *); /* passed lstTlist_elem->data */ + + lstTlist_elem *head; + lstTlist_elem *tail; +}; + +/** Linked list code **/ + +/* + * Initialize a new linked list, with the destructor destory. + */ +void lstFlist_init(lstTlist * list, void (*destroy) (void *)) +{ + list->size = 0; + list->destroy = destroy; + + list->head = NULL; + list->tail = NULL; + + return; +} + +/* + * destroy the given list, freeing all memory + */ +void lstFlist_destroy(lstTlist * list) +{ + void *data; + + while (lstFlist_size(list) > 0) { + if (lstFlist_remove(list, lstFlist_tail(list), &data) == 0 && + list->destroy != NULL) + list->destroy(data); + } + + memFclear(list, sizeof(lstTlist)); +} + +/* + * THESE SHOULD REPLACE THE CURRENT INIT AND DESTROY FUNCTIONS + */ +lstTlist *lstFlist_create(void (*destroy) (void *)) +{ + lstTlist *list = malloc(sizeof(lstTlist)); + + lstFlist_init(list, destroy); + + return (list); +} + +void lstFlist_free(lstTlist * list) +{ + lstFlist_destroy(list); + + free(list); +} + +int lstFlist_add_next(lstTlist * list, lstTlist_elem * elem, void *data) +{ + lstTlist_elem *new_elem; + + if (lstFlist_size(list) != 0 && elem == NULL) + return (-1); + + new_elem = (lstTlist_elem *) malloc(sizeof(lstTlist_elem)); + + if (new_elem == NULL) + return (-1); + + new_elem->data = data; + + if (lstFlist_size(list) == 0) { + new_elem->next = new_elem->prev = NULL; + + list->head = list->tail = new_elem; + } else { + /* insert after elem */ + + new_elem->next = elem->next; + new_elem->prev = elem; + + if (elem->next == NULL) + list->tail = new_elem; + else + elem->next->prev = new_elem; + + elem->next = new_elem; + } + + list->size++; + + return (0); +} + +int lstFlist_add_prev(lstTlist * list, lstTlist_elem * elem, void *data) +{ + lstTlist_elem *new_elem; + + if (lstFlist_size(list) != 0 && elem == NULL) + return (-1); + + new_elem = (lstTlist_elem *) malloc(sizeof(lstTlist_elem)); + + if (new_elem == NULL) + return (-1); + + new_elem->data = data; + + if (lstFlist_size(list) == 0) { + new_elem->next = new_elem->prev = NULL; + + list->head = list->tail = new_elem; + } else { + /* insert before elem */ + + new_elem->prev = elem->prev; + new_elem->next = elem; + + if (elem->prev == NULL) + list->head = new_elem; + else + elem->prev->next = new_elem; + + elem->prev = new_elem; + } + + list->size++; + + return (0); +} + +int lstFlist_remove(lstTlist * list, lstTlist_elem * elem, void **data) +{ + if (lstFlist_size(list) == 0 || elem == NULL) + return (-1); + + if (data) + *data = elem->data; + + if (elem == list->head) { + list->head = elem->next; + + if (list->head == NULL) + list->tail = NULL; + else + list->head->prev = NULL; + } else { + elem->prev->next = elem->next; + + if (elem->next == NULL) + list->tail = elem->prev; + else + elem->next->prev = elem->prev; + } + + free(elem); + + list->size--; + + return (0); +} + +lstTlist_elem *lstFlist_next(lstTlist_elem * elem) +{ + return (elem->next); +} + +lstTlist_elem *lstFlist_prev(lstTlist_elem * elem) +{ + return (elem->prev); +} + +void *lstFlist_data(lstTlist_elem * elem) +{ + return (elem->data); +} + +int lstFlist_is_head(lstTlist * list, lstTlist_elem * elem) +{ + if (list->head == elem) { + return (1); + } else { + return (0); + } +} + +int lstFlist_is_tail(lstTlist * list, lstTlist_elem * elem) +{ + if (list->tail == elem) { + return (1); + } else { + return (0); + } +} + +lstTlist_elem *lstFlist_head(lstTlist * list) +{ + return (list->head); +} + +lstTlist_elem *lstFlist_tail(lstTlist * list) +{ + return (list->tail); +} + +int lstFlist_size(lstTlist * list) +{ + return (list->size); +} diff --git a/mk4/continuity/mecha/mecha.c b/mk4/continuity/mecha/mecha.c new file mode 100644 index 0000000..3595d06 --- /dev/null +++ b/mk4/continuity/mecha/mecha.c @@ -0,0 +1,9 @@ +#include "mecha.h" + +void mecha_init(void) { + logFinit(); + thrFmod_init(); + rndFinit(); + tlsFinit(); + +} diff --git a/mk4/continuity/mecha/mem.c b/mk4/continuity/mecha/mem.c new file mode 100644 index 0000000..d32e116 --- /dev/null +++ b/mk4/continuity/mecha/mem.c @@ -0,0 +1,35 @@ +/* + * $Header: /san01/cvs/ashpool/csrc/continuity/mecha/Attic/mem.c,v 1.9 2004/04/30 13:41:56 aleigh Exp $ + */ + +/* + * Copyright (c) 2004 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Disclosure, copying, distribution, or transmission of of this code without + * express permission is prohibited. + */ + +#include "mecha.h" + +void *memFdup(const void *p, size_t len) +{ + char *a; + + assert(p != NULL); + + /* add an extra byte to put a trailing NULL */ + a = malloc(len + 1); + + assert(a != NULL); + + memFcopy(p, a, len); + + /* add a trailing NULL incase this is a string */ + a[len] = 0; + + return a; +} diff --git a/mk4/continuity/mecha/net.c b/mk4/continuity/mecha/net.c new file mode 100644 index 0000000..c076570 --- /dev/null +++ b/mk4/continuity/mecha/net.c @@ -0,0 +1,559 @@ +/* + * $Header: /san01/cvs/ashpool/csrc/continuity/mecha/Attic/net.c,v 1.14 2004/05/27 13:32:22 aleigh Exp $ + */ + +/* + * Copyright (c) 2004 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Use, disclosure, copying, distribution, or transmission of this code without + * express permission is prohibited. + */ + +#include "mecha.h" +#include "net.h" + +#define EAGAIN_TRYCOUNT 28 +#define EAGAIN_WAIT 15 + +ssize_t netFconn_writev(netTconn * conn, const struct iovec * iov,int iovcnt); + +int netFset_reuse(int sd) +{ + int reuse = 1; + + if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) != + 0) { + return -1; + } + return 0; +} + +int netFset_nodelay(int sd) +{ + int opt = 1; +#ifndef DARWIN + if (setsockopt(sd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)) != 0) + return -1; +#endif + return 0; +} + +int netFipv4_listen_tcp(int port, unsigned int ip, int maxconnect) +{ + int newport; + struct sockaddr_in dest; + int on = 1; + + newport = socket(AF_INET, SOCK_STREAM, 6); + if (newport == -1) { + logFmsg(2, "netFipv4_listen_tcp: socket failed [e: %s]", + strerror(errno)); + return -1; + } + dest.sin_family = AF_INET; + dest.sin_port = htons(port); + dest.sin_addr.s_addr = htonl(ip); + + fleFset_close_exec(newport); + + setsockopt(newport, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + + if (bind(newport, (struct sockaddr *) &dest, sizeof(dest)) == -1) { + logFmsg(2, "netFipv4_listen_tcp: bind failed: %s", + strerror(errno)); + return (-1); + } + listen(newport, maxconnect); + + return (newport); +} + +static ssize_t netFconn_reader_read(netTconn * conn, netTreader * reader) +{ + ssize_t ret; + + bzero(reader->buf, READER_CHUNK_SZ); + + thrFtrigger_set(10, conn->sd); + + ret = conn->io_read(conn, reader->buf, READER_CHUNK_SZ); + + thrFtrigger_clear(); + + if (ret == -1) + return -1; + + reader->len = ret; + + reader->pos = 0; + + return reader->len; +} + +/* + * Reads and writes into buf until either len-1 occurs, or a newline is found + * in the input sd. Always null terminates and returns the number of bytes + * written including the null. + */ + +ssize_t netFconn_read_line(netTconn * conn, netTreader * reader, + char *buf, ssize_t len) +{ + char *p; + ssize_t i, ret; + + assert(conn != NULL); + assert(reader != NULL); + assert(buf != NULL); + assert(len > 1); + + p = reader->buf + reader->pos; + + for (i = 0; i < len; i++) { + if ((reader->len == 0) || (reader->pos > (reader->len - 1))) { + /* No data in the buffer; read. */ + ret = netFconn_reader_read(conn, reader); + + /* error trap / null read trap */ + if (ret == -1 || ret == 0) { + return i; + } + p = reader->buf + reader->pos; + } + if (*p == '\n') { + reader->pos++; + + /* lets go back one to the newline */ + i--; + buf[i] = '\0'; /* Null terminate the string */ + return i; + } + if (*p != '\r') + buf[i] = *p; + + p++; + reader->pos++; + + } + return i; +} + +int netFisready(int fd) +{ + int rc; + fd_set fds; + struct timeval tv; + + FD_ZERO(&fds); + FD_SET(fd, &fds); + tv.tv_sec = 5; + tv.tv_usec = 0; + + rc = select(fd + 1, &fds, NULL, NULL, &tv); + if (rc < 0) + return -1; + + return FD_ISSET(fd, &fds) ? 1 : 0; +} + +int netFtcp_connect(char *addr, unsigned int port) +{ + int sock; + struct sockaddr_in sa; + struct hostent *hp; + + bzero((char *) &sa, sizeof(struct sockaddr_in)); + if (!(hp = gethostbyname(addr))) { + logFmsg(1, "gethostbyname failed."); + return -1; + } + sa.sin_family = AF_INET; + memcpy((char *) &sa.sin_addr, hp->h_addr_list[0], hp->h_length); + sa.sin_port = htons(port); + + if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + logFmsg(1, "socket [a: %s] [e: %s]", + addr, strerror(errno)); + return -1; + } + fleFset_close_exec(sock); + + if (connect(sock, (struct sockaddr *) &sa, + sizeof(struct sockaddr_in)) < 0) { + close(sock); + logFmsg(1, "connect failed: %s", strerror(errno)); + + return -1; + } + return sock; +} + +int netFconn_close(netTconn *conn) { + return conn->io_close(conn); +} + +ssize_t netFconn_read(netTconn * conn, netTreader * reader, + char *buf, ssize_t len) +{ + char *p; + ssize_t i, ret; + + p = reader->buf + reader->pos; + + for (i = 0; i < len; i++) { + if ((reader->len == 0) || (reader->pos > (reader->len - 1))) { + /* No data in the buffer; read. */ + ret = netFconn_reader_read(conn, reader); + + /* error trap / null read trap */ + if (ret == -1 || ret == 0) { + return i; + } + p = reader->buf + reader->pos; + } + buf[i] = *p; + p++; + reader->pos++; + } + return i; +} + +ssize_t netFconn_write_two(netTconn * conn, const char *buf1, + size_t buf1_len, const char *buf2, + size_t buf2_len) +{ + struct iovec io[2]; + ssize_t ret; + + io[0].iov_base = (char *) buf1; + io[0].iov_len = buf1_len; + io[1].iov_base = (char *) buf2; + io[1].iov_len = buf2_len; + + ret = conn->io_writev(conn, io, 2); + + if (ret > (ssize_t)buf1_len) + return ret - buf1_len; + else + return ret; +} + +ssize_t netFconn_writev(netTconn * conn, const struct iovec * iov, + int iovcnt) +{ + ssize_t ret = conn->io_writev(conn, iov, iovcnt); + return ret; +} + +ssize_t netFconn_write(netTconn * conn, const char *buf, ssize_t len) +{ + const char *bp = buf; + size_t blen = len; + ssize_t ret; + int tc = 0; + ssize_t written = 0; + + while (blen != 0) { + while ((ret = conn->io_write(conn, bp, blen)) == -1) { + if (errno == EAGAIN || errno == EINTR) { + if (errno == EPIPE) { + return -1; + } + if (tc == EAGAIN_TRYCOUNT) { + /* + * We have tried as many times as we are going to for + * this connection, so pass out an error and our caller + * can decide what to do. Register this as an EAGAIN + * failure. + */ + return -1; + } + tc++; + thrFsleep(EAGAIN_WAIT); + continue; + } else { + return -1; + } + } + blen -= ret; + bp += ret; + written += ret; + } + return written; +} + +int netFudp_send(int sd, const void *msg, size_t msg_len, unsigned int port, unsigned int ip) +{ + struct sockaddr_in sa; + sa.sin_family = AF_INET; + sa.sin_addr.s_addr = htonl(ip); + sa.sin_port = htons(port); + + return sendto(sd, msg, msg_len, 0, (struct sockaddr *) &sa, sizeof sa); +} + +int netFudp_recv(int sd, char *msg, size_t msg_len, struct sockaddr_in *sa, + size_t * sa_len) +{ + return recvfrom(sd, msg, msg_len, 0, (struct sockaddr *) sa, sa_len); +} + +/* + * port - Writes back the port that is actually used. Must be 0. defport - A + * default port in case it's not in services service - The service name to + * look in services + */ +int netFudp_open(uint16_t * port, int defport, char *service) +{ + int fd; + int result; + struct servent *svp; + struct sockaddr_in *sin_local; + struct sockaddr_in salocal; + uint16_t lport; + + /* + * If port already has an assignment, use it. This provides a kind of + * caching but requires that port be initialized to zero previous to this + * call + */ + + if (*port > 5) { + lport = htons(*port); + } else { + svp = getservbyname(service, "udp"); + if (svp != (struct servent *) NULL) { + lport = (unsigned short) svp->s_port; + } else { + lport = htons(defport); + } + *port = ntohs(lport); + } + + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + logFmsg(2, "netFudp_open: socket error. [e: %d] [s: %s]", errno, + service); + return -1; + } + fleFset_close_exec(fd); + + sin_local = (struct sockaddr_in *) &salocal; + memset((char *) sin_local, '\0', sizeof(salocal)); + sin_local->sin_family = AF_INET; + sin_local->sin_addr.s_addr = INADDR_ANY; + sin_local->sin_port = lport; + + result = bind(fd, (struct sockaddr *) &salocal, sizeof(*sin_local)); + if (result < 0) { + logFmsg(2, "netFudp_open: bind error. [e: %d] [s: %s]", errno, + service); + return -1; + } + return fd; +} + +/* + * Create a socket for UDP Broadcast use. Returns the socket or -1/errno on + * error. + */ +int netFudp_bcast_connect(void) +{ + int sock; + struct sockaddr_in sa; + int on = 1; + int fd_flags; + + bzero((char *) &sa, sizeof(struct sockaddr_in)); + + sa.sin_family = AF_INET; + sa.sin_addr.s_addr = htonl(INADDR_ANY); + /* sa.sin_port=htons(port); random source port */ + + if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + return -1; + + fleFset_close_exec(sock); + + if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof on) == -1) + return -1; + + if ((fd_flags = fcntl(sock, F_GETFL)) == -1) + return -1; + fd_flags |= O_NONBLOCK; + if (fcntl(sock, F_SETFL, fd_flags) == -1) + return -1; + + if (bind(sock, (struct sockaddr *) &sa, sizeof sa) == -1) + return -1; + + return sock; +} + +int netFconn_writef(netTconn * conn, const char *fmt, ...) +{ + va_list ap; + char *buf; + int size = 1024; + int e; + + buf = (char *) malloc(size); + + va_start(ap, fmt); + + while (1) { + int nchars = vsnprintf(buf, size, fmt, ap); + + if (nchars > -1 && nchars < size) + break; + if (nchars > -1) + size = nchars + 1; + else + size *= 2; + buf = (char *) realloc(buf, size); + } + + va_end(ap); + + if ((e = netFconn_write(conn, buf, strlen(buf))) == -1) + e = -errno; + + free(buf); + + return e; +} + +int _netFconn_writef(netTconn * conn, const char *fmt, va_list * ap) +{ + char *buf; + int size = 1024; + int e; + + buf = (char *) malloc(size); + + while (1) { + int nchars = vsnprintf(buf, size, fmt, *ap); + + if (nchars > -1 && nchars < size) + break; + if (nchars > -1) { + size = nchars + 1; + } else { + size *= 2; + } + + buf = (char *) realloc(buf, size); + } + + if ((e = netFconn_write(conn, buf, strlen(buf))) == -1) { + e = -errno; + } + + free(buf); + + return e; +} + +netTreader *netFreader_init(void) +{ + netTreader *r; + + r = (netTreader *) malloc(sizeof(netTreader)); + bzero(r, sizeof(netTreader)); + + return r; +} + +void netFreader_free(netTreader * reader) +{ + free(reader); +} + +ssize_t netFconn_os_read(netTconn * conn, void *buf, size_t len) +{ + return read(conn->sd, buf, len); +} + +ssize_t netFconn_os_write(netTconn * conn, const void *buf, size_t len) +{ + size_t ret; + + thrFtrigger_set(10,conn->sd); + ret=write(conn->sd, buf, len); + thrFtrigger_clear(); + + return ret; +} + +int netFconn_os_close(netTconn * conn) +{ + return close(conn->sd); +} + +ssize_t netFconn_os_writev(netTconn * conn, const struct iovec * iov, + int iovcnt) +{ + return writev(conn->sd, iov, iovcnt); +} + +void netFconn_free(netTconn * conn) +{ + if (conn->data_free != NULL && conn->data != NULL) + conn->data_free(conn->data); + free(conn); +} + +netTconn *netFconn_make(int sd) +{ + netTconn *conn = memFalloc(sizeof(netTconn)); + + conn->sd = sd; + conn->io_read = &netFconn_os_read; + conn->io_write = &netFconn_os_write; + conn->io_close = &netFconn_os_close; + conn->io_writev = &netFconn_os_writev; + conn->data_free = NULL; + + return conn; +} + +/** IPv4 Multicast **/ + +#define MSGBUFSIZE 256 + +int netFipv4_mcast_create(unsigned int port, char *group) +{ + struct sockaddr_in addr; + int sd; + struct ip_mreq mreq; + + if((sd=socket(AF_INET,SOCK_DGRAM,0))<0) { + logFmsg(1,"socket() failed. [e: %d]", errno); + return -1; + } + + netFset_reuse(sd); + + memFclear(&addr,sizeof(addr)); + addr.sin_family=AF_INET; + addr.sin_addr.s_addr=htonl(INADDR_ANY); + addr.sin_port=htons(port); + + if(bind(sd,(struct sockaddr *)&addr,sizeof(addr))<0) { + logFmsg(1,"bind() failed. [e: %d]", errno); + return -1; + } + + mreq.imr_multiaddr.s_addr=inet_addr(group); + mreq.imr_interface.s_addr=htonl(INADDR_ANY); + if (setsockopt(sd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq)) < 0) { + logFmsg(1,"setsockopt() 2 failed. [e: %d]", errno); + return -1; + } + + return sd; +} diff --git a/mk4/continuity/mecha/net.h b/mk4/continuity/mecha/net.h new file mode 100644 index 0000000..d653f67 --- /dev/null +++ b/mk4/continuity/mecha/net.h @@ -0,0 +1,28 @@ +/* + * $Header: /cvsroot/csrc/continuity/mecha/net.h,v 1.1 2004/03/11 19:05:20 + * aleigh Exp $ + */ + +/* + * Copyright (c) 1994, 2003 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Use, disclosure, copying, distribution, or transmission of this code without + * express permission is prohibited. + */ + +#ifndef _NET_H +#define _NET_H + +#define READER_CHUNK_SZ 1024 + +struct netSreader { + char buf[READER_CHUNK_SZ]; + ssize_t pos; + ssize_t len; +}; + +#endif diff --git a/mk4/continuity/mecha/pat.c b/mk4/continuity/mecha/pat.c new file mode 100644 index 0000000..f8c0ce9 --- /dev/null +++ b/mk4/continuity/mecha/pat.c @@ -0,0 +1,120 @@ +/* + * $Header: /san01/cvs/ashpool/csrc/continuity/mecha/Attic/pat.c,v 1.6 2004/04/30 13:41:56 aleigh Exp $ + * + * Copyright (c) 2004, Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH. The copyright + * notice above does not evidence any actual or intended publication of + * such source code. + * + * Use, disclosure, copying, distribution, or transmission of this code without + * express permission is prohibited. + */ + +#include "mecha.h" + +struct patSstack { + struct patSpattern *patterns; + size_t count; + void (*destructor) (void *); +}; + +/* Some other time we will extend this to include the per-compiled version of the + * regular expression for performance reasons, but I've got other fish to fry + * right now. -aleigh + */ +struct patSpattern { + const char *regexp; + void *target; +}; +typedef struct patSpattern patTpattern; + +/* This may need to take a destructor if we say that the list is going to be + * responsible for freeing the void pointers passed into it. -aleigh + */ + +/* + * MT - Does not require a lock. + */ +patTstack *patFstack_init(void (*destructor) (void *)) +{ + patTstack *stack = (patTstack *) malloc(sizeof(patTstack)); + + assert(stack != NULL); + + memFclear(stack, sizeof(patTstack)); + + stack->destructor = destructor; + + return stack; +} + +/* + * MT - Requires a write lock. + * */ +void patFstack_free(patTstack * stack) +{ + size_t i; + + for (i = 0; i < stack->count; i++) { + if (stack->destructor != NULL) { + (stack->destructor)(stack->patterns[i].target); + } + free((void *)stack->patterns[i].regexp); /* We added this field with strFcopy() */ + } + + free(stack->patterns); + free(stack); +} + +/* + * MT - Does not require a lock. + */ +size_t patFstack_size(patTstack * stack) +{ + return stack->count; +} + +/* + * MT - Requires a write lock on the stack. + */ +void patFstack_append(patTstack * stack, const char *regexp, void *target) +{ + assert(stack != NULL); + assert(regexp != NULL); + assert(target != NULL); + + if (stack->count == 0) { + stack->patterns = (patTpattern *) malloc(sizeof(patTpattern)); + stack->patterns[0].regexp = strFcopy(regexp); + stack->patterns[0].target = target; + stack->count = 1; + } else { + stack->count++; + stack->patterns = + (patTpattern *) realloc(stack->patterns, + sizeof(patTpattern) * stack->count); + stack->patterns[stack->count].regexp = strFcopy(regexp); + stack->patterns[stack->count].target = target; + } +} + +/* + * MT - requires at least a read lock on the stack. Patterns are searched in the order + * that they were appended into the stack. + */ +void *patFstack_search(patTstack * stack, const char *needle) +{ + size_t i; + + assert(stack != NULL); + assert(needle != NULL); + + for(i=0;icount;i++) { + if(expFmatch(stack->patterns[i].regexp, needle)==1) { + logFmsg(3,"pat: Matched."); + return stack->patterns[i].target; + } + } + return NULL; +} diff --git a/mk4/continuity/mecha/qry.c b/mk4/continuity/mecha/qry.c new file mode 100644 index 0000000..20e3ca6 --- /dev/null +++ b/mk4/continuity/mecha/qry.c @@ -0,0 +1,90 @@ +/* + * $Header: /san01/cvs/ashpool/csrc/continuity/mecha/Attic/qry.c,v 1.9 2004/04/30 13:41:56 aleigh Exp $ + * + * Copyright (c) 1994, 2004 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Disclosure, copying, distribution, or transmission of this code without + * express permission is prohibited. + */ + +#include "mecha.h" + +#define QRY_M_INIT 1 +#define QRY_M_NCOPY 2 +#define QRY_M_VCOPY 3 +#define QRY_M_SCAN 4 + +/* This is my December, this is my time of the year */ + +lstTset *qryFlst_parse(const char *query) +{ + lstTset *set = lstFset_create("query"); + int mode = QRY_M_INIT; + char nbuf[1024], vbuf[1024], *y; + const char *x; + + /* x points to the input query. */ + /* y points to the output buffer, n, or v */ + + assert(query != NULL); + + x = query; + + while (1) { + if (mode == QRY_M_INIT) { + mode = QRY_M_NCOPY; + y = nbuf; + nbuf[0] = '\0'; + } + if (mode == QRY_M_NCOPY) { + if (*x == '=') { + /* finished with the name */ + mode = QRY_M_VCOPY; + x++; + *y = '\0'; + + y = (char *) vbuf; + *y = '\0'; + continue; + } + *y = *x; + + y++; + x++; + + /* If this matches, the query is short. */ + if (*x == '\0') { + break; + } + continue; + } + if (mode == QRY_M_VCOPY) { + if (*x == '&' || *x == '\0') { + /* Finished with the value */ + mode = QRY_M_INIT; + if (*vbuf != '\0') { + *y = '\0'; + lstFset_add(set, nbuf, vbuf); + } + /* If not, then we have another argument. */ + if (*x == '\0') + break; + + x++; + *y = '\0'; + continue; + + } + *y = *x; + y++; + x++; + continue; + } + } + + return set; +} diff --git a/mk4/continuity/mecha/rnd.c b/mk4/continuity/mecha/rnd.c new file mode 100644 index 0000000..c7dab28 --- /dev/null +++ b/mk4/continuity/mecha/rnd.c @@ -0,0 +1,69 @@ +/* + * $Header: /san01/cvs/ashpool/csrc/continuity/mecha/Attic/rnd.c,v 1.8 2004/04/30 13:41:56 aleigh Exp $ + */ + +/* + * Copyright (c) 1994, 2004 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Disclosure, copying, distribution, or transmission of this code without + * express permission is prohibited. + */ + +/* + * Generate len random bytes and write them into buf. + */ + +#include "mecha.h" + +static unsigned int rndGseed; + +void rndFinit(void) +{ + rndGseed = utlFtime(); + +#ifdef HAVE_RAND_R + srand(rndGseed); +#endif +} + +void rndFrandom_bytes(unsigned char *buf, int len) +{ + unsigned char *p = buf; + int i; + + for (i = 0; i < len; i++) { +#ifdef HAVE_RAND_R + *p = rand_r(&rndGseed) % 256; +#else + +#ifdef WIN32 + *p = rand() % 256; +#else + *p = random() % 256; +#endif /* WIN32 */ + +#endif /* HAVE_RAND_R */ + p++; + } +} + +unsigned int rndFnumber(void) +{ +#ifdef HAVE_RAND_R + unsigned int seed; + + return rand_r(&seed); +#else + +#ifdef WIN32 + return rand(); +#else + return random(); +#endif /* WIN32 */ + +#endif /* HAVE_RAND_R */ +} diff --git a/mk4/continuity/mecha/str.c b/mk4/continuity/mecha/str.c new file mode 100644 index 0000000..75c3538 --- /dev/null +++ b/mk4/continuity/mecha/str.c @@ -0,0 +1,322 @@ +/* + * $Header: /san01/cvs/ashpool/csrc/continuity/mecha/Attic/str.c,v 1.21 2004/04/30 13:41:56 aleigh Exp $ + */ + +/* + * Copyright (c) 1994, 2004 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Disclosure, copying, distribution, or transmission of this code without + * express permission is prohibited. + */ + +#include "mecha.h" + +#ifndef MAX +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +void strFstrip_crlf(char *s, const size_t len) +{ + char *p; + + for (p = s + len; p != s; p--) { + if (*p == '\r' || *p == '\n' || *p == '\0') { + *p = '\0'; + } else { + return; + } + } +} + +void strFtoupper(char *s) +{ + char *p; + + for (p = s; *p != '\0'; p++) { + *p = toupper(*p); + } +} + +void strFtolower(char *s) +{ + char *p; + + for (p = s; *p != '\0'; p++) { + *p = tolower(*p); + } +} + +/* + * Duplicate the string s, and write back the length of the string into len. + * The duplicate string is returned. + */ +char *strFdup_size(const char *s, size_t * len) +{ + char *t; + size_t l_len; + + assert(s != NULL); + + l_len = strlen(s); + + t = (char *) malloc(l_len + 1); + + /* we know the length so we can use memcpy instead of strcpy */ + memcpy(t, s, l_len); + + /* add the trailing null */ + t[l_len] = 0; + + *len = l_len; + + return t; +} + +/* + * duplicate the length of the string, and write the strlen back into the + * pointer provided by len. If the input string is NULL, nothing will be + * written into len. + */ +char *strFcopy_size(const char *s, size_t * len) +{ + return (s == NULL ? NULL : strFdup_size(s, len)); +} + +/* TODO: strFdup() and strFcopy() are now functionally identical. */ + +/* + * Duplicate the string and return the duplicate, or, return NULL if the + * provided string was NULL + */ +char *strFcopy(const char *s) +{ + size_t unused; + + return (strFcopy_size(s, &unused)); +} + +char *strFncopy(const char *s, size_t len) { + assert(s!=NULL); + + return (char *)memFdup(s,len); +} + +/* from thttpd */ +static int str_alloc_count = 0; +static long str_alloc_size = 0; + +void strFrealloc(char **strP, int *maxsizeP, int size) +{ + if (*maxsizeP == 0) { + *maxsizeP = MAX(200, size); /* arbitrary */ + *strP = (char *) malloc(*maxsizeP + 1); + ++str_alloc_count; + str_alloc_size += *maxsizeP; + } else if (size > *maxsizeP) { + str_alloc_size -= *maxsizeP; + *maxsizeP = MAX(*maxsizeP * 2, size * 5 / 4); + *strP = (char *) realloc(*strP, *maxsizeP + 1); + str_alloc_size += *maxsizeP; + } else + return; + if (*strP == (char *) 0) { + /* logFmsgid(1,"CON",15,"strFrealloc"); */ + abort(); + } +} + +const char *strFcasestr(const char *haystack, const char *needle) +{ + const char *hptr, *hlast; + const char *nptr; + + hptr = haystack; + nptr = needle; + + while (*hptr) { + if (tolower(*hptr++) == tolower(*nptr)) { + hlast = hptr; + + while (*nptr && tolower(*hptr++) == tolower(*++nptr)) + continue; + + if (*nptr) { + hptr = hlast; + nptr = needle; + } else + return hlast - 1; + } + } + return (NULL); +} + +int strFis_whitespace(char c) +{ + if (c == '\n' || c == '\r' || c == ' ' || c == '\t') + return 1; + return 0; +} + +int strFis_blank(char *s) +{ + char *p; + + for (p = s; *p != 0; p++) { + if (strFis_whitespace(*p) == 0) + return 0; + } + + return 1; +} + + +#define CM_COPY 1 +#define CM_WHITE 2 +dynTstring *strFcollapse_whitespace(char *str) +{ + dynTstring *new = dynFinit(); + char *p; + int mode = CM_COPY; + + assert(str != NULL); + + for (p = str; *p != '\0'; p++) { + switch (mode) { + case CM_COPY: + if (*p == '\r') + continue; + + if (strFis_whitespace(*p) == 1) { + dynFappend(new, " ", 1); + mode = CM_WHITE; + continue; + } + dynFappend(new, p, 1); + + break; + + case CM_WHITE: + if (strFis_whitespace(*p) == 1) + continue; + dynFappend(new, p, 1); + mode = CM_COPY; + break; + } + } + return new; +} + +#define P_SEARCH 3 +#define P_NAME 1 +#define P_VAL 2 + +lstTset *strFattrib_parser(const char *str) +{ + int mode = P_SEARCH; + const char *p; + char nbuf[128]; + int nbufc = 0; + char vbuf[128]; + int vbufc = 0; + lstTset *set = lstFset_init(); + + assert(str != NULL); + assert(set != NULL); + + for (p = str; *p != 0; p++) { + switch (mode) { + case P_SEARCH: + if (strFis_whitespace(*p) == 1) + break; + mode = P_NAME; + + case P_NAME: + if (*p == '=') { + nbuf[nbufc] = 0; + mode = P_VAL; + p++; + break; + } + nbuf[nbufc] = *p; + nbufc++; + break; + + case P_VAL: + if (*p == '"') { + mode = P_SEARCH; + vbuf[vbufc] = 0; + lstFset_add(set, nbuf, vbuf); + /* printf("Got %s %s\n", nbuf, vbuf); */ + vbufc = 0; + nbufc = 0; + break; + } + vbuf[vbufc] = *p; + vbufc++; + break; + } + } + return set; +} + + +unsigned int strFsplit(char *str, char **list, unsigned int list_size, + const char delim, const char quotechar) +{ + register char *p, *sp; + register unsigned int listc = 0; + register short inquote = 0; + + assert(str != NULL); + assert(list != NULL); + assert(list_size > 0); + + list_size--; + + if (quotechar == 0) + inquote = 3; + + for (sp = p = str; *p != 0; p++) { + if (inquote == 1) { + if (*p == quotechar) + inquote = 0; + continue; + } + if (inquote == 0) + if (*p == quotechar) { + inquote = 1; + continue; + } + if (*p == delim) { + *p = '\0'; + list[listc] = sp; + if (listc == list_size) + return listc + 1; + listc++; + sp = (p + 1); + } + } + + list[listc] = sp; + return listc + 1; +} + +const char *strFskip_whitespace(const char *p) +{ + while (isspace(*p)) p++; + return p; +} + +const char *strFskip_token(const char *p) +{ + while (isspace(*p)) p++; + while (*p && !isspace(*p)) p++; + return p; +} diff --git a/mk4/continuity/mecha/sys.c b/mk4/continuity/mecha/sys.c new file mode 100644 index 0000000..1008e5b --- /dev/null +++ b/mk4/continuity/mecha/sys.c @@ -0,0 +1,618 @@ +/* + * Copyright (c) 1994, 2004 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Use, disclosure, copying, distribution, or transmission of of this code without + * express permission is prohibited. + */ + +#include "mecha.h" + +#ifdef LINUX + +/* Have faith; it's really here but you need a weird collection + of define's to get the declaration for it. */ + +extern int getloadavg(double loadavg[], int nelem); + +static unsigned int sysGstart_time=0; + +#define PAGESIZE 4096 + +int sysFnet_usage(uint32_t *obytes, uint32_t *ibytes, + uint32_t *opkts, uint32_t *ipkts) +{ + int fd; + char *stack[24]; + char buf[4096]; + size_t len; + int lines, i; + + fd=open("/proc/net/dev",O_RDONLY); + if(fd==-1) { + logFmsg(2,"Cannot open /proc/net/dev. [e: %d]", errno); + return -1; + } + + len=read(fd,buf,4095); + close(fd); + buf[len]=0; + + lines=strFsplit(buf,stack,24,'\n','"'); + lines--; + + if(lines<2) { + logFmsg(2,"Unable to parse the /proc/net/dev file. Invalid format."); + return -1; + } + + unsigned long ob=0, op=0, ib=0, ip=0; + + char *p; + + for(i=2;i +#include +#ifdef HAVE_GETLOADAVG +#include +#endif +#include + +int sysFfs_info(lstTset * set) +{ + FILE *mnttab; + struct mnttab me; + struct statvfs fse; + char nbuf[128]; + char vbuf[128]; + + assert(set!=NULL); + + mnttab = fopen("/etc/mnttab", "r"); + + if (mnttab == NULL) { + logFmsg(2, "Unable to open /etc/mnttab [e: %d]", errno); + return -1; + } + + while (getmntent(mnttab, &me) == 0) { + if (strcmp(me.mnt_fstype, "ufs") == 0 + || strcmp(me.mnt_fstype, "vxfs") == 0 + || strcmp(me.mnt_fstype, "tmpfs") == 0) { + if (statvfs(me.mnt_mountp, &fse) != 0) { + logFmsg(2, "statvfs() failed [e: %d] [mp: %s]", + errno, me.mnt_mountp); + } + sprintf(nbuf, "fs_%s_blocks", me.mnt_mountp); + sprintf(vbuf, "%u", fse.f_blocks); + lstFset_add(set, (char *) &nbuf, (char *) &vbuf); + + sprintf(nbuf, "fs_%s_bavail", me.mnt_mountp); + sprintf(vbuf, "%u", fse.f_bavail); + lstFset_add(set, (char *) &nbuf, (char *) &vbuf); + + sprintf(nbuf, "fs_%s_bsize", me.mnt_mountp); + sprintf(vbuf, "%u", fse.f_bsize); + lstFset_add(set, (char *) &nbuf, (char *) &vbuf); + + sprintf(nbuf, "fs_%s_files", me.mnt_mountp); + sprintf(vbuf, "%u", fse.f_files); + lstFset_add(set, (char *) &nbuf, (char *) &vbuf); + + sprintf(nbuf, "fs_%s_favail", me.mnt_mountp); + sprintf(vbuf, "%u", fse.f_favail); + lstFset_add(set, (char *) &nbuf, (char *) &vbuf); + } + } + fclose(mnttab); +} + +/* + * PercentLoad = 100 * (1 - D/(D+Load)) + * where D determines which load value should be associated with which + * load percentage. D=50 means that 128 is 50% load, 256 is 80%, etc. + */ +int sysFget_load(double *one_min, double *five_min, double *fifteen_min) +{ + double x[3]; + +#ifdef HAVE_GETLOADAVG + if (getloadavg(x, 3) == -1) { + logFmsg(2, "getloadvg failed [e: %d]", errno); + return -1; + } +#else + x[0]=0; + x[1]=0; + x[2]=0; +#endif + + *one_min=x[0]; + *five_min=x[1]; + *fifteen_min=x[2]; + + return 0; +} + +static kstat_ctl_t *sysGkc=NULL; +static pthread_mutex_t sysLkc=PTHREAD_MUTEX_INITIALIZER; + +static kstat_ctl_t *sysFgetkc(void) { + if(sysGkc!=NULL) { + return sysGkc; + } + + pthread_mutex_lock(&sysLkc); + + if(sysGkc!=NULL) { + /* Someone else opened it */ + pthread_mutex_unlock(&sysLkc); + return sysGkc; + } + + sysGkc=kstat_open(); + pthread_mutex_unlock(&sysLkc); + return sysGkc; +} + +/* + * Return the startup time of the host, in unix time. + */ +unsigned int sysFboot_time(void) +{ + + kstat_ctl_t *kc; + kstat_t *ksp; + kstat_named_t *kn; + + kc = sysFgetkc(); + + if (kc == NULL) { + perror("kstat_open"); + abort(); + } + ksp = kstat_lookup(kc, "unix", -1, "system_misc"); + + kstat_read(kc, ksp, NULL); + + kn = kstat_data_lookup(ksp, "boot_time"); + + switch (kn->data_type) { +#ifdef KSTAT_DATA_INT32 + case KSTAT_DATA_INT32: + return kn->value.i32; + break; + case KSTAT_DATA_UINT32: + return kn->value.ui32; + break; + case KSTAT_DATA_INT64: + return kn->value.i64; + break; + case KSTAT_DATA_UINT64: + return kn->value.ui64; + break; +#endif + } + + return -1; +} + +int sysFmem_usage(uint32_t *pages_total, uint32_t *pages_free, + uint32_t *phys_mem, uint32_t *availr_mem, + uint32_t *free_mem) +{ + + kstat_ctl_t *kc; + kstat_t *ksp; + kstat_named_t *kn; + + kc = sysFgetkc(); + + if (kc == NULL) { + logFmsg(2,"kstat_open failed [e: %d]", errno); + return -1; + } + + ksp = kstat_lookup(kc, "unix", -1, "system_pages"); + + assert(ksp!=NULL); + + kstat_read(kc, ksp, NULL); + + kn = kstat_data_lookup(ksp, "pagestotal"); + assert(kn!=NULL); + *pages_total = kn->value.ui32; + + kn = kstat_data_lookup(ksp, "pagesfree"); + assert(kn!=NULL); + *pages_free = kn->value.ui32; + + kn = kstat_data_lookup(ksp, "physmem"); + assert(kn!=NULL); + *phys_mem = kn->value.ui32; + + kn = kstat_data_lookup(ksp, "availrmem"); + assert(kn!=NULL); + *availr_mem = kn->value.ui32; + + kn = kstat_data_lookup(ksp, "freemem"); + assert(kn!=NULL); + *free_mem=kn->value.ui32; + + return 0; +} + +struct sysScpu { + kstat_t *ksp; + struct sysScpu *next; +}; +typedef struct sysScpu sysTcpu; + +static sysTcpu *sysGcpus=NULL; +static pthread_mutex_t sysLcpus=PTHREAD_MUTEX_INITIALIZER; + +static int sysFcpu_init(kstat_ctl_t *kc) { + int i; + kstat_t *ksp; + sysTcpu *cpu; + + assert(kc!=NULL); + + for(i=0;i<128;i++) { + ksp=kstat_lookup(kc,"cpu_stat",i,NULL); + if(ksp==NULL) continue; + + logFmsg(3,"Found CPU: %d", i); + cpu=(sysTcpu *)malloc(sizeof(sysTcpu)); + cpu->ksp=ksp; + cpu->next=sysGcpus; + sysGcpus=cpu; + } + + return 0; +} + +int sysFcpu_usage(uint32_t *idle_time, uint32_t *user_time, + uint32_t *kernel_time, uint32_t *wait_time) +{ + kstat_ctl_t *kc; + sysTcpu *cpu; + cpu_stat_t cpu_stat; + + kc=sysFgetkc(); + + assert(kc!=NULL); + + *idle_time=0; + *user_time=0; + *kernel_time=0; + *wait_time=0; + + if(sysGcpus==NULL) { + pthread_mutex_lock(&sysLcpus); + if(sysGcpus==NULL) { + sysFcpu_init(kc); + } + pthread_mutex_unlock(&sysLcpus); + } + + for(cpu=sysGcpus;cpu!=NULL;cpu=cpu->next) { + assert(cpu!=NULL); + assert(cpu->ksp!=NULL); + + if(kstat_read(kc,cpu->ksp,&cpu_stat)==-1) { + return -1; + } + *idle_time += cpu_stat.cpu_sysinfo.cpu[0]; + *user_time += cpu_stat.cpu_sysinfo.cpu[1]; + *kernel_time += cpu_stat.cpu_sysinfo.cpu[2]; + *wait_time += cpu_stat.cpu_sysinfo.cpu[3]; + } + + return 0; +} + +struct sysSnet { + kstat_t *ksp; + struct sysSnet *next; +}; +typedef struct sysSnet sysTnet; + +static sysTnet *sysGnet=NULL; +static pthread_mutex_t sysLnet = PTHREAD_MUTEX_INITIALIZER; + +/* Must own sysLnet */ +static void sysFnet_register(kstat_t *ksp) { + sysTnet *net; + + assert(ksp!=NULL); + + net=(sysTnet *)malloc(sizeof(sysTnet)); + assert(net!=NULL); + + net->ksp=ksp; + net->next=sysGnet; + sysGnet=net; +} + +static int sysFnet_init(kstat_ctl_t *kc) { + kstat_t *ksp; + int i; + + assert(kc!=NULL); + + for(i=0;i<128;i++) { + ksp=kstat_lookup(kc,"hme",i,NULL); + if(ksp!=NULL) { + logFmsg(3,"Found network interface hme%d", i); + sysFnet_register(ksp); + } + + ksp=kstat_lookup(kc,"qfe",i,NULL); + if(ksp!=NULL) { + logFmsg(3,"Found network interface qfe%d", i); + sysFnet_register(ksp); + } + + ksp=kstat_lookup(kc,"le",i,NULL); + if(ksp!=NULL) { + logFmsg(3,"Found network interface le%d", i); + sysFnet_register(ksp); + } + + ksp=kstat_lookup(kc,"ge",i,NULL); + if(ksp!=NULL) { + logFmsg(3,"Found network interface ge%d", i); + sysFnet_register(ksp); + } + } + + return i; +} + +int sysFnet_usage(uint32_t *obytes, uint32_t *ibytes, + uint32_t *opkts, uint32_t *ipkts) +{ + kstat_ctl_t *kc; + kstat_named_t *kn; + sysTnet *net; + + kc=sysFgetkc(); + + assert(kc!=NULL); + + *obytes=0; + *ibytes=0; + *opkts=0; + *ipkts=0; + + if(sysGnet==NULL) { + pthread_mutex_lock(&sysLnet); + if(sysGnet==NULL) { + sysFnet_init(kc); + } + pthread_mutex_unlock(&sysLnet); + } + + for(net=sysGnet;net!=NULL;net=net->next) { + kstat_read(kc,net->ksp,NULL); + + kn=kstat_data_lookup(net->ksp,"obytes"); + if(kn!=NULL) { + *obytes+=kn->value.ui32; + } + + kn=kstat_data_lookup(net->ksp,"rbytes"); + if(kn!=NULL) { + *ibytes+=kn->value.ui32; + } + + kn=kstat_data_lookup(net->ksp,"ipackets"); + if(kn!=NULL) { + *ipkts+=kn->value.ui32; + } + + kn=kstat_data_lookup(net->ksp,"opackets"); + if(kn!=NULL) { + *opkts+=kn->value.ui32; + } + } + + return 0; +} + +#endif diff --git a/mk4/continuity/mecha/thr.c b/mk4/continuity/mecha/thr.c new file mode 100644 index 0000000..6519caf --- /dev/null +++ b/mk4/continuity/mecha/thr.c @@ -0,0 +1,533 @@ +/* + * $Header: /san01/cvs/ashpool/csrc/continuity/mecha/Attic/thr.c,v 1.24 2004/05/27 13:55:00 aleigh Exp $ + */ + +/* + * Copyright (c) 1994, 2004 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Disclosure, copying, distribution, or transmission of of this code without + * express permission is prohibited. + */ + +#include "mecha.h" + +/* #define PRECREATE */ + +struct thrSinfo { + struct thrStpool *tpool; + int index; +}; +typedef struct thrSinfo thrTinfo; + +struct thrStrigger { + unsigned int time; + int fd; + pthread_t tid; +}; + +typedef struct tpool_work { + void (*routine) (void *data); + void *arg; + struct tpool_work *next; +} thrTtpool_work; + +struct thrStpool { + /* pool characteristics */ + int num_threads; + int max_queue_size; + int started; + int inuse; + + int blocking_mode; + /* pool state */ + int cur_queue_size; + pthread_t *threads; + thrTtpool_work *queue_head; + thrTtpool_work *queue_tail; + int queue_closed; + int shutdown; + /* pool synchronization */ + pthread_mutex_t queue_lock; + pthread_mutex_t thread_lock; + pthread_cond_t queue_not_empty; + pthread_cond_t queue_not_full; + pthread_cond_t queue_empty; + struct thrStrigger *trigger; +}; + +pthread_key_t thrKtrigger; +void *thrFthread(void *); + +void thrFmod_init(void) +{ + if (pthread_key_create(&thrKtrigger, NULL) == -1) { + logFmsg(3, "thrFmod_init: Failed to create trigger TLS key."); + } +} + +int thrFsleep(int ms) +{ + struct timespec then; + int ret; + +#ifdef LINUX + + then.tv_sec = ms / 1000; + then.tv_nsec = (ms % 1000) * 1000000; + + /* shut up vgrind, not required */ + ret = nanosleep (&then, NULL); + +#else + pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; + pthread_cond_t cond = PTHREAD_COND_INITIALIZER; + struct timeval now; + int deltams; + + gettimeofday(&now, NULL); + + deltams = (now.tv_usec / 1000) + ms; + + then.tv_sec = now.tv_sec + (deltams / 1000); + then.tv_nsec = (deltams % 1000) * 1000000; + + /* + * OpenBSD requires that the mutex be locked, or else cond_timedwait will + * return EINVAL. We can get away with this on Linux so far even though + * it is bad behavior. Will generate valgrind warnings. + */ +#if defined(OPENBSD) || defined(FREEBSD) + pthread_mutex_lock(&mut); + pthread_mutex_lock(&mut); +#endif + + ret = pthread_cond_timedwait(&cond, &mut, (struct timespec *) &then); +#endif /* LINUX */ + + return 0; +} + +thrTtrigger *thrFgettrigger(void) +{ + return pthread_getspecific(thrKtrigger); +} + +int thrFtrigger_set(unsigned int delta, int fd) +{ + thrTtrigger *trig = thrFgettrigger(); + + if (trig == NULL) { +// logFmsg(3, "trig NULL tid %d", pthread_self()); + return -1; + } + trig->fd = fd; + trig->time = utlFtime() + delta; + + return 0; +} + +int thrFtrigger_clear(void) +{ + thrTtrigger *trig = thrFgettrigger(); + + if (trig == NULL) + return -1; + + trig->time = 0; + + return 0; + + +} + +void thrFcheck_triggers(thrTtpool * tp) +{ + int i; + unsigned int now = utlFtime(); + + for (i = 0; i < tp->num_threads; i++) { + if (tp->trigger[i].time <= now && tp->trigger[i].time != 0) { + /* + * logFmsg(3, "thrFcheck_triggers: Triggering fd %d", + * tp->trigger[i].fd); + */ + shutdown(tp->trigger[i].fd, 2); + tp->trigger[i].time = 0; + } + } +} + +/* + * This thread runs continuously and keeps statistics about the threadpool + * current. It is also responsable for outputting messages when the pool + * filles. + */ + +void thrFstat_thr(void *tp) +{ + thrTtpool *tpool = (thrTtpool *) tp; + + while (1) { + if (tpool->cur_queue_size > 0) { + logFmsg(0, "thr_pool: [queue: %d/%d] [threads: %d/%d (%d)]", + tpool->cur_queue_size, tpool->max_queue_size, + tpool->inuse, tpool->started, tpool->num_threads); + } + thrFcheck_triggers(tpool); + thrFsleep(1000); + } +} + +thrTtpool *thrFinit(int num_worker_threads, + int max_queue_size, int blocking_mode) +{ + unsigned int i; + int ret; + thrTtpool *tpool; + + /* allocate a pool data structure */ + if ((tpool = (thrTtpool *) malloc(sizeof(thrTtpool))) == NULL) { + logFmsg(3, "thrFinit: malloc()"); + exit(1); + } + /* initialize th fields */ + tpool->num_threads = num_worker_threads; + tpool->max_queue_size = max_queue_size; + tpool->blocking_mode = blocking_mode; + tpool->started = 1; + tpool->inuse = 0; + + if ((tpool->threads = + (pthread_t *) malloc(sizeof(pthread_t) * num_worker_threads)) + == NULL) + perror("malloc"), exit(1); + tpool->cur_queue_size = 0; + tpool->queue_head = NULL; + tpool->queue_tail = NULL; + tpool->queue_closed = 0; + tpool->shutdown = 0; + + tpool->trigger = + (thrTtrigger *) malloc(sizeof(thrTtrigger) * num_worker_threads); + memFclear(tpool->trigger, sizeof(thrTtrigger) * num_worker_threads); + + /* Start the statistics output thread */ + pthread_create((pthread_t *) & i, NULL, + (void *(*)(void *)) thrFstat_thr, (void *) tpool); + + if ((ret = pthread_mutex_init(&(tpool->queue_lock), NULL)) != 0) { + logFmsg(2, "thrFinit: pthread_mutex_init failed. (e: %d)", ret); + exit(1); + } + if ((ret = pthread_mutex_init(&(tpool->thread_lock), NULL)) != 0) { + logFmsg(2, "thrFinit: pthread_mutex_init failed. (e: %d)", ret); + exit(1); + } + if ((ret = pthread_cond_init(&(tpool->queue_not_empty), NULL)) != 0) { + logFmsg(2, "thrFinit: conditional not_empty failed. (e: %d)", ret); + exit(1); + } + if ((ret = pthread_cond_init(&(tpool->queue_not_full), NULL)) != 0) { + logFmsg(2, "thrFinit: conditional not_full failed. (e: %d)", ret); + exit(1); + } + if ((ret = pthread_cond_init(&(tpool->queue_empty), NULL)) != 0) { + logFmsg(2, "thrFinit: conditional empty failed. (e: %d)", ret); + exit(1); + } + { + thrTinfo *info = (thrTinfo *) malloc(sizeof(thrTinfo)); + pthread_t tid; + + info->index = 0; + info->tpool = tpool; + + if ((ret = + pthread_create((pthread_t *) & tid, NULL, thrFthread, + (void *) info)) != 0) { + logFmsg(2, + "thrFinit: Unable to create first pool thread. (e: %d)", + ret); + exit(1); + } + } + +#ifdef PRECREATE + for (i = 1; i != num_worker_threads; i++) { + thrTinfo *info = (thrTinfo *) malloc(sizeof(thrTinfo)); + pthread_t tid; + + info->index = i; + info->tpool = tpool; + + if ((ret = pthread_create((pthread_t *) & tid, + NULL, thrFthread, (void *) info)) != 0) { + logFmsg(2, "thrFinit: Unable to create pool thread: %d", ret); + exit(1); + } + } +#endif + + return tpool; +} + +/* + * Beyond, Amon Hen is before us. + */ + +int thrFadd_work(thrTtpool * tpool, void (*routine) (void *data), + void *arg) +{ + int ret; + thrTtpool_work *workp; + + if ((ret = pthread_mutex_lock(&(tpool->queue_lock))) != 0) { + logFmsg(2, "thrFadd_work: mutex lock failed. (e: %d)", ret); + exit(1); + } + /* + * If the blocking mode is 1 and the queue is full than we are going to + * return immediately. Otherwise we will go ahead and try to add the work + * but will block until it is able to be accepted. + */ + + if ((tpool->cur_queue_size == tpool->max_queue_size) && + tpool->blocking_mode == 1) { + if ((ret = pthread_mutex_unlock(&(tpool->queue_lock))) != 0) { + logFmsg(2, "thrFadd_work: mutex unlock failed. (e: %d)", ret); + exit(1); + } + return -1; + } + while ((tpool->cur_queue_size == tpool->max_queue_size) && + (!(tpool->shutdown || tpool->queue_closed))) { + if ((ret = pthread_cond_wait(&(tpool->queue_not_full), + &(tpool->queue_lock))) != 0) { + logFmsg(2, "thrFadd_work: cond_wait failed. (e: %d)", ret); + exit(1); + } + } + + if (tpool->shutdown || tpool->queue_closed) { + if ((ret = pthread_mutex_unlock(&(tpool->queue_lock))) != 0) { + logFmsg(2, "thrFadd_work: mutex unlock failed. (e: %d)", ret); + exit(1); + } + return -1; + } + if ((workp = + (thrTtpool_work *) malloc(sizeof(thrTtpool_work))) == NULL) { + logFmsg(2, "thrFadd_work: malloc() failed."); + exit(1); + } + workp->routine = routine; + workp->arg = arg; + workp->next = NULL; + + if (tpool->cur_queue_size == 0) { + tpool->cur_queue_size++; + + tpool->queue_tail = tpool->queue_head = workp; + + if ((ret = pthread_cond_signal(&(tpool->queue_not_empty))) != 0) { + logFmsg(2, + "thrFadd_work: conditional signal on pool failed. (e: %d)", + ret); + exit(1); + } + } else { + tpool->cur_queue_size++; + + tpool->queue_tail->next = workp; + tpool->queue_tail = workp; + + if ((ret = pthread_cond_signal(&(tpool->queue_not_empty))) != 0) { + logFmsg(2, + "thrFadd_work: conditional signal on not empty failed. (e: %d)", + ret); + exit(1); + } + } + + if ((ret = pthread_mutex_unlock(&(tpool->queue_lock))) != 0) { + logFmsg(2, "thrFadd_work: mutex unlock on queue failed. (e: %d)", + ret); + exit(1); + } + /* + * Check to see if all the threads are currently in use, and if we've + * started them all or not. If we haven't, we're going to go ahead and + * start another one now. This is coded like this so that the mutex isn't + * locked every time work is added, rather, only when it's likely that + * another thread is needed. Synchronization on demand. Once all the + * threads are started, we won't check at all. + */ + + if (tpool->started < tpool->num_threads) { + if ((tpool->started - tpool->inuse) <= 5) { + pthread_mutex_lock(&tpool->thread_lock); + if (tpool->started < tpool->num_threads) { + thrTinfo *info = (thrTinfo *) malloc(sizeof(thrTinfo)); + pthread_t tid; + + info->index = tpool->started - 1; + info->tpool = tpool; + + /* + * logFmsg (3, "thrFadd_work: starting new worker thread. + * (sid: %d)", info->index); + */ + + if ((ret = + pthread_create((pthread_t *) & tid, NULL, thrFthread, + (void *) info)) != 0) { + logFmsg(2, + "thrFinit: Unable to create first pool thread. (e: %d)", + ret); + exit(1); + } + tpool->started++; + } + pthread_mutex_unlock(&tpool->thread_lock); + } + } + return 1; +} + +int thrFdestroy(thrTtpool * tpool, int finish) +{ + int i, ret; + thrTtpool_work *cur_nodep; + + if ((ret = pthread_mutex_lock(&(tpool->queue_lock))) != 0) + fprintf(stderr, "pthread_mutex_lock %d", ret), exit(1); + + /* Is a shutdown already in progress? */ + if (tpool->queue_closed || tpool->shutdown) { + if ((ret = pthread_mutex_unlock(&(tpool->queue_lock))) != 0) + fprintf(stderr, "pthread_mutex_unlock %d", ret), exit(1); + return 0; + } + tpool->queue_closed = 1; + + if (finish == 1) { + while (tpool->cur_queue_size != 0) { + if ((ret = pthread_cond_wait(&(tpool->queue_empty), + &(tpool->queue_lock))) != 0) + fprintf(stderr, "pthread_cond_wait %d", ret), exit(1); + } + } + tpool->shutdown = 1; + + if ((ret = pthread_mutex_unlock(&(tpool->queue_lock))) != 0) + fprintf(stderr, "pthread_mutex_unlock %d", ret), exit(1); + + + if ((ret = pthread_cond_signal(&(tpool->queue_not_empty))) != 0) + fprintf(stderr, "pthread_cond_signal %d", ret), exit(1); + if ((ret = pthread_cond_broadcast(&(tpool->queue_not_full))) != 0) + fprintf(stderr, "pthread_cond_broadcast %d", ret), exit(1); + + + for (i = 0; i < tpool->num_threads; i++) { + if ((ret = pthread_cancel(tpool->threads[i])) != 0) + logFmsg(2, "tpool: pthread_cancel (e:%d)", ret); + + if ((ret = pthread_join(tpool->threads[i], NULL)) != 0) + logFmsg(2, "tpool: pthread_join (e:%d)", ret); + } + + free(tpool->threads); + while (tpool->queue_head != NULL) { + cur_nodep = tpool->queue_head->next; + tpool->queue_head = tpool->queue_head->next; + free(cur_nodep); + } + free(tpool); + + return 1; +} + +void *thrFthread(void *arg) +{ + thrTinfo *info = (thrTinfo *) arg; + int ret; + thrTtpool_work *my_workp; + + info->tpool->threads[info->index] = pthread_self(); + info->tpool->trigger[info->index].tid = pthread_self(); + if (pthread_setspecific + (thrKtrigger, &info->tpool->trigger[info->index]) + != 0) { + logFmsg(2, "thrFthread: pthread_setspecific() failed. e: %d", + errno); + logFmsg(3, "thrFthread: Failed to register I/O trigger."); + exit(0); + } + while (1) { + if ((ret = pthread_mutex_lock(&(info->tpool->queue_lock))) != 0) { + logFmsg(2, "tpool: Mutex lock returned error. (e: %d)", ret); + } + while ((info->tpool->cur_queue_size == 0) + && (!info->tpool->shutdown)) { + if ((ret = + pthread_cond_wait(&(info->tpool->queue_not_empty), + &(info->tpool->queue_lock))) != 0) { + logFmsg(2, "tpool: cond_wait returned fatally. (e: %d)", + ret); + exit(1); + } + } + + info->tpool->inuse++; + + if (info->tpool->shutdown == 1) { + if ((ret = + pthread_mutex_unlock(&(info->tpool->queue_lock))) != 0) { + logFmsg(2, "tpool: pthread_mutex_unlock (e: %d)", ret); + exit(1); + } + free(info); + pthread_exit(NULL); + } + my_workp = info->tpool->queue_head; + info->tpool->cur_queue_size--; + + if (info->tpool->cur_queue_size == 0) { + info->tpool->queue_head = info->tpool->queue_tail = NULL; + } else { + info->tpool->queue_head = my_workp->next; + } + + /* Handle waiting add_work threads */ + if ((!info->tpool->blocking_mode) && + (info->tpool->cur_queue_size == + (info->tpool->max_queue_size - 1))) { + if ((ret = + pthread_cond_broadcast(&(info->tpool->queue_not_full))) != + 0) { + logFmsg(2, "itpool: pthread_cond_broadcast (e: %d)", ret); + exit(1); + } + } + /* Handle waiting destroyer threads */ + if (info->tpool->cur_queue_size == 0) { + if ((ret = + pthread_cond_signal(&(info->tpool->queue_empty))) != 0) { + logFmsg(2, "pthread_cond_signal (e:%d)", ret); + exit(1); + } + } + if ((ret = pthread_mutex_unlock(&(info->tpool->queue_lock))) != 0) { + logFmsg(2, "tpool: pthread_mutex_unlock (e: %d)", ret); + exit(1); + } + (*(my_workp->routine)) (my_workp->arg); + free(my_workp); + info->tpool->inuse--; + } +} diff --git a/mk4/continuity/mecha/tls.c b/mk4/continuity/mecha/tls.c new file mode 100644 index 0000000..d53c3ad --- /dev/null +++ b/mk4/continuity/mecha/tls.c @@ -0,0 +1,231 @@ +/* + * $Header: /san01/cvs/ashpool/csrc/continuity/mecha/Attic/tls.c,v 1.9 2004/04/30 13:41:56 aleigh Exp $ + */ + +/* + * Copyright (c) 1994, 2004 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Disclosure, copying, distribution, or transmission of this code without + * express permission is prohibited. + */ + +#include "mecha.h" + +static pthread_key_t tls_key; +static void **clean_funcs; +static int clean_count = 0; + +struct tlsSent { + void *data; + int class; + char *name; + struct tlsSent *next; +}; +typedef struct tlsSent tlsTent; + +static void tlsFfree(tlsTent * p); + +static void tlsFadd_internal(void *data, char *name, int class); + +#undef TLS_DEBUG + +/* + * Allow another piece of code to register a cleanup handler. This function + * will return an integer which is the TLS class. This class needs to be + * provided for subsequent calls to the TLS system. + */ +int tlsFregister(void *(*clean_fn) (void *)) +{ + if (clean_count == 0) { + clean_funcs = (void *) malloc(sizeof(void *)); + clean_funcs[0] = (void *) clean_fn; + clean_count++; + } else { + clean_count++; + clean_funcs = realloc(clean_funcs, sizeof(void *) * clean_count); + clean_funcs[clean_count - 1] = (void *) clean_fn; + } + return clean_count - 1; +} + +/* + * Free a TLS entry and call it's associated cleanup function if it has + * client data + */ +static void tlsFfree(tlsTent * p) +{ + void (*f) (void *data); + +#ifdef TLS_DEBUG + logFmsg(3, "tlsFfree: freeing a TLS entity %s class %d data 0x%x", + p->name, p->class, p->data); +#endif + + if (p->data != NULL) { + + f = (void (*)(void *)) clean_funcs[p->class]; +#ifdef TLS_DEBUG + logFmsg(3, "tlsFfree: calling 0x%x for cleanup", f); +#endif + (*f) (p->data); + } + free(p->name); + free(p); +} + +/* + * Destroy an entire TLS list, calling any associated cleanup functions for + * it's client data. + */ +void tlsFdestroy(void *p) +{ + tlsTent *ent, *next = NULL; + + if (p == NULL) + return; + + ent = (tlsTent *) p; + + while (1) { + next = ent->next; + tlsFfree(ent); + if (next == NULL) + return; + ent = next; + } +} + +/* + * Remove all of a thread's TLS storage. + */ +void tlsFclean(void) +{ + tlsTent *p; + + p = pthread_getspecific(tls_key); + if (p == NULL) + return; + + tlsFdestroy(p); + pthread_setspecific(tls_key, NULL); +} + +void tlsFinit(void) +{ + if (pthread_key_create(&tls_key, tlsFdestroy) != 0) { +#ifdef TLS_DEBUG + logFmsg(2, "tls: Unable to register tls_key. [e: %d]", errno); +#endif + abort(); + } + tlsFregister((void *(*)(void *)) lstFset_free); +} + +void tlsFadd(void *data, char *name, int class) +{ + tlsFadd_internal(data, strFcopy(name), class); +} + +static void tlsFadd_internal(void *data, char *name, int class) +{ + tlsTent *tls; + tlsTent *ent; + +#ifdef TLS_DEBUG + logFmsg(3, "tlsFadd: called to add: 0x%x %s %d", data, name, class); +#endif + ent = malloc(sizeof(tlsTent)); + ent->name = name; + ent->data = data; + ent->class = class; + + tls = pthread_getspecific(tls_key); + + if (tls == NULL) { + ent->next = NULL; + } else { + /* TODO: Lame */ + ent->next = tls; + } + + if (pthread_setspecific(tls_key, ent) != 0) { + logFmsg(2, "tlsFadd: setspecific failed. [e: %d]", errno); + } +#ifdef TLS_DEBUG + else { + + logFmsg(3, "tlsFadd: setspecific 0."); + } +#endif +} + +void tlsFdel(char *name, int class) +{ + tlsTent *e; + void *(*f) (void *data); + +#ifdef TLS_DEBUG + logFmsg(3, "tlsFdel: called for %s %d", name, class); +#endif + + e = pthread_getspecific(tls_key); + + for (; e != NULL; e = e->next) { + /* We do this as two to avoid the strcmp for other classes */ + if (e->class == class) { + if (strcmp(name, e->name) == 0) { +#ifdef TLS_DEBUG + logFmsg(3, "tlsFdel: found match"); +#endif + if (e->data != NULL) { + f = (void *(*)(void *)) clean_funcs[e->class]; + (*f) (e->data); + e->data = NULL; + } + } + } + } +} + +void *tlsFget(char *name, int class) +{ + tlsTent *e; + + assert(name != NULL); + + e = pthread_getspecific(tls_key); + +#ifdef TLS_DEBUG + logFmsg(3, "tlsFget: e is 0x%x", e); +#endif + + if (e == NULL) + return NULL; + + while (1) { + if (strcmp(e->name, name) == 0 && e->class == class) { +#ifdef TLS_DEBUG + logFmsg(3, "tlsFget: returning 0x%x", e->data); +#endif + return e->data; + } + if (e->next == NULL) + return NULL; + e = e->next; + } +} + +char *tlsFadd_makeid(void *data, int class) +{ + char *id = malloc(sizeof(char) * 37); + + uidFgenerate_str(id, 37); + + tlsFadd_internal(data, id, class); + + return id; +} diff --git a/mk4/continuity/mecha/uid.c b/mk4/continuity/mecha/uid.c new file mode 100644 index 0000000..bd135ec --- /dev/null +++ b/mk4/continuity/mecha/uid.c @@ -0,0 +1,148 @@ +/* + * $Header: /san01/cvs/ashpool/csrc/continuity/mecha/Attic/uid.c,v 1.9 2004/04/30 13:41:56 aleigh Exp $ + */ + +/* + * Copyright (c) 1994, 2004 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Use, disclosure, copying, distribution, or transmission of of this code without + * express permission is prohibited. + */ + +typedef unsigned char uuidTpack[16]; + +#include "mecha.h" + +struct uuidSid { + uint32_t time_low; + uint16_t time_mid; + uint16_t time_hi_and_version; + uint16_t clock_seq; + uint8_t node[6]; +}; +typedef struct uuidSid uuidTid; + +static void uuidFpack(uuidTid * uu, uuidTpack * ptr); +static void uuidFgenerate(uuidTpack * out); +static void uuidFunpack(uuidTpack * in, uuidTid * uu); +static void uuidFunparse(uuidTpack * uu, char *out); + +static void uuidFunpack(uuidTpack * in, uuidTid * uu) +{ + uint8_t *ptr = (uint8_t *) in; + uint32_t tmp; + + tmp = *ptr++; + tmp = (tmp << 8) | *ptr++; + tmp = (tmp << 8) | *ptr++; + tmp = (tmp << 8) | *ptr++; + uu->time_low = tmp; + + tmp = *ptr++; + tmp = (tmp << 8) | *ptr++; + uu->time_mid = tmp; + + tmp = *ptr++; + tmp = (tmp << 8) | *ptr++; + uu->time_hi_and_version = tmp; + + tmp = *ptr++; + tmp = (tmp << 8) | *ptr++; + uu->clock_seq = tmp; + + memcpy(uu->node, ptr, 6); +} + +static void uuidFunparse(uuidTpack * uu, char *out) +{ + uuidTid uuid; + + uuidFunpack(uu, &uuid); + sprintf(out, + "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + uuid.time_low, uuid.time_mid, uuid.time_hi_and_version, + uuid.clock_seq >> 8, uuid.clock_seq & 0xFF, + uuid.node[0], uuid.node[1], uuid.node[2], + uuid.node[3], uuid.node[4], uuid.node[5]); +} + +static void uuidFpack(uuidTid * uu, uuidTpack * ptr) +{ + uint32_t tmp; + unsigned char *out = (unsigned char *) ptr; + + tmp = uu->time_low; + out[3] = (unsigned char) tmp; + tmp >>= 8; + out[2] = (unsigned char) tmp; + tmp >>= 8; + out[1] = (unsigned char) tmp; + tmp >>= 8; + out[0] = (unsigned char) tmp; + + tmp = uu->time_mid; + out[5] = (unsigned char) tmp; + tmp >>= 8; + out[4] = (unsigned char) tmp; + + tmp = uu->time_hi_and_version; + out[7] = (unsigned char) tmp; + tmp >>= 8; + out[6] = (unsigned char) tmp; + + tmp = uu->clock_seq; + out[9] = (unsigned char) tmp; + tmp >>= 8; + out[8] = (unsigned char) tmp; + + memcpy(out + 10, uu->node, 6); +} + +/* + * generates a UUID based on the current time on the platform. + */ +static void uuidFgenerate(uuidTpack * out) +{ + static unsigned char node_id[6]; + uuidTid uu; + uint32_t clock_mid; + uint32_t node_number; + + if ((node_number = utlFgethostid()) == 0) { + rndFrandom_bytes(node_id, 6); + /* + * Set multicast bit, to prevent conflicts with IEEE 802 addresses + * obtained from network cards + */ + node_id[0] |= 0x80; + } else { + memcpy(node_id, (char *) &node_number, 4); + } + + utlFclock_get(&clock_mid, &uu.time_low, &uu.clock_seq); + uu.clock_seq |= 0x8000; + uu.time_mid = (uint16_t) clock_mid; + uu.time_hi_and_version = (clock_mid >> 16) | 0x1000; + memcpy(uu.node, node_id, 6); + uuidFpack(&uu, out); +} + +/* Generate a uuid, and write it into the provided buffer. */ + +int uidFgenerate_str(char *id, size_t len) +{ + uuidTpack uuid; + + if (len < 37) + return -1; + + memFclear(&uuid, sizeof(uuidTpack)); + uuidFgenerate(&uuid); + uuidFunparse(&uuid, id); + + return 0; +} diff --git a/mk4/continuity/mecha/utl.c b/mk4/continuity/mecha/utl.c new file mode 100644 index 0000000..b783ba1 --- /dev/null +++ b/mk4/continuity/mecha/utl.c @@ -0,0 +1,868 @@ +/* + * $Header: /san01/cvs/ashpool/csrc/continuity/mecha/Attic/utl.c,v 1.31 2004/05/13 14:11:25 aleigh Exp $ + */ + +/* + * Copyright (c) 1994, 2004 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Disclosure, copying, distribution, or transmission of of this code without + * express permission is prohibited. + */ + +#include "mecha.h" + +struct utlSswatch { + unsigned int sa_sec; + unsigned int sa_usec; + unsigned int so_sec; + unsigned int so_usec; + unsigned int e_sec; + unsigned int e_usec; + unsigned int e_msec; +}; + +/* + * Stolen from Eric Lindvall 5stops.com + */ +int utlFfd_printf(int fd, const char *fmt, ...) +{ + va_list ap; + char *buf; + int size = 1024; + int e; + + assert(fmt != NULL); + + buf = (char *) malloc(size); + + assert(buf != NULL); + + va_start(ap, fmt); + + while (1) { + int nchars = vsnprintf(buf, size, fmt, ap); + + if (nchars > -1 && nchars < size) + break; + if (nchars > -1) + size = nchars + 1; + else + size *= 2; + buf = (char *) realloc(buf, size); + } + + va_end(ap); + + if ((e = write(fd, buf, strlen(buf))) == -1) + e = -errno; + + free(buf); + + return (e); +} + +unsigned int utlFtime(void) +{ + struct timeval tv; + + gettimeofday(&tv, NULL); + + return tv.tv_sec; +} + +/* + * under solaris 2.7, localtime is not MT-safe. localtime_r instead. + * + * this is very crude, and not necessarily the kind of thing that we really want + * to endorse, but it seems effective enough at 560/sec rates. + */ +volatile const struct tm *utlFlocaltime(void) +{ + static struct tm cache_tm; + static unsigned int cache_time; + static unsigned int processing = 0; + unsigned int now; + + now = utlFtime(); + + if (now != cache_time && processing == 0) { + processing = 1; + cache_time = now; + localtime_r((time_t *) & now, &cache_tm); + processing = 0; + } + return &cache_tm; +} + +static const char utlGmonths[48] = + "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec "; +static const char utlGdays[] = "Sun,Mon,Tue,Wed,Thu,Fri,Sat,"; + +/* + * Returns the time in common log format. This returned string is always 29 + * characters long. This looks kind of dubious, but it seems to work quite + * well. + */ +volatile const char *utlFcommonlog_time(void) +{ + volatile const struct tm *t = utlFlocaltime(); + char *p; + unsigned int a; + static char buf[30]; + int time_offset = 0; + + assert(t != NULL); + + p = buf + 29; + *p-- = '\0'; + *p-- = ' '; + *p-- = ']'; + a = abs(time_offset / 60); + *p-- = '0' + a % 10; + a /= 10; + *p-- = '0' + a % 6; + a /= 6; + *p-- = '0' + a % 10; + *p-- = '0' + a / 10; + *p-- = (time_offset > 0) ? '-' : '+'; + *p-- = ' '; + + a = t->tm_sec; + *p-- = '0' + a % 10; + *p-- = '0' + a / 10; + *p-- = ':'; + a = t->tm_min; + *p-- = '0' + a % 10; + *p-- = '0' + a / 10; + *p-- = ':'; + a = t->tm_hour; + *p-- = '0' + a % 10; + *p-- = '0' + a / 10; + *p-- = ':'; + a = 1900 + t->tm_year; + while (a) { + *p-- = '0' + a % 10; + a /= 10; + } + /* p points to an unused spot */ + *p-- = '/'; + p -= 2; + memcpy(p--, utlGmonths + 4 * (t->tm_mon), 3); + *p-- = '/'; + a = t->tm_mday; + *p-- = '0' + a % 10; + *p-- = '0' + a / 10; + *p = '['; + return p; /* should be same as returning buf */ +} + +volatile const char *utlFlocal_time(void) +{ + volatile const struct tm *t; + char *p; + unsigned int a; + static char buf[30]; + + t = utlFlocaltime(); + + assert(t != NULL); + + p = buf + 29; + *p-- = '\0'; + *p-- = ']'; + + a = t->tm_sec; + *p-- = '0' + a % 10; + *p-- = '0' + a / 10; + *p-- = ':'; + a = t->tm_min; + *p-- = '0' + a % 10; + *p-- = '0' + a / 10; + *p-- = ':'; + a = t->tm_hour; + *p-- = '0' + a % 10; + *p-- = '0' + a / 10; + *p-- = ':'; + a = 1900 + t->tm_year; + while (a) { + *p-- = '0' + a % 10; + a /= 10; + } + /* p points to an unused spot */ + *p-- = '/'; + p -= 2; + memcpy(p--, utlGmonths + 4 * (t->tm_mon), 3); + *p-- = '/'; + a = t->tm_mday; + *p-- = '0' + a % 10; + *p-- = '0' + a / 10; + *p = '['; + return p; /* should be same as returning buf */ +} + +utlTswatch *utlFstart_swatch(void) +{ + struct timeval tv; + utlTswatch *sw; + + gettimeofday(&tv, NULL); + + sw = malloc(sizeof(utlTswatch)); + memFclear(sw, sizeof(utlTswatch)); + + sw->sa_sec = tv.tv_sec; + sw->sa_usec = tv.tv_usec; + + return sw; +} + +unsigned int utlFstop_swatch(utlTswatch * sw) +{ + struct timeval tv; + unsigned int x; + + assert(sw != NULL); + + gettimeofday(&tv, NULL); + + sw->so_sec = tv.tv_sec; + sw->so_usec = tv.tv_usec; + + sw->e_sec = sw->so_sec - sw->sa_sec; + sw->e_usec = sw->so_usec - sw->sa_usec; + + x = (sw->e_sec * 1000) * 1000 + (sw->e_usec); + + free(sw); + + return x; +} + +int utlFtv_sub(struct timeval *r, const struct timeval *x, + const struct timeval *y) +{ + struct timeval working; + + assert(r != NULL); + assert(x != NULL); + assert(y != NULL); + + + memcpy(&working, y, sizeof(struct timeval)); + + if (x->tv_usec < working.tv_usec) { + int nsec = (working.tv_usec - x->tv_usec) / 1000000L + 1; + working.tv_usec -= 1000000L * nsec; + working.tv_sec += nsec; + } + if (x->tv_usec - working.tv_usec > 1000000L) { + int nsec = (x->tv_usec - working.tv_usec) / 1000000L; + working.tv_usec += 1000000L * nsec; + working.tv_sec -= nsec; + } + r->tv_sec = x->tv_sec - working.tv_sec; + r->tv_usec = x->tv_usec - working.tv_usec; + + /* Return 1 if result is negative. */ + return x->tv_sec < working.tv_sec; +} + +int utlFip_to_str(unsigned int ip, char *buf, size_t buflen) +{ + int a, b, c, d; + int carry; + + assert(buf != NULL); + + a = ip / 16777216; + carry = ip % 16777216; + + b = carry / 65536; + carry = carry % 65536; + + c = carry / 256; + d = carry % 256; + + return snprintf(buf, buflen, "%d.%d.%d.%d", a, b, c, d); +} + +unsigned int utlFstr_to_ip(const char *ip) +{ + return ntohl(inet_addr(ip)); +} + +int utlFisnum(const char c) +{ + return (c >= '0' && c <= '9' ? 1 : 0); +} + +/* check to see if the given string contains any alphas or is just numbers */ +int utlFstr_has_alphas(const char *p) +{ + const char *c; + int ret = 0; + + assert(p != NULL); + + for (c = p; *c != 0; c++) { + if (utlFisnum(*c) == 0) + ret = 1; + } + + return ret; +} + + +void utlFtv_add(struct timeval *res, struct timeval *t1, + struct timeval *t2) +{ + assert(res != NULL); + assert(t1 != NULL); + assert(t2 != NULL); + + res->tv_sec = t1->tv_sec + t2->tv_sec; + res->tv_usec = t1->tv_usec + t2->tv_usec; + + res->tv_sec += res->tv_usec / 1000000L; + + res->tv_usec %= 1000000L; +} + + +long utlFtv_to_ms(struct timeval *tv) +{ + assert(tv != NULL); + return (tv->tv_sec * 1000 + tv->tv_usec / 1000); +} + +/* + * Encode an URL in the URL encoding format. Arguments are an empty dynamic + * string that will contain the output encoding, and string, which is the + * string to be encoded. A pointer to the string content of the ds will be + * returned on success. + */ + +int utlFurl_encode(dynTstring * dyn, const char *string) +{ + static char safechars[] = + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789:/."; + + assert(dyn != NULL); + + if (string == NULL) + return -1; + + assert(dyn != NULL); + + while (*string != '\0') { + if (strchr(safechars, *string) != NULL) { + dynFappend(dyn, string, 1); + } else { + char buf[4]; + sprintf(buf, "%%%02x", (unsigned char) *string); + dynFappend(dyn, buf, 3); + } + ++string; + } + return 0; +} + +int utlFurl_decode(dynTstring * dyn, const char *string) +{ + unsigned char decoded; + char twobytes[3]; + + assert(dyn != NULL); + assert(string != NULL); + + twobytes[2] = '\0'; + while (*string != '\0') { + + if (*string == '+') { + dynFappend(dyn, " ", 1); + string++; + continue; + } + if (*string != '%') { + dynFappend(dyn, string, 1); + string++; + } else { + if (utlFhexdigit(string[1]) && utlFhexdigit(string[2])) { + twobytes[0] = string[1]; + twobytes[1] = string[2]; + decoded = + (unsigned char) strtol(twobytes, (char **) NULL, 16); + dynFappend(dyn, (char *) &decoded, 1); + string += 3; + } else { + return 0; + } + } + } + return 0; +} + +int utlFhexdigit(char c) +{ + static char hexdigits[] = "0123456789ABCDEFabcdef"; + return (c != '\0' && (strchr(hexdigits, c) != NULL)); +} + +/* + * return a 32-bit number identifying this machine. For Sun, this is the + * hostid. For other PC platforms it should probably return the MAC address + * of the 1st Ethernet controller. + */ +uint32_t utlFgethostid(void) +{ +#ifdef SOLARIS + return gethostid(); +#else + return 0; +#endif +} + +/* Microsecond granularity */ +#define MAX_ADJUSTMENT 10 + +int utlFclock_get(uint32_t * clock_high, uint32_t * clock_low, + uint16_t * ret_clock_seq) +{ + static int adjustment = 0; + static struct timeval last = { 0, 0 }; + uint16_t clock_seq; + struct timeval tv; + unsigned long long clock_reg; + + assert(clock_high != NULL); + assert(clock_low != NULL); + assert(ret_clock_seq != NULL); + + try_again: + gettimeofday(&tv, 0); + if ((last.tv_sec == 0) && (last.tv_usec == 0)) { + rndFrandom_bytes((unsigned char *) &clock_seq, sizeof(clock_seq)); + clock_seq &= 0x1FFF; + last = tv; + last.tv_sec--; + } + if ((tv.tv_sec < last.tv_sec) || + ((tv.tv_sec == last.tv_sec) && (tv.tv_usec < last.tv_usec))) { + clock_seq = (clock_seq + 1) & 0x1FFF; + adjustment = 0; + } else if ((tv.tv_sec == last.tv_sec) && (tv.tv_usec == last.tv_usec)) { + if (adjustment >= MAX_ADJUSTMENT) + goto try_again; + adjustment++; + } else + adjustment = 0; + + clock_reg = tv.tv_usec * 10 + adjustment; + clock_reg += ((unsigned long long) tv.tv_sec) * 10000000; + clock_reg += (((unsigned long long) 0x01B21DD2) << 32) + 0x13814000; + + *clock_high = clock_reg >> 32; + *clock_low = clock_reg; + *ret_clock_seq = clock_seq; + return 0; +} + +/* + * Parse 'when' into HTTP format time, GMT. The receiving buffer must be at + * least 40 characters to fully fit the time. + */ +size_t utlFhttp_time_print(time_t when, char *buf, size_t buflen) +{ + struct tm tmp; + + assert(buf != NULL); + + gmtime_r(&when, &tmp); + tmp.tm_isdst = 0; + + return strftime(buf, buflen, "%a, %d %b %Y %H:%M:%S GMT", &tmp); +} + + +static const char *month_names[12] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +}; + +static int MakeMonth(char *s) +{ + int i; + + assert(s != NULL); + + /* + * Make sure it's capitalized like this: "Jan" + */ + + *s = toupper(*s); + *(s + 1) = tolower(*(s + 1)); + *(s + 2) = tolower(*(s + 2)); + + for (i = 0; i < 12; i++) { + if (!strncmp(month_names[i], s, 3)) { + return i; + } + } + return 0; +} + +static int MakeNum(char *s) +{ + assert(s != NULL); + + if (*s >= '0' && *s <= '9') { + return (10 * (*s - '0')) + (*(s + 1) - '0'); + } else { + return *(s + 1) - '0'; + } +} + +time_t utlFhttp_time_parse(char *str) +{ + char *s; + struct tm tm; + time_t t; + time_t toff; + + if (str == NULL) { + return 0; + } + /* + * Find the comma after day-of-week + * + * Thursday, 10-Jun-93 01:29:59 GMT ^ +-- s + * + * Thu, 10 Jan 1993 01:29:59 GMT ^ +-- s + */ + + s = strchr(str, ','); + if (s != NULL) { + + /* + * Advance S to the first non-space after the comma which should be + * the first digit of the day. + */ + + s++; + while (*s && *s == ' ') { + s++; + } + + /* + * Figure out which format it is in. If there is a hyphen, then it + * must be the first format. + */ + + if (strchr(s, '-') != NULL) { + if (strlen(s) < 18) { + return 0; + } + /* + * The format is: + * + * Thursday, 10-Jun-93 01:29:59 GMT ^ +--s + */ + + tm.tm_mday = MakeNum(s); + tm.tm_mon = MakeMonth(s + 3); + tm.tm_year = MakeNum(s + 7); + tm.tm_hour = MakeNum(s + 10); + tm.tm_min = MakeNum(s + 13); + tm.tm_sec = MakeNum(s + 16); + } else { + if ((int) strlen(s) < 20) { + return 0; + } + /* + * The format is: + * + * Thu, 10 Jan 1993 01:29:59 GMT Thu, 10 Jan 1993 01:29:59 GMT ^ + * +--s + */ + + tm.tm_mday = MakeNum(s); + tm.tm_mon = MakeMonth(s + 3); + tm.tm_year = (100 * MakeNum(s + 7) - 1900) + MakeNum(s + 9); + tm.tm_hour = MakeNum(s + 12); + tm.tm_min = MakeNum(s + 15); + tm.tm_sec = MakeNum(s + 18); + } + } else { + + /* + * No commas, so it must be the third, fixed field, format: + * + * Wed Jun 9 01:29:59 1993 GMT + * + * Advance s to the first letter of the month. + */ + + s = str; + while (*s && *s == ' ') { + s++; + } + if ((int) strlen(s) < 24) { + return 0; + } + tm.tm_mday = MakeNum(s + 8); + tm.tm_mon = MakeMonth(s + 4); + tm.tm_year = MakeNum(s + 22); + tm.tm_hour = MakeNum(s + 11); + tm.tm_min = MakeNum(s + 14); + tm.tm_sec = MakeNum(s + 17); + } + + /* + * If there are any impossible values, then return an error. + */ + + if (tm.tm_sec < 0 || tm.tm_sec > 59 || + tm.tm_min < 0 || tm.tm_min > 59 || + tm.tm_hour < 0 || tm.tm_hour > 23 || + tm.tm_mday < 1 || tm.tm_mday > 31 || + tm.tm_mon < 0 || tm.tm_mon > 11 || tm.tm_year < 70 + || tm.tm_year > 120) { + return 0; + } + tm.tm_isdst = 0; + toff = (time_t) timezone; + t = mktime(&tm) - toff; + return t; +} + +int utlFgetuid (const char *username) +{ + struct passwd pw; + + assert(username != NULL); + + if (utlFget_pwname(username, &pw) == -1) { + return -1; + } else { + return pw.pw_uid; + } +} + +int utlFgetgid (const char *username) +{ + struct passwd pw; + + assert(username != NULL); + + if (utlFget_pwname(username, &pw) == -1) { + return -1; + } else { + return pw.pw_gid; + } +} + +int utlFget_pwname(const char *username, struct passwd *pw) +{ + struct passwd *pwptr; + char pwbuf[512]; + + assert(username != NULL); + assert(pw != NULL); + +#ifdef SOLARIS + if ((pwptr = getpwnam_r(username, pw, pwbuf, 512)) != NULL) { +#else + if (!getpwnam_r(username, pw, pwbuf, 512, &pwptr) && pwptr) { +#endif + + /* Do Nothing */ + } else { + if (errno == 0) { + /* this can happen with getpwnam() on FreeBSD 4.3 */ + return -1; + } + return -1; + } + return 0; +} + +int utlFget_homedir(const char *username, char *dir, size_t dir_len) +{ +#ifndef WIN32 + struct passwd pw; + size_t len; + + assert(username != NULL); + assert(dir != NULL); + assert(dir_len > 0); + + if (utlFget_pwname(username, &pw) != 0) + return -1; + + len = strlen(pw.pw_dir); + + /* NULL */ + len++; + if (len > dir_len) + return -1; + + memcpy(dir, pw.pw_dir, len); + + return len; +#else + return -1; +#endif +} + +void utlFhours_to_hourmin(double in_time, int *hours, int *mins) +{ + *mins = in_time * 60; + *hours = *mins / 60; + *mins = *mins % 60; +} + +double utlFhourmin_to_hours(const int hours, const int mins) +{ + return hours + ((double) mins / 60.0); +} + +int utlFip_match(unsigned int ipa, unsigned int ipb, unsigned int netmask) +{ + if ((ipa & netmask) == (ipb & netmask)) + return 1; + return 0; +} + +int utlFip_validate(const char *addr) { + int dot_count; + int digit_count; + + dot_count = 0; + digit_count = 0; + while(*addr != '\0' && *addr != ' ') { + if(*addr == '.') { + dot_count++; + digit_count = 0; + } + else if(!isdigit(*addr)) { + dot_count = 5; + } + else { + digit_count++; + if(digit_count > 3) { + dot_count = 5; + } + } + addr++; + } + if(dot_count != 3) { + return(-1); + } + else { + return(0); + } +} + +static const char *utlGnumber_lut[] = { + "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", "65", "66", "67", "68", "69", "70", "71", + "72", "73", "74", "75", "76", "77", "78", "79", "80", "81", "82", "83", + "84", "85", "86", "87", "88", "89", "90", "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", "128", "129", "130", "131", "132", "133", "134", "135", "136", + "137", "138", "139", "140", "141", "142", "143", "144", "145", "146", + "147", "148", "149", "150", "151", "152", "153", "154", "155", "156", + "157", "158", "159", "160", "161", "162", "163", "164", "165", "166", + "167", "168", "169", "170", "171", "172", "173", "174", "175", "176", + "177", "178", "179", "180", "181", "182", "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", "215", "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", + "247", "248", "249", "250", "251", "252", "253", "254", "255" +}; + +const char *utlFshort_to_str(unsigned short n) +{ + return utlGnumber_lut[n]; +} + +unsigned int utlFatoui(const char *s) { + assert(sizeof(unsigned long)==sizeof(unsigned int)); + + return (unsigned int)strtoul(s, (char **)NULL, 0); +} + +int utlFatoi(const char *s) { + return (int) strtol (s, (char **)NULL, 10); +} + +void utlFhexdump(void *data, size_t size) +{ + /* dumps size bytes of *data to stdout. Looks like: + * [0000] 75 6E 6B 6E 6F 77 6E 20 + * 30 FF 00 00 00 00 39 00 unknown 0.....9. + * (in a single line of course) + */ + + unsigned char *p = data; + unsigned char c; + int n; + char bytestr[4] = {0}; + char addrstr[10] = {0}; + char hexstr[ 16*3 + 5] = {0}; + char charstr[16*1 + 5] = {0}; + for(n=1;n<=size;n++) { + if (n%16 == 1) { + /* store address for this line */ + snprintf(addrstr, sizeof(addrstr), "%.4x", + ((unsigned int)p-(unsigned int)data) ); + } + + c = *p; + if (isalnum(c) == 0) { + c = '.'; + } + + /* store hex str (for left side) */ + snprintf(bytestr, sizeof(bytestr), "%02X ", *p); + strncat(hexstr, bytestr, sizeof(hexstr)-strlen(hexstr)-1); + + /* store char str (for right side) */ + snprintf(bytestr, sizeof(bytestr), "%c", c); + strncat(charstr, bytestr, sizeof(charstr)-strlen(charstr)-1); + + if(n%16 == 0) { + /* line completed */ + printf("[%4.4s] %-50.50s %s\n", addrstr, hexstr, charstr); + hexstr[0] = 0; + charstr[0] = 0; + } else if(n%8 == 0) { + /* half line: add whitespaces */ + strncat(hexstr, " ", sizeof(hexstr)-strlen(hexstr)-1); + strncat(charstr, " ", sizeof(charstr)-strlen(charstr)-1); + } + p++; /* next byte */ + } + + if (strlen(hexstr) > 0) { + /* print rest of buffer if not empty */ + printf("[%4.4s] %-50.50s %s\n", addrstr, hexstr, charstr); + } +} + + diff --git a/mk4/continuity/mecha/w32.c b/mk4/continuity/mecha/w32.c new file mode 100644 index 0000000..68ff4d6 --- /dev/null +++ b/mk4/continuity/mecha/w32.c @@ -0,0 +1,102 @@ +/* + * $Header: /san01/cvs/ashpool/csrc/continuity/mecha/Attic/w32.c,v 1.5 2004/04/30 13:41:56 aleigh Exp $ + */ + +/* + * Copyright (c) 2004 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Use, disclosure, copying, distribution, or transmission of this code without + * express permission is prohibited. + */ + +#include "mecha.h" + +MECHA_UNUSED static int not_empty; + +#ifdef WIN32 + + +int gettimeofday(struct timeval *time_Info, struct timezone *timezone_Info) +{ + static struct timeval starttime = { 0, 0 }; + static __int64 lasttime = 0; + static __int64 freq = 0; + __int64 timer; + LARGE_INTEGER li; + BOOL b; + double dt; + + /* Get the time, if they want it */ + if (time_Info != NULL) { + if (starttime.tv_sec == 0) { + b = QueryPerformanceFrequency(&li); + if (!b) { + starttime.tv_sec = -1; + } else { + freq = li.QuadPart; + b = QueryPerformanceCounter(&li); + if (!b) { + starttime.tv_sec = -1; + } else { + getfilesystemtime(&starttime); + timer = li.QuadPart; + dt = (double) timer / freq; + starttime.tv_usec -= (int) ((dt - (int) dt) * 1000000); + if (starttime.tv_usec < 0) { + starttime.tv_usec += 1000000; + --starttime.tv_sec; + } + starttime.tv_sec -= (int) dt; + } + } + } + if (starttime.tv_sec > 0) { + b = QueryPerformanceCounter(&li); + if (!b) { + starttime.tv_sec = -1; + } else { + timer = li.QuadPart; + if (timer < lasttime) { + getfilesystemtime(time_Info); + dt = (double) timer / freq; + starttime = *time_Info; + starttime.tv_usec -= (int) ((dt - (int) dt) * 1000000); + if (starttime.tv_usec < 0) { + starttime.tv_usec += 1000000; + --starttime.tv_sec; + } + starttime.tv_sec -= (int) dt; + } else { + lasttime = timer; + dt = (double) timer / freq; + time_Info->tv_sec = starttime.tv_sec + (int) dt; + time_Info->tv_usec = + starttime.tv_usec + + (int) ((dt - (int) dt) * 1000000); + if (time_Info->tv_usec > 1000000) { + time_Info->tv_usec -= 1000000; + ++time_Info->tv_sec; + } + } + } + } + if (starttime.tv_sec < 0) { + getfilesystemtime(time_Info); + } + } + /* Get the timezone, if they want it */ + if (timezone_Info != NULL) { + _tzset(); + timezone_Info->tz_minuteswest = _timezone; + timezone_Info->tz_dsttime = _daylight; + } + /* And return */ + return 0; +} + + +#endif diff --git a/mk4/continuity/mecha/xml.c b/mk4/continuity/mecha/xml.c new file mode 100644 index 0000000..cba8ba6 --- /dev/null +++ b/mk4/continuity/mecha/xml.c @@ -0,0 +1,555 @@ +/* + * $Header: /san01/cvs/ashpool/csrc/continuity/mecha/Attic/xml.c,v 1.21 2004/04/30 13:41:56 aleigh Exp $ + */ + +/* + * Copyright (c) 2004 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Use, disclosure, copying, distribution, or transmission of this code without + * express permission is prohibited. + */ + +#include "mecha.h" + +#undef _XML_DEBUG + +struct xmlSiterator { + const struct xmlStag *first; + const struct xmlStag *tag; +}; + +struct xmlSconfig { + struct xmlStag *tags; +}; + +struct xmlStag { + char *name; /* My name */ + size_t name_len; + char *value; /* My string value, if I have one */ + size_t value_len; + lstTset *attrib_list; + struct xmlStag *linear_child; /* Child tags */ + struct xmlStag *linear_next; /* Brother Tag */ +}; + +static const char *xmlF_parse(const char *str, const char *level, + xmlTtag * parent, lstTset * arglist); +static void xmlFtag_addchild(xmlTtag * parent, xmlTtag * child); +static xmlTconfig *xmlFconfig_init(void); +static xmlTtag *xmlFtag_init(void); +static void xmlFtag_free(xmlTtag * tag); + +const xmlTtag *xmlFiterator_tag(xmlTiterator *it) { + assert(it!=NULL); + + return it->tag; +} + +const char *xmlFtag_get_name(const xmlTtag * tag, size_t * name_len) +{ + assert(tag != NULL); + assert(name_len != NULL); + + *name_len = tag->name_len; + return tag->name; +} + +const char *xmlFtag_get_value_str(const xmlTtag * tag) +{ + assert(tag != NULL); + + return tag->value; +} + +const char *xmlFtag_get_name_str(const xmlTtag * tag) +{ + assert(tag != NULL); + + return tag->name; +} + +const char *xmlFtag_get_value(const xmlTtag * tag, size_t * value_len) +{ + assert(tag != NULL); + assert(value_len != NULL); + + *value_len = tag->value_len; + return tag->value; +} + +const lstTset *xmlFtag_get_attribs(const xmlTtag * tag) +{ + assert(tag != NULL); + return tag->attrib_list; +} + +const xmlTtag *xmlFtag_get_children(const xmlTtag * tag) +{ + assert(tag != NULL); + + return tag->linear_child; +} + +xmlTiterator *xmlFiterator_init(const xmlTtag * tag) +{ + xmlTiterator *iterator; + + assert(tag != NULL); + + iterator = (xmlTiterator *) malloc(sizeof(xmlTiterator)); + + assert(iterator != NULL); + + iterator->tag = iterator->first = tag; + + return iterator; +} + +void xmlFiterator_reset(xmlTiterator *iterator) { + assert(iterator!=NULL); + iterator->tag=iterator->first; +} + +xmlTiterator *xmlFiterate_children(const xmlTtag * tag) +{ + xmlTiterator *iterator; + + assert(tag != NULL); + + if (tag->linear_child == NULL) + return NULL; + + iterator = (xmlTiterator *) malloc(sizeof(xmlTiterator)); + + iterator->tag = tag->linear_child; + + return iterator; +} + +void xmlFiterator_free(xmlTiterator * iterator) +{ + assert(iterator != NULL); + + free(iterator); +} + +const xmlTtag *xmlFiterator_next_name(xmlTiterator * iterator, + const char *name) +{ + const xmlTtag *t; + + assert(iterator!=NULL); + assert(name!=NULL); + +#ifdef _XML_DEBUG + logFmsg(3,"xmlFiterator_next_name: Called to search for %s", name); +#endif + + + while ((t = xmlFiterator_next(iterator)) != NULL) { +#ifdef _XML_DEBUG + logFmsg(3,"xmlFiterator_next_name: Testing '%s' == '%s'", t->name, name); +#endif + if (strcmp(t->name, name) == 0) { +#ifdef _XML_DEBUG + logFmsg(3,"xmlFiterator_next_name: Returning 0x%x", t); +#endif + return t; + } + } + +#ifdef _XML_DEBUG + logFmsg(3,"xmlFiterator_next_name: Returning NULL"); +#endif + + return NULL; +} + +const xmlTtag *xmlFfind_first_tag_children(const xmlTtag * tag, + const char *name) +{ + const xmlTtag *t; + + assert(tag!=NULL); + assert(name!=NULL); + + t = xmlFfind_first_tag(tag, name); + + if (t == NULL) { + return NULL; + } else { + return t->linear_child; + } +} + +const xmlTtag *xmlFfind_first_child(const xmlTtag *tag, const char *name) { + xmlTiterator *it; + const xmlTtag *match; + + assert(tag!=NULL); + assert(name!=NULL); + + it=xmlFiterate_children(tag); + + if(it==NULL) { + return NULL; + } + + match=xmlFiterator_next_name(it,name); + + xmlFiterator_free(it); + + return match; +} + +const xmlTtag *xmlFfind_first_tag(const xmlTtag * tag, const char *name) +{ + xmlTiterator *it; + const xmlTtag *t; + + assert(tag != NULL); + assert(name != NULL); + + it = xmlFiterator_init(tag); + + assert(it != NULL); + + t = xmlFiterator_next_name(it, name); + + xmlFiterator_free(it); + + return t; +} + +const xmlTtag *xmlFiterator_next(xmlTiterator * iterator) +{ + const xmlTtag *t; + + assert(iterator != NULL); + + if (iterator->tag == NULL) { + return NULL; + } + + t = iterator->tag; + + iterator->tag = iterator->tag->linear_next; + + return t; +} + +static xmlTconfig *xmlFconfig_init(void) +{ + xmlTconfig *config = (xmlTconfig *) malloc(sizeof(xmlTconfig)); + memFclear(config, sizeof(xmlTconfig)); + return config; +} + +/* + * But I will go down with this ship, and I won't hurt myself and surrender, + * there will be no white flag above my door -aleigh + */ + +static xmlTtag *xmlFtag_init(void) +{ + xmlTtag *tag = (xmlTtag *) malloc(sizeof(xmlTtag)); + assert(tag != NULL); + memFclear(tag, sizeof(xmlTtag)); + return tag; +} + +static void xmlFtag_free(xmlTtag * tag) +{ + assert(tag != NULL); + if (tag->name != NULL) + free(tag->name); + if (tag->value != NULL) + free(tag->value); + free(tag); +} + +static void xmlFtag_addchild(xmlTtag * parent, xmlTtag * child) +{ + xmlTtag *p; + + assert(parent != NULL); + assert(child != NULL); + + if (parent->linear_child == NULL) { + parent->linear_child = child; + } else { + for (p = parent->linear_child; p->linear_next != NULL; + p = p->linear_next) { + /* Do Nothing */ + } + assert(p != NULL); + p->linear_next = child; + } +} + +/* I really hope to whatever god is convinient that we do not have to change + * anything in this function ever again -aleigh + */ +#define P_SEARCH 1 /* Searching for 1 */ +#define P_TAG 2 /* In <> tag, break > */ +#define P_NAME 3 /* submode: copying tag name */ +#define P_ARG 4 /* submode: copying tag attributes */ + +static const char *xmlF_parse(const char *str, const char *level, + xmlTtag * parent, lstTset * my_arglist) +{ + const char *p; + int mode = P_SEARCH; + int submode = P_NAME; + char buf[128]; + int buf_p = 0; + char arglist[128]; + int arglist_p = 0; + lstTset *argset = NULL; + xmlTtag *my_tag = xmlFtag_init(); + + assert(str != NULL); + assert(level != NULL); + assert(parent != NULL); + + /* make sure that at least we have an empty arglist */ + arglist[0] = 0; + + my_tag->name = strFcopy_size(level, &my_tag->name_len); + my_tag->attrib_list = my_arglist; + + xmlFtag_addchild(parent, my_tag); + + /* + * When P_SEARCH is high the parser is searching for a tag, while copying + * the value into buf. When P_TAG comes high, the parser is inside a tag + * and is copying the tag name into buf. + */ + + for (p = str; *p != 0; p++) { + switch (mode) { + case P_SEARCH: + if (*p == '<') { + if (buf_p > 0) { + buf[buf_p] = 0; + + if (strFis_blank(buf) == 0) { + my_tag->value = strFcopy(buf); + my_tag->value_len = strlen(buf); + } + buf_p = 0; + } + if (*(p + 1) == '!' && *(p + 2) == '-' && *(p + 3) == '-') { + /* It's */ + for (; *p != 0; p++) { + if (*p == '>' && *(p - 1) == '-' + && *(p - 2) == '-') { + break; + } + } + continue; + } else { + mode = P_TAG; + break; + } + } + /* Copy in value */ + buf[buf_p] = *p; + buf_p++; + break; + case P_TAG: + if (*p == ' ' && submode == P_NAME) { + /* We were doign the name, now we have an arglist */ + /* Finish buf */ + buf[buf_p] = 0; + buf_p = 0; + submode = P_ARG; + break; + } + if (*p == '>') { + + if (submode == P_NAME) { + /* we were copying the tags; so finish that */ + buf[buf_p] = 0; + buf_p = 0; + } else { + /* We were copying attributes; so finish that */ + arglist[arglist_p] = 0; + arglist_p = 0; + } + + if (buf[0] == '/') { + + for (; *p != 0; p++) + if (*p == '>') + return p; + return NULL; + } + argset = strFattrib_parser(arglist); + + /* let's see if this tag closes itself */ + if (buf[0] != '/' && *(p - 1) == '/') { + xmlTtag *child = xmlFtag_init(); + + child->name = strFcopy_size(buf, &child->name_len); + child->attrib_list = argset; + + /* + * add this new child to my_tag (which would be the + * parent + */ + xmlFtag_addchild(my_tag, child); + } else { + p = xmlF_parse(p + 1, (char *) &buf, my_tag, argset); + argset = NULL; + /* Short input stream - collapse */ + if (p == NULL) + return NULL; + } + + mode = P_SEARCH; + submode = P_NAME; + break; + } + if (submode == P_NAME) { + /* We are copying the tag name */ + buf[buf_p] = *p; + buf_p++; + } else { + /* We are copying the tag arglist */ + arglist[arglist_p] = *p; + arglist_p++; + } + break; + } + } + + return NULL; +} + +xmlTconfig *xmlFparse(const char *str) +{ + xmlTtag *tag = xmlFtag_init(); + xmlTconfig *config = xmlFconfig_init(); + + assert(str != NULL); + + tag->name = strFcopy("__base"); + tag->name_len = strlen("__base"); + + xmlF_parse(str, "__base_config", tag, NULL); + + config->tags = tag->linear_child->linear_child; + + xmlFtag_free(tag->linear_child); + xmlFtag_free(tag); + + return config; +} + +xmlTconfig *xmlFload_file(const char *filename) +{ + char *config; + size_t config_len; + xmlTconfig *c; + dynTstring *clean; + + assert(filename != NULL); + + config = fleFload_file(filename, &config_len); + + if (config == NULL) { + return NULL; + } + clean = strFcollapse_whitespace(config); + assert(clean != NULL); + + c = xmlFparse(dynFgetstr(clean)); + + dynFfree(clean); + free(config); + + return c; +} + +xmlTtag *xmlFbase_tag(const xmlTconfig * config) +{ + assert(config != NULL); + + return config->tags; +} + +const char *xmlFtag_get_attrib_value(const xmlTtag * tag, const char *name) +{ + const lstTset *set; + + assert(tag != NULL); + assert(name != NULL); + + set = xmlFtag_get_attribs(tag); + + if (set != NULL) + return lstFset_get(set, name); + else + return NULL; +} + + +lstTset *xmlFcreate_list(const xmlTtag * tag, const char *tagname, + const char *attribname) +{ + lstTset *list; + xmlTiterator *tags; + const xmlTtag *t; + const char *key, *val; + + assert(tag != NULL); + assert(tagname != NULL); + assert(attribname != NULL); + + tags = xmlFiterator_init(tag); + + assert(tags != NULL); + + list = lstFset_init(); + + while ((t = xmlFiterator_next_name(tags, tagname)) != NULL) { + key = xmlFtag_get_attrib_value(t, attribname); + if (key == NULL) + continue; + val = xmlFtag_get_value_str(t); + if (val == NULL) + continue; + lstFset_add(list, key, val); + } + + return list; +} + +const char *xmlFfirst_child_value_str (const xmlTtag *tag, const char *name) { + size_t unused; + + assert(tag!=NULL); + assert(name!=NULL); + + return (xmlFfirst_child_value (tag, name, &unused)); +} + +const char *xmlFfirst_child_value(const xmlTtag *tag, const char *name, size_t *value_len) { + const xmlTtag *child; + + assert(tag!=NULL); + assert(name!=NULL); + + child=xmlFfind_first_child(tag,name); + + if(child==NULL) { + return NULL; + } + + return xmlFtag_get_value(child,value_len); +} diff --git a/mk4/continuity/pcre/.cvsignore b/mk4/continuity/pcre/.cvsignore new file mode 100644 index 0000000..5cb998d --- /dev/null +++ b/mk4/continuity/pcre/.cvsignore @@ -0,0 +1,15 @@ +*.lo +*.la +config.log +.libs +config.status +Makefile +libtool +pcre.h +pcre-config +RunTest +config.h +chartables.c +pcretest +pcregrep +dftables diff --git a/mk4/continuity/pcre/AUTHORS b/mk4/continuity/pcre/AUTHORS new file mode 100644 index 0000000..832dddc --- /dev/null +++ b/mk4/continuity/pcre/AUTHORS @@ -0,0 +1,6 @@ +Written by: Philip Hazel + +University of Cambridge Computing Service, +Cambridge, England. Phone: +44 1223 334714. + +Copyright (c) 1997-2001 University of Cambridge diff --git a/mk4/continuity/pcre/COPYING b/mk4/continuity/pcre/COPYING new file mode 100644 index 0000000..8d68061 --- /dev/null +++ b/mk4/continuity/pcre/COPYING @@ -0,0 +1,54 @@ +PCRE LICENCE +------------ + +PCRE is a library of functions to support regular expressions whose syntax +and semantics are as close as possible to those of the Perl 5 language. + +Written by: Philip Hazel + +University of Cambridge Computing Service, +Cambridge, England. Phone: +44 1223 334714. + +Copyright (c) 1997-2001 University of Cambridge + +Permission is granted to anyone to use this software for any purpose on any +computer system, and to redistribute it freely, subject to the following +restrictions: + +1. This software 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. + +2. The origin of this software must not be misrepresented, either by + explicit claim or by omission. In practice, this means that if you use + PCRE in software that you distribute to others, commercially or + otherwise, you must put a sentence like this + + Regular expression support is provided by the PCRE library package, + which is open source software, written by Philip Hazel, and copyright + by the University of Cambridge, England. + + somewhere reasonably visible in your documentation and in any relevant + files or online help data or similar. A reference to the ftp site for + the source, that is, to + + ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/ + + should also be given in the documentation. However, this condition is not + intended to apply to whole chains of software. If package A includes PCRE, + it must acknowledge it, but if package B is software that includes package + A, the condition is not imposed on package B (unless it uses PCRE + independently). + +3. Altered versions must be plainly marked as such, and must not be + misrepresented as being the original software. + +4. If PCRE is embedded in any software that is released under the GNU + General Purpose Licence (GPL), or Lesser General Purpose Licence (LGPL), + then the terms of that licence shall supersede any condition above with + which it is incompatible. + +The documentation for PCRE, supplied in the "doc" directory, is distributed +under the same terms as the software itself. + +End diff --git a/mk4/continuity/pcre/CVS/Entries b/mk4/continuity/pcre/CVS/Entries new file mode 100644 index 0000000..cf27089 --- /dev/null +++ b/mk4/continuity/pcre/CVS/Entries @@ -0,0 +1,37 @@ +/.cvsignore/1.1/Thu Mar 11 01:11:48 2004//Tmk4_mod6_rc2 +/AUTHORS/1.1/Fri Nov 7 14:48:15 2003//Tmk4_mod6_rc2 +/COPYING/1.1/Fri Nov 7 14:48:15 2003//Tmk4_mod6_rc2 +/ChangeLog/1.1/Fri Nov 7 14:48:15 2003//Tmk4_mod6_rc2 +/INSTALL/1.1/Fri Nov 7 14:48:15 2003//Tmk4_mod6_rc2 +/LICENCE/1.1/Fri Nov 7 14:48:15 2003//Tmk4_mod6_rc2 +/Makefile.in/1.1/Fri Nov 7 14:48:15 2003//Tmk4_mod6_rc2 +/NEWS/1.1/Fri Nov 7 14:48:15 2003//Tmk4_mod6_rc2 +/NON-UNIX-USE/1.1/Fri Nov 7 14:48:15 2003//Tmk4_mod6_rc2 +/README/1.1/Fri Nov 7 14:48:15 2003//Tmk4_mod6_rc2 +/RunTest.in/1.1/Fri Nov 7 14:48:15 2003//Tmk4_mod6_rc2 +/config.guess/1.1/Fri Nov 7 14:48:15 2003//Tmk4_mod6_rc2 +/config.in/1.1/Fri Nov 7 14:48:15 2003//Tmk4_mod6_rc2 +/config.sub/1.1/Fri Nov 7 14:48:15 2003//Tmk4_mod6_rc2 +/configure/1.1/Fri Nov 7 14:48:15 2003//Tmk4_mod6_rc2 +/configure.in/1.1/Fri Nov 7 14:48:15 2003//Tmk4_mod6_rc2 +/dftables.c/1.1/Fri Nov 7 14:48:15 2003//Tmk4_mod6_rc2 +/get.c/1.1/Fri Nov 7 14:48:15 2003//Tmk4_mod6_rc2 +/install-sh/1.1/Fri Nov 7 14:48:15 2003//Tmk4_mod6_rc2 +/internal.h/1.1/Fri Nov 7 14:48:15 2003//Tmk4_mod6_rc2 +/ltmain.sh/1.1/Fri Nov 7 14:48:15 2003//Tmk4_mod6_rc2 +/maketables.c/1.1/Fri Nov 7 14:48:15 2003//Tmk4_mod6_rc2 +/makevp.bat/1.1/Fri Nov 7 14:48:15 2003//Tmk4_mod6_rc2 +/mkinstalldirs/1.1/Fri Nov 7 14:48:15 2003//Tmk4_mod6_rc2 +/pcre-config.in/1.1/Fri Nov 7 14:48:15 2003//Tmk4_mod6_rc2 +/pcre.c/1.1/Fri Nov 7 14:48:15 2003//Tmk4_mod6_rc2 +/pcre.def/1.1/Fri Nov 7 14:48:15 2003//Tmk4_mod6_rc2 +/pcre.in/1.1/Fri Nov 7 14:48:15 2003//Tmk4_mod6_rc2 +/pcredemo.c/1.2/Tue Feb 24 19:22:06 2004//Tmk4_mod6_rc2 +/pcregrep.c/1.1/Fri Nov 7 14:48:15 2003//Tmk4_mod6_rc2 +/pcreposix.c/1.1/Fri Nov 7 14:48:15 2003//Tmk4_mod6_rc2 +/pcreposix.h/1.1/Fri Nov 7 14:48:15 2003//Tmk4_mod6_rc2 +/pcretest.c/1.1/Fri Nov 7 14:48:15 2003//Tmk4_mod6_rc2 +/perltest/1.1/Fri Nov 7 14:48:15 2003//Tmk4_mod6_rc2 +/printint.c/1.1/Fri Nov 7 14:48:15 2003//Tmk4_mod6_rc2 +/study.c/1.1/Fri Nov 7 14:48:15 2003//Tmk4_mod6_rc2 +D diff --git a/mk4/continuity/pcre/CVS/Repository b/mk4/continuity/pcre/CVS/Repository new file mode 100644 index 0000000..e8d1b61 --- /dev/null +++ b/mk4/continuity/pcre/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/continuity/pcre diff --git a/mk4/continuity/pcre/CVS/Root b/mk4/continuity/pcre/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/continuity/pcre/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/continuity/pcre/CVS/Tag b/mk4/continuity/pcre/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/continuity/pcre/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/continuity/pcre/ChangeLog b/mk4/continuity/pcre/ChangeLog new file mode 100644 index 0000000..b912314 --- /dev/null +++ b/mk4/continuity/pcre/ChangeLog @@ -0,0 +1,1320 @@ +ChangeLog for PCRE +------------------ + +Version 4.3 21-May-03 +--------------------- + +1. Two instances of @WIN_PREFIX@ omitted from the Windows targets in the + Makefile. + +2. Some refactoring to improve the quality of the code: + + (i) The utf8_table... variables are now declared "const". + + (ii) The code for \cx, which used the "case flipping" table to upper case + lower case letters, now just substracts 32. This is ASCII-specific, + but the whole concept of \cx is ASCII-specific, so it seems + reasonable. + + (iii) PCRE was using its character types table to recognize decimal and + hexadecimal digits in the pattern. This is silly, because it handles + only 0-9, a-f, and A-F, but the character types table is locale- + specific, which means strange things might happen. A private + table is now used for this - though it costs 256 bytes, a table is + much faster than multiple explicit tests. Of course, the standard + character types table is still used for matching digits in subject + strings against \d. + + (iv) Strictly, the identifier ESC_t is reserved by POSIX (all identifiers + ending in _t are). So I've renamed it as ESC_tee. + +3. The first argument for regexec() in the POSIX wrapper should have been + defined as "const". + +4. Changed pcretest to use malloc() for its buffers so that they can be + Electric Fenced for debugging. + +5. There were several places in the code where, in UTF-8 mode, PCRE would try + to read one or more bytes before the start of the subject string. Often this + had no effect on PCRE's behaviour, but in some circumstances it could + provoke a segmentation fault. + +6. A lookbehind at the start of a pattern in UTF-8 mode could also cause PCRE + to try to read one or more bytes before the start of the subject string. + +7. A lookbehind in a pattern matched in non-UTF-8 mode on a PCRE compiled with + UTF-8 support could misbehave in various ways if the subject string + contained bytes with the 0x80 bit set and the 0x40 bit unset in a lookbehind + area. (PCRE was not checking for the UTF-8 mode flag, and trying to move + back over UTF-8 characters.) + + +Version 4.2 14-Apr-03 +--------------------- + +1. Typo "#if SUPPORT_UTF8" instead of "#ifdef SUPPORT_UTF8" fixed. + +2. Changes to the building process, supplied by Ronald Landheer-Cieslak + [ON_WINDOWS]: new variable, "#" on non-Windows platforms + [NOT_ON_WINDOWS]: new variable, "#" on Windows platforms + [WIN_PREFIX]: new variable, "cyg" for Cygwin + * Makefile.in: use autoconf substitution for OBJEXT, EXEEXT, BUILD_OBJEXT + and BUILD_EXEEXT + Note: automatic setting of the BUILD variables is not yet working + set CPPFLAGS and BUILD_CPPFLAGS (but don't use yet) - should be used at + compile-time but not at link-time + [LINK]: use for linking executables only + make different versions for Windows and non-Windows + [LINKLIB]: new variable, copy of UNIX-style LINK, used for linking + libraries + [LINK_FOR_BUILD]: new variable + [OBJEXT]: use throughout + [EXEEXT]: use throughout + : new target + : new target + : use native compiler + : use native linker + : handle Windows platform correctly + : ditto + : ditto + copy DLL to top builddir before testing + + As part of these changes, -no-undefined was removed again. This was reported + to give trouble on HP-UX 11.0, so getting rid of it seems like a good idea + in any case. + +3. Some tidies to get rid of compiler warnings: + + . In the match_data structure, match_limit was an unsigned long int, whereas + match_call_count was an int. I've made them both unsigned long ints. + + . In pcretest the fact that a const uschar * doesn't automatically cast to + a void * provoked a warning. + + . Turning on some more compiler warnings threw up some "shadow" variables + and a few more missing casts. + +4. If PCRE was complied with UTF-8 support, but called without the PCRE_UTF8 + option, a class that contained a single character with a value between 128 + and 255 (e.g. /[\xFF]/) caused PCRE to crash. + +5. If PCRE was compiled with UTF-8 support, but called without the PCRE_UTF8 + option, a class that contained several characters, but with at least one + whose value was between 128 and 255 caused PCRE to crash. + + +Version 4.1 12-Mar-03 +--------------------- + +1. Compiling with gcc -pedantic found a couple of places where casts were +needed, and a string in dftables.c that was longer than standard compilers are +required to support. + +2. Compiling with Sun's compiler found a few more places where the code could +be tidied up in order to avoid warnings. + +3. The variables for cross-compiling were called HOST_CC and HOST_CFLAGS; the +first of these names is deprecated in the latest Autoconf in favour of the name +CC_FOR_BUILD, because "host" is typically used to mean the system on which the +compiled code will be run. I can't find a reference for HOST_CFLAGS, but by +analogy I have changed it to CFLAGS_FOR_BUILD. + +4. Added -no-undefined to the linking command in the Makefile, because this is +apparently helpful for Windows. To make it work, also added "-L. -lpcre" to the +linking step for the pcreposix library. + +5. PCRE was failing to diagnose the case of two named groups with the same +name. + +6. A problem with one of PCRE's optimizations was discovered. PCRE remembers a +literal character that is needed in the subject for a match, and scans along to +ensure that it is present before embarking on the full matching process. This +saves time in cases of nested unlimited repeats that are never going to match. +Problem: the scan can take a lot of time if the subject is very long (e.g. +megabytes), thus penalizing straightforward matches. It is now done only if the +amount of subject to be scanned is less than 1000 bytes. + +7. A lesser problem with the same optimization is that it was recording the +first character of an anchored pattern as "needed", thus provoking a search +right along the subject, even when the first match of the pattern was going to +fail. The "needed" character is now not set for anchored patterns, unless it +follows something in the pattern that is of non-fixed length. Thus, it still +fulfils its original purpose of finding quick non-matches in cases of nested +unlimited repeats, but isn't used for simple anchored patterns such as /^abc/. + + +Version 4.0 17-Feb-03 +--------------------- + +1. If a comment in an extended regex that started immediately after a meta-item +extended to the end of string, PCRE compiled incorrect data. This could lead to +all kinds of weird effects. Example: /#/ was bad; /()#/ was bad; /a#/ was not. + +2. Moved to autoconf 2.53 and libtool 1.4.2. + +3. Perl 5.8 no longer needs "use utf8" for doing UTF-8 things. Consequently, +the special perltest8 script is no longer needed - all the tests can be run +from a single perltest script. + +4. From 5.004, Perl has not included the VT character (0x0b) in the set defined +by \s. It has now been removed in PCRE. This means it isn't recognized as +whitespace in /x regexes too, which is the same as Perl. Note that the POSIX +class [:space:] *does* include VT, thereby creating a mess. + +5. Added the class [:blank:] (a GNU extension from Perl 5.8) to match only +space and tab. + +6. Perl 5.005 was a long time ago. It's time to amalgamate the tests that use +its new features into the main test script, reducing the number of scripts. + +7. Perl 5.8 has changed the meaning of patterns like /a(?i)b/. Earlier versions +were backward compatible, and made the (?i) apply to the whole pattern, as if +/i were given. Now it behaves more logically, and applies the option setting +only to what follows. PCRE has been changed to follow suit. However, if it +finds options settings right at the start of the pattern, it extracts them into +the global options, as before. Thus, they show up in the info data. + +8. Added support for the \Q...\E escape sequence. Characters in between are +treated as literals. This is slightly different from Perl in that $ and @ are +also handled as literals inside the quotes. In Perl, they will cause variable +interpolation. Note the following examples: + + Pattern PCRE matches Perl matches + + \Qabc$xyz\E abc$xyz abc followed by the contents of $xyz + \Qabc\$xyz\E abc\$xyz abc\$xyz + \Qabc\E\$\Qxyz\E abc$xyz abc$xyz + +For compatibility with Perl, \Q...\E sequences are recognized inside character +classes as well as outside them. + +9. Re-organized 3 code statements in pcretest to avoid "overflow in +floating-point constant arithmetic" warnings from a Microsoft compiler. Added a +(size_t) cast to one statement in pcretest and one in pcreposix to avoid +signed/unsigned warnings. + +10. SunOS4 doesn't have strtoul(). This was used only for unpicking the -o +option for pcretest, so I've replaced it by a simple function that does just +that job. + +11. pcregrep was ending with code 0 instead of 2 for the commands "pcregrep" or +"pcregrep -". + +12. Added "possessive quantifiers" ?+, *+, ++, and {,}+ which come from Sun's +Java package. This provides some syntactic sugar for simple cases of what my +documentation calls "once-only subpatterns". A pattern such as x*+ is the same +as (?>x*). In other words, if what is inside (?>...) is just a single repeated +item, you can use this simplified notation. Note that only makes sense with +greedy quantifiers. Consequently, the use of the possessive quantifier forces +greediness, whatever the setting of the PCRE_UNGREEDY option. + +13. A change of greediness default within a pattern was not taking effect at +the current level for patterns like /(b+(?U)a+)/. It did apply to parenthesized +subpatterns that followed. Patterns like /b+(?U)a+/ worked because the option +was abstracted outside. + +14. PCRE now supports the \G assertion. It is true when the current matching +position is at the start point of the match. This differs from \A when the +starting offset is non-zero. Used with the /g option of pcretest (or similar +code), it works in the same way as it does for Perl's /g option. If all +alternatives of a regex begin with \G, the expression is anchored to the start +match position, and the "anchored" flag is set in the compiled expression. + +15. Some bugs concerning the handling of certain option changes within patterns +have been fixed. These applied to options other than (?ims). For example, +"a(?x: b c )d" did not match "XabcdY" but did match "Xa b c dY". It should have +been the other way round. Some of this was related to change 7 above. + +16. PCRE now gives errors for /[.x.]/ and /[=x=]/ as unsupported POSIX +features, as Perl does. Previously, PCRE gave the warnings only for /[[.x.]]/ +and /[[=x=]]/. PCRE now also gives an error for /[:name:]/ because it supports +POSIX classes only within a class (e.g. /[[:alpha:]]/). + +17. Added support for Perl's \C escape. This matches one byte, even in UTF8 +mode. Unlike ".", it always matches newline, whatever the setting of +PCRE_DOTALL. However, PCRE does not permit \C to appear in lookbehind +assertions. Perl allows it, but it doesn't (in general) work because it can't +calculate the length of the lookbehind. At least, that's the case for Perl +5.8.0 - I've been told they are going to document that it doesn't work in +future. + +18. Added an error diagnosis for escapes that PCRE does not support: these are +\L, \l, \N, \P, \p, \U, \u, and \X. + +19. Although correctly diagnosing a missing ']' in a character class, PCRE was +reading past the end of the pattern in cases such as /[abcd/. + +20. PCRE was getting more memory than necessary for patterns with classes that +contained both POSIX named classes and other characters, e.g. /[[:space:]abc/. + +21. Added some code, conditional on #ifdef VPCOMPAT, to make life easier for +compiling PCRE for use with Virtual Pascal. + +22. Small fix to the Makefile to make it work properly if the build is done +outside the source tree. + +23. Added a new extension: a condition to go with recursion. If a conditional +subpattern starts with (?(R) the "true" branch is used if recursion has +happened, whereas the "false" branch is used only at the top level. + +24. When there was a very long string of literal characters (over 255 bytes +without UTF support, over 250 bytes with UTF support), the computation of how +much memory was required could be incorrect, leading to segfaults or other +strange effects. + +25. PCRE was incorrectly assuming anchoring (either to start of subject or to +start of line for a non-DOTALL pattern) when a pattern started with (.*) and +there was a subsequent back reference to those brackets. This meant that, for +example, /(.*)\d+\1/ failed to match "abc123bc". Unfortunately, it isn't +possible to check for precisely this case. All we can do is abandon the +optimization if .* occurs inside capturing brackets when there are any back +references whatsoever. (See below for a better fix that came later.) + +26. The handling of the optimization for finding the first character of a +non-anchored pattern, and for finding a character that is required later in the +match were failing in some cases. This didn't break the matching; it just +failed to optimize when it could. The way this is done has been re-implemented. + +27. Fixed typo in error message for invalid (?R item (it said "(?p"). + +28. Added a new feature that provides some of the functionality that Perl +provides with (?{...}). The facility is termed a "callout". The way it is done +in PCRE is for the caller to provide an optional function, by setting +pcre_callout to its entry point. Like pcre_malloc and pcre_free, this is a +global variable. By default it is unset, which disables all calling out. To get +the function called, the regex must include (?C) at appropriate points. This +is, in fact, equivalent to (?C0), and any number <= 255 may be given with (?C). +This provides a means of identifying different callout points. When PCRE +reaches such a point in the regex, if pcre_callout has been set, the external +function is called. It is provided with data in a structure called +pcre_callout_block, which is defined in pcre.h. If the function returns 0, +matching continues; if it returns a non-zero value, the match at the current +point fails. However, backtracking will occur if possible. [This was changed +later and other features added - see item 49 below.] + +29. pcretest is upgraded to test the callout functionality. It provides a +callout function that displays information. By default, it shows the start of +the match and the current position in the text. There are some new data escapes +to vary what happens: + + \C+ in addition, show current contents of captured substrings + \C- do not supply a callout function + \C!n return 1 when callout number n is reached + \C!n!m return 1 when callout number n is reached for the mth time + +30. If pcregrep was called with the -l option and just a single file name, it +output "" if a match was found, instead of the file name. + +31. Improve the efficiency of the POSIX API to PCRE. If the number of capturing +slots is less than POSIX_MALLOC_THRESHOLD, use a block on the stack to pass to +pcre_exec(). This saves a malloc/free per call. The default value of +POSIX_MALLOC_THRESHOLD is 10; it can be changed by --with-posix-malloc-threshold +when configuring. + +32. The default maximum size of a compiled pattern is 64K. There have been a +few cases of people hitting this limit. The code now uses macros to handle the +storing of links as offsets within the compiled pattern. It defaults to 2-byte +links, but this can be changed to 3 or 4 bytes by --with-link-size when +configuring. Tests 2 and 5 work only with 2-byte links because they output +debugging information about compiled patterns. + +33. Internal code re-arrangements: + +(a) Moved the debugging function for printing out a compiled regex into + its own source file (printint.c) and used #include to pull it into + pcretest.c and, when DEBUG is defined, into pcre.c, instead of having two + separate copies. + +(b) Defined the list of op-code names for debugging as a macro in + internal.h so that it is next to the definition of the opcodes. + +(c) Defined a table of op-code lengths for simpler skipping along compiled + code. This is again a macro in internal.h so that it is next to the + definition of the opcodes. + +34. Added support for recursive calls to individual subpatterns, along the +lines of Robin Houston's patch (but implemented somewhat differently). + +35. Further mods to the Makefile to help Win32. Also, added code to pcregrep to +allow it to read and process whole directories in Win32. This code was +contributed by Lionel Fourquaux; it has not been tested by me. + +36. Added support for named subpatterns. The Python syntax (?P...) is +used to name a group. Names consist of alphanumerics and underscores, and must +be unique. Back references use the syntax (?P=name) and recursive calls use +(?P>name) which is a PCRE extension to the Python extension. Groups still have +numbers. The function pcre_fullinfo() can be used after compilation to extract +a name/number map. There are three relevant calls: + + PCRE_INFO_NAMEENTRYSIZE yields the size of each entry in the map + PCRE_INFO_NAMECOUNT yields the number of entries + PCRE_INFO_NAMETABLE yields a pointer to the map. + +The map is a vector of fixed-size entries. The size of each entry depends on +the length of the longest name used. The first two bytes of each entry are the +group number, most significant byte first. There follows the corresponding +name, zero terminated. The names are in alphabetical order. + +37. Make the maximum literal string in the compiled code 250 for the non-UTF-8 +case instead of 255. Making it the same both with and without UTF-8 support +means that the same test output works with both. + +38. There was a case of malloc(0) in the POSIX testing code in pcretest. Avoid +calling malloc() with a zero argument. + +39. Change 25 above had to resort to a heavy-handed test for the .* anchoring +optimization. I've improved things by keeping a bitmap of backreferences with +numbers 1-31 so that if .* occurs inside capturing brackets that are not in +fact referenced, the optimization can be applied. It is unlikely that a +relevant occurrence of .* (i.e. one which might indicate anchoring or forcing +the match to follow \n) will appear inside brackets with a number greater than +31, but if it does, any back reference > 31 suppresses the optimization. + +40. Added a new compile-time option PCRE_NO_AUTO_CAPTURE. This has the effect +of disabling numbered capturing parentheses. Any opening parenthesis that is +not followed by ? behaves as if it were followed by ?: but named parentheses +can still be used for capturing (and they will acquire numbers in the usual +way). + +41. Redesigned the return codes from the match() function into yes/no/error so +that errors can be passed back from deep inside the nested calls. A malloc +failure while inside a recursive subpattern call now causes the +PCRE_ERROR_NOMEMORY return instead of quietly going wrong. + +42. It is now possible to set a limit on the number of times the match() +function is called in a call to pcre_exec(). This facility makes it possible to +limit the amount of recursion and backtracking, though not in a directly +obvious way, because the match() function is used in a number of different +circumstances. The count starts from zero for each position in the subject +string (for non-anchored patterns). The default limit is, for compatibility, a +large number, namely 10 000 000. You can change this in two ways: + +(a) When configuring PCRE before making, you can use --with-match-limit=n + to set a default value for the compiled library. + +(b) For each call to pcre_exec(), you can pass a pcre_extra block in which + a different value is set. See 45 below. + +If the limit is exceeded, pcre_exec() returns PCRE_ERROR_MATCHLIMIT. + +43. Added a new function pcre_config(int, void *) to enable run-time extraction +of things that can be changed at compile time. The first argument specifies +what is wanted and the second points to where the information is to be placed. +The current list of available information is: + + PCRE_CONFIG_UTF8 + +The output is an integer that is set to one if UTF-8 support is available; +otherwise it is set to zero. + + PCRE_CONFIG_NEWLINE + +The output is an integer that it set to the value of the code that is used for +newline. It is either LF (10) or CR (13). + + PCRE_CONFIG_LINK_SIZE + +The output is an integer that contains the number of bytes used for internal +linkage in compiled expressions. The value is 2, 3, or 4. See item 32 above. + + PCRE_CONFIG_POSIX_MALLOC_THRESHOLD + +The output is an integer that contains the threshold above which the POSIX +interface uses malloc() for output vectors. See item 31 above. + + PCRE_CONFIG_MATCH_LIMIT + +The output is an unsigned integer that contains the default limit of the number +of match() calls in a pcre_exec() execution. See 42 above. + +44. pcretest has been upgraded by the addition of the -C option. This causes it +to extract all the available output from the new pcre_config() function, and to +output it. The program then exits immediately. + +45. A need has arisen to pass over additional data with calls to pcre_exec() in +order to support additional features. One way would have been to define +pcre_exec2() (for example) with extra arguments, but this would not have been +extensible, and would also have required all calls to the original function to +be mapped to the new one. Instead, I have chosen to extend the mechanism that +is used for passing in "extra" data from pcre_study(). + +The pcre_extra structure is now exposed and defined in pcre.h. It currently +contains the following fields: + + flags a bitmap indicating which of the following fields are set + study_data opaque data from pcre_study() + match_limit a way of specifying a limit on match() calls for a specific + call to pcre_exec() + callout_data data for callouts (see 49 below) + +The flag bits are also defined in pcre.h, and are + + PCRE_EXTRA_STUDY_DATA + PCRE_EXTRA_MATCH_LIMIT + PCRE_EXTRA_CALLOUT_DATA + +The pcre_study() function now returns one of these new pcre_extra blocks, with +the actual study data pointed to by the study_data field, and the +PCRE_EXTRA_STUDY_DATA flag set. This can be passed directly to pcre_exec() as +before. That is, this change is entirely upwards-compatible and requires no +change to existing code. + +If you want to pass in additional data to pcre_exec(), you can either place it +in a pcre_extra block provided by pcre_study(), or create your own pcre_extra +block. + +46. pcretest has been extended to test the PCRE_EXTRA_MATCH_LIMIT feature. If a +data string contains the escape sequence \M, pcretest calls pcre_exec() several +times with different match limits, until it finds the minimum value needed for +pcre_exec() to complete. The value is then output. This can be instructive; for +most simple matches the number is quite small, but for pathological cases it +gets very large very quickly. + +47. There's a new option for pcre_fullinfo() called PCRE_INFO_STUDYSIZE. It +returns the size of the data block pointed to by the study_data field in a +pcre_extra block, that is, the value that was passed as the argument to +pcre_malloc() when PCRE was getting memory in which to place the information +created by pcre_study(). The fourth argument should point to a size_t variable. +pcretest has been extended so that this information is shown after a successful +pcre_study() call when information about the compiled regex is being displayed. + +48. Cosmetic change to Makefile: there's no need to have / after $(DESTDIR) +because what follows is always an absolute path. (Later: it turns out that this +is more than cosmetic for MinGW, because it doesn't like empty path +components.) + +49. Some changes have been made to the callout feature (see 28 above): + +(i) A callout function now has three choices for what it returns: + + 0 => success, carry on matching + > 0 => failure at this point, but backtrack if possible + < 0 => serious error, return this value from pcre_exec() + + Negative values should normally be chosen from the set of PCRE_ERROR_xxx + values. In particular, returning PCRE_ERROR_NOMATCH forces a standard + "match failed" error. The error number PCRE_ERROR_CALLOUT is reserved for + use by callout functions. It will never be used by PCRE itself. + +(ii) The pcre_extra structure (see 45 above) has a void * field called + callout_data, with corresponding flag bit PCRE_EXTRA_CALLOUT_DATA. The + pcre_callout_block structure has a field of the same name. The contents of + the field passed in the pcre_extra structure are passed to the callout + function in the corresponding field in the callout block. This makes it + easier to use the same callout-containing regex from multiple threads. For + testing, the pcretest program has a new data escape + + \C*n pass the number n (may be negative) as callout_data + + If the callout function in pcretest receives a non-zero value as + callout_data, it returns that value. + +50. Makefile wasn't handling CFLAGS properly when compiling dftables. Also, +there were some redundant $(CFLAGS) in commands that are now specified as +$(LINK), which already includes $(CFLAGS). + +51. Extensions to UTF-8 support are listed below. These all apply when (a) PCRE +has been compiled with UTF-8 support *and* pcre_compile() has been compiled +with the PCRE_UTF8 flag. Patterns that are compiled without that flag assume +one-byte characters throughout. Note that case-insensitive matching applies +only to characters whose values are less than 256. PCRE doesn't support the +notion of cases for higher-valued characters. + +(i) A character class whose characters are all within 0-255 is handled as + a bit map, and the map is inverted for negative classes. Previously, a + character > 255 always failed to match such a class; however it should + match if the class was a negative one (e.g. [^ab]). This has been fixed. + +(ii) A negated character class with a single character < 255 is coded as + "not this character" (OP_NOT). This wasn't working properly when the test + character was multibyte, either singly or repeated. + +(iii) Repeats of multibyte characters are now handled correctly in UTF-8 + mode, for example: \x{100}{2,3}. + +(iv) The character escapes \b, \B, \d, \D, \s, \S, \w, and \W (either + singly or repeated) now correctly test multibyte characters. However, + PCRE doesn't recognize any characters with values greater than 255 as + digits, spaces, or word characters. Such characters always match \D, \S, + and \W, and never match \d, \s, or \w. + +(v) Classes may now contain characters and character ranges with values + greater than 255. For example: [ab\x{100}-\x{400}]. + +(vi) pcregrep now has a --utf-8 option (synonym -u) which makes it call + PCRE in UTF-8 mode. + +52. The info request value PCRE_INFO_FIRSTCHAR has been renamed +PCRE_INFO_FIRSTBYTE because it is a byte value. However, the old name is +retained for backwards compatibility. (Note that LASTLITERAL is also a byte +value.) + +53. The single man page has become too large. I have therefore split it up into +a number of separate man pages. These also give rise to individual HTML pages; +these are now put in a separate directory, and there is an index.html page that +lists them all. Some hyperlinking between the pages has been installed. + +54. Added convenience functions for handling named capturing parentheses. + +55. Unknown escapes inside character classes (e.g. [\M]) and escapes that +aren't interpreted therein (e.g. [\C]) are literals in Perl. This is now also +true in PCRE, except when the PCRE_EXTENDED option is set, in which case they +are faulted. + +56. Introduced HOST_CC and HOST_CFLAGS which can be set in the environment when +calling configure. These values are used when compiling the dftables.c program +which is run to generate the source of the default character tables. They +default to the values of CC and CFLAGS. If you are cross-compiling PCRE, +you will need to set these values. + +57. Updated the building process for Windows DLL, as provided by Fred Cox. + + +Version 3.9 02-Jan-02 +--------------------- + +1. A bit of extraneous text had somehow crept into the pcregrep documentation. + +2. If --disable-static was given, the building process failed when trying to +build pcretest and pcregrep. (For some reason it was using libtool to compile +them, which is not right, as they aren't part of the library.) + + +Version 3.8 18-Dec-01 +--------------------- + +1. The experimental UTF-8 code was completely screwed up. It was packing the +bytes in the wrong order. How dumb can you get? + + +Version 3.7 29-Oct-01 +--------------------- + +1. In updating pcretest to check change 1 of version 3.6, I screwed up. +This caused pcretest, when used on the test data, to segfault. Unfortunately, +this didn't happen under Solaris 8, where I normally test things. + +2. The Makefile had to be changed to make it work on BSD systems, where 'make' +doesn't seem to recognize that ./xxx and xxx are the same file. (This entry +isn't in ChangeLog distributed with 3.7 because I forgot when I hastily made +this fix an hour or so after the initial 3.7 release.) + + +Version 3.6 23-Oct-01 +--------------------- + +1. Crashed with /(sens|respons)e and \1ibility/ and "sense and sensibility" if +offsets passed as NULL with zero offset count. + +2. The config.guess and config.sub files had not been updated when I moved to +the latest autoconf. + + +Version 3.5 15-Aug-01 +--------------------- + +1. Added some missing #if !defined NOPOSIX conditionals in pcretest.c that +had been forgotten. + +2. By using declared but undefined structures, we can avoid using "void" +definitions in pcre.h while keeping the internal definitions of the structures +private. + +3. The distribution is now built using autoconf 2.50 and libtool 1.4. From a +user point of view, this means that both static and shared libraries are built +by default, but this can be individually controlled. More of the work of +handling this static/shared cases is now inside libtool instead of PCRE's make +file. + +4. The pcretest utility is now installed along with pcregrep because it is +useful for users (to test regexs) and by doing this, it automatically gets +relinked by libtool. The documentation has been turned into a man page, so +there are now .1, .txt, and .html versions in /doc. + +5. Upgrades to pcregrep: + (i) Added long-form option names like gnu grep. + (ii) Added --help to list all options with an explanatory phrase. + (iii) Added -r, --recursive to recurse into sub-directories. + (iv) Added -f, --file to read patterns from a file. + +6. pcre_exec() was referring to its "code" argument before testing that +argument for NULL (and giving an error if it was NULL). + +7. Upgraded Makefile.in to allow for compiling in a different directory from +the source directory. + +8. Tiny buglet in pcretest: when pcre_fullinfo() was called to retrieve the +options bits, the pointer it was passed was to an int instead of to an unsigned +long int. This mattered only on 64-bit systems. + +9. Fixed typo (3.4/1) in pcre.h again. Sigh. I had changed pcre.h (which is +generated) instead of pcre.in, which it its source. Also made the same change +in several of the .c files. + +10. A new release of gcc defines printf() as a macro, which broke pcretest +because it had an ifdef in the middle of a string argument for printf(). Fixed +by using separate calls to printf(). + +11. Added --enable-newline-is-cr and --enable-newline-is-lf to the configure +script, to force use of CR or LF instead of \n in the source. On non-Unix +systems, the value can be set in config.h. + +12. The limit of 200 on non-capturing parentheses is a _nesting_ limit, not an +absolute limit. Changed the text of the error message to make this clear, and +likewise updated the man page. + +13. The limit of 99 on the number of capturing subpatterns has been removed. +The new limit is 65535, which I hope will not be a "real" limit. + + +Version 3.4 22-Aug-00 +--------------------- + +1. Fixed typo in pcre.h: unsigned const char * changed to const unsigned char *. + +2. Diagnose condition (?(0) as an error instead of crashing on matching. + + +Version 3.3 01-Aug-00 +--------------------- + +1. If an octal character was given, but the value was greater than \377, it +was not getting masked to the least significant bits, as documented. This could +lead to crashes in some systems. + +2. Perl 5.6 (if not earlier versions) accepts classes like [a-\d] and treats +the hyphen as a literal. PCRE used to give an error; it now behaves like Perl. + +3. Added the functions pcre_free_substring() and pcre_free_substring_list(). +These just pass their arguments on to (pcre_free)(), but they are provided +because some uses of PCRE bind it to non-C systems that can call its functions, +but cannot call free() or pcre_free() directly. + +4. Add "make test" as a synonym for "make check". Corrected some comments in +the Makefile. + +5. Add $(DESTDIR)/ in front of all the paths in the "install" target in the +Makefile. + +6. Changed the name of pgrep to pcregrep, because Solaris has introduced a +command called pgrep for grepping around the active processes. + +7. Added the beginnings of support for UTF-8 character strings. + +8. Arranged for the Makefile to pass over the settings of CC, CFLAGS, and +RANLIB to ./ltconfig so that they are used by libtool. I think these are all +the relevant ones. (AR is not passed because ./ltconfig does its own figuring +out for the ar command.) + + +Version 3.2 12-May-00 +--------------------- + +This is purely a bug fixing release. + +1. If the pattern /((Z)+|A)*/ was matched agained ZABCDEFG it matched Z instead +of ZA. This was just one example of several cases that could provoke this bug, +which was introduced by change 9 of version 2.00. The code for breaking +infinite loops after an iteration that matches an empty string was't working +correctly. + +2. The pcretest program was not imitating Perl correctly for the pattern /a*/g +when matched against abbab (for example). After matching an empty string, it +wasn't forcing anchoring when setting PCRE_NOTEMPTY for the next attempt; this +caused it to match further down the string than it should. + +3. The code contained an inclusion of sys/types.h. It isn't clear why this +was there because it doesn't seem to be needed, and it causes trouble on some +systems, as it is not a Standard C header. It has been removed. + +4. Made 4 silly changes to the source to avoid stupid compiler warnings that +were reported on the Macintosh. The changes were from + + while ((c = *(++ptr)) != 0 && c != '\n'); +to + while ((c = *(++ptr)) != 0 && c != '\n') ; + +Totally extraordinary, but if that's what it takes... + +5. PCRE is being used in one environment where neither memmove() nor bcopy() is +available. Added HAVE_BCOPY and an autoconf test for it; if neither +HAVE_MEMMOVE nor HAVE_BCOPY is set, use a built-in emulation function which +assumes the way PCRE uses memmove() (always moving upwards). + +6. PCRE is being used in one environment where strchr() is not available. There +was only one use in pcre.c, and writing it out to avoid strchr() probably gives +faster code anyway. + + +Version 3.1 09-Feb-00 +--------------------- + +The only change in this release is the fixing of some bugs in Makefile.in for +the "install" target: + +(1) It was failing to install pcreposix.h. + +(2) It was overwriting the pcre.3 man page with the pcreposix.3 man page. + + +Version 3.0 01-Feb-00 +--------------------- + +1. Add support for the /+ modifier to perltest (to output $` like it does in +pcretest). + +2. Add support for the /g modifier to perltest. + +3. Fix pcretest so that it behaves even more like Perl for /g when the pattern +matches null strings. + +4. Fix perltest so that it doesn't do unwanted things when fed an empty +pattern. Perl treats empty patterns specially - it reuses the most recent +pattern, which is not what we want. Replace // by /(?#)/ in order to avoid this +effect. + +5. The POSIX interface was broken in that it was just handing over the POSIX +captured string vector to pcre_exec(), but (since release 2.00) PCRE has +required a bigger vector, with some working space on the end. This means that +the POSIX wrapper now has to get and free some memory, and copy the results. + +6. Added some simple autoconf support, placing the test data and the +documentation in separate directories, re-organizing some of the +information files, and making it build pcre-config (a GNU standard). Also added +libtool support for building PCRE as a shared library, which is now the +default. + +7. Got rid of the leading zero in the definition of PCRE_MINOR because 08 and +09 are not valid octal constants. Single digits will be used for minor values +less than 10. + +8. Defined REG_EXTENDED and REG_NOSUB as zero in the POSIX header, so that +existing programs that set these in the POSIX interface can use PCRE without +modification. + +9. Added a new function, pcre_fullinfo() with an extensible interface. It can +return all that pcre_info() returns, plus additional data. The pcre_info() +function is retained for compatibility, but is considered to be obsolete. + +10. Added experimental recursion feature (?R) to handle one common case that +Perl 5.6 will be able to do with (?p{...}). + +11. Added support for POSIX character classes like [:alpha:], which Perl is +adopting. + + +Version 2.08 31-Aug-99 +---------------------- + +1. When startoffset was not zero and the pattern began with ".*", PCRE was not +trying to match at the startoffset position, but instead was moving forward to +the next newline as if a previous match had failed. + +2. pcretest was not making use of PCRE_NOTEMPTY when repeating for /g and /G, +and could get into a loop if a null string was matched other than at the start +of the subject. + +3. Added definitions of PCRE_MAJOR and PCRE_MINOR to pcre.h so the version can +be distinguished at compile time, and for completeness also added PCRE_DATE. + +5. Added Paul Sokolovsky's minor changes to make it easy to compile a Win32 DLL +in GnuWin32 environments. + + +Version 2.07 29-Jul-99 +---------------------- + +1. The documentation is now supplied in plain text form and HTML as well as in +the form of man page sources. + +2. C++ compilers don't like assigning (void *) values to other pointer types. +In particular this affects malloc(). Although there is no problem in Standard +C, I've put in casts to keep C++ compilers happy. + +3. Typo on pcretest.c; a cast of (unsigned char *) in the POSIX regexec() call +should be (const char *). + +4. If NOPOSIX is defined, pcretest.c compiles without POSIX support. This may +be useful for non-Unix systems who don't want to bother with the POSIX stuff. +However, I haven't made this a standard facility. The documentation doesn't +mention it, and the Makefile doesn't support it. + +5. The Makefile now contains an "install" target, with editable destinations at +the top of the file. The pcretest program is not installed. + +6. pgrep -V now gives the PCRE version number and date. + +7. Fixed bug: a zero repetition after a literal string (e.g. /abcde{0}/) was +causing the entire string to be ignored, instead of just the last character. + +8. If a pattern like /"([^\\"]+|\\.)*"/ is applied in the normal way to a +non-matching string, it can take a very, very long time, even for strings of +quite modest length, because of the nested recursion. PCRE now does better in +some of these cases. It does this by remembering the last required literal +character in the pattern, and pre-searching the subject to ensure it is present +before running the real match. In other words, it applies a heuristic to detect +some types of certain failure quickly, and in the above example, if presented +with a string that has no trailing " it gives "no match" very quickly. + +9. A new runtime option PCRE_NOTEMPTY causes null string matches to be ignored; +other alternatives are tried instead. + + +Version 2.06 09-Jun-99 +---------------------- + +1. Change pcretest's output for amount of store used to show just the code +space, because the remainder (the data block) varies in size between 32-bit and +64-bit systems. + +2. Added an extra argument to pcre_exec() to supply an offset in the subject to +start matching at. This allows lookbehinds to work when searching for multiple +occurrences in a string. + +3. Added additional options to pcretest for testing multiple occurrences: + + /+ outputs the rest of the string that follows a match + /g loops for multiple occurrences, using the new startoffset argument + /G loops for multiple occurrences by passing an incremented pointer + +4. PCRE wasn't doing the "first character" optimization for patterns starting +with \b or \B, though it was doing it for other lookbehind assertions. That is, +it wasn't noticing that a match for a pattern such as /\bxyz/ has to start with +the letter 'x'. On long subject strings, this gives a significant speed-up. + + +Version 2.05 21-Apr-99 +---------------------- + +1. Changed the type of magic_number from int to long int so that it works +properly on 16-bit systems. + +2. Fixed a bug which caused patterns starting with .* not to work correctly +when the subject string contained newline characters. PCRE was assuming +anchoring for such patterns in all cases, which is not correct because .* will +not pass a newline unless PCRE_DOTALL is set. It now assumes anchoring only if +DOTALL is set at top level; otherwise it knows that patterns starting with .* +must be retried after every newline in the subject. + + +Version 2.04 18-Feb-99 +---------------------- + +1. For parenthesized subpatterns with repeats whose minimum was zero, the +computation of the store needed to hold the pattern was incorrect (too large). +If such patterns were nested a few deep, this could multiply and become a real +problem. + +2. Added /M option to pcretest to show the memory requirement of a specific +pattern. Made -m a synonym of -s (which does this globally) for compatibility. + +3. Subpatterns of the form (regex){n,m} (i.e. limited maximum) were being +compiled in such a way that the backtracking after subsequent failure was +pessimal. Something like (a){0,3} was compiled as (a)?(a)?(a)? instead of +((a)((a)(a)?)?)? with disastrous performance if the maximum was of any size. + + +Version 2.03 02-Feb-99 +---------------------- + +1. Fixed typo and small mistake in man page. + +2. Added 4th condition (GPL supersedes if conflict) and created separate +LICENCE file containing the conditions. + +3. Updated pcretest so that patterns such as /abc\/def/ work like they do in +Perl, that is the internal \ allows the delimiter to be included in the +pattern. Locked out the use of \ as a delimiter. If \ immediately follows +the final delimiter, add \ to the end of the pattern (to test the error). + +4. Added the convenience functions for extracting substrings after a successful +match. Updated pcretest to make it able to test these functions. + + +Version 2.02 14-Jan-99 +---------------------- + +1. Initialized the working variables associated with each extraction so that +their saving and restoring doesn't refer to uninitialized store. + +2. Put dummy code into study.c in order to trick the optimizer of the IBM C +compiler for OS/2 into generating correct code. Apparently IBM isn't going to +fix the problem. + +3. Pcretest: the timing code wasn't using LOOPREPEAT for timing execution +calls, and wasn't printing the correct value for compiling calls. Increased the +default value of LOOPREPEAT, and the number of significant figures in the +times. + +4. Changed "/bin/rm" in the Makefile to "-rm" so it works on Windows NT. + +5. Renamed "deftables" as "dftables" to get it down to 8 characters, to avoid +a building problem on Windows NT with a FAT file system. + + +Version 2.01 21-Oct-98 +---------------------- + +1. Changed the API for pcre_compile() to allow for the provision of a pointer +to character tables built by pcre_maketables() in the current locale. If NULL +is passed, the default tables are used. + + +Version 2.00 24-Sep-98 +---------------------- + +1. Since the (>?) facility is in Perl 5.005, don't require PCRE_EXTRA to enable +it any more. + +2. Allow quantification of (?>) groups, and make it work correctly. + +3. The first character computation wasn't working for (?>) groups. + +4. Correct the implementation of \Z (it is permitted to match on the \n at the +end of the subject) and add 5.005's \z, which really does match only at the +very end of the subject. + +5. Remove the \X "cut" facility; Perl doesn't have it, and (?> is neater. + +6. Remove the ability to specify CASELESS, MULTILINE, DOTALL, and +DOLLAR_END_ONLY at runtime, to make it possible to implement the Perl 5.005 +localized options. All options to pcre_study() were also removed. + +7. Add other new features from 5.005: + + $(?<= positive lookbehind + $(?a*))*/ (a PCRE_EXTRA facility). + + +Version 1.00 18-Nov-97 +---------------------- + +1. Added compile-time macros to support systems such as SunOS4 which don't have +memmove() or strerror() but have other things that can be used instead. + +2. Arranged that "make clean" removes the executables. + + +Version 0.99 27-Oct-97 +---------------------- + +1. Fixed bug in code for optimizing classes with only one character. It was +initializing a 32-byte map regardless, which could cause it to run off the end +of the memory it had got. + +2. Added, conditional on PCRE_EXTRA, the proposed (?>REGEX) construction. + + +Version 0.98 22-Oct-97 +---------------------- + +1. Fixed bug in code for handling temporary memory usage when there are more +back references than supplied space in the ovector. This could cause segfaults. + + +Version 0.97 21-Oct-97 +---------------------- + +1. Added the \X "cut" facility, conditional on PCRE_EXTRA. + +2. Optimized negated single characters not to use a bit map. + +3. Brought error texts together as macro definitions; clarified some of them; +fixed one that was wrong - it said "range out of order" when it meant "invalid +escape sequence". + +4. Changed some char * arguments to const char *. + +5. Added PCRE_NOTBOL and PCRE_NOTEOL (from POSIX). + +6. Added the POSIX-style API wrapper in pcreposix.a and testing facilities in +pcretest. + + +Version 0.96 16-Oct-97 +---------------------- + +1. Added a simple "pgrep" utility to the distribution. + +2. Fixed an incompatibility with Perl: "{" is now treated as a normal character +unless it appears in one of the precise forms "{ddd}", "{ddd,}", or "{ddd,ddd}" +where "ddd" means "one or more decimal digits". + +3. Fixed serious bug. If a pattern had a back reference, but the call to +pcre_exec() didn't supply a large enough ovector to record the related +identifying subpattern, the match always failed. PCRE now remembers the number +of the largest back reference, and gets some temporary memory in which to save +the offsets during matching if necessary, in order to ensure that +backreferences always work. + +4. Increased the compatibility with Perl in a number of ways: + + (a) . no longer matches \n by default; an option PCRE_DOTALL is provided + to request this handling. The option can be set at compile or exec time. + + (b) $ matches before a terminating newline by default; an option + PCRE_DOLLAR_ENDONLY is provided to override this (but not in multiline + mode). The option can be set at compile or exec time. + + (c) The handling of \ followed by a digit other than 0 is now supposed to be + the same as Perl's. If the decimal number it represents is less than 10 + or there aren't that many previous left capturing parentheses, an octal + escape is read. Inside a character class, it's always an octal escape, + even if it is a single digit. + + (d) An escaped but undefined alphabetic character is taken as a literal, + unless PCRE_EXTRA is set. Currently this just reserves the remaining + escapes. + + (e) {0} is now permitted. (The previous item is removed from the compiled + pattern). + +5. Changed all the names of code files so that the basic parts are no longer +than 10 characters, and abolished the teeny "globals.c" file. + +6. Changed the handling of character classes; they are now done with a 32-byte +bit map always. + +7. Added the -d and /D options to pcretest to make it possible to look at the +internals of compilation without having to recompile pcre. + + +Version 0.95 23-Sep-97 +---------------------- + +1. Fixed bug in pre-pass concerning escaped "normal" characters such as \x5c or +\x20 at the start of a run of normal characters. These were being treated as +real characters, instead of the source characters being re-checked. + + +Version 0.94 18-Sep-97 +---------------------- + +1. The functions are now thread-safe, with the caveat that the global variables +containing pointers to malloc() and free() or alternative functions are the +same for all threads. + +2. Get pcre_study() to generate a bitmap of initial characters for non- +anchored patterns when this is possible, and use it if passed to pcre_exec(). + + +Version 0.93 15-Sep-97 +---------------------- + +1. /(b)|(:+)/ was computing an incorrect first character. + +2. Add pcre_study() to the API and the passing of pcre_extra to pcre_exec(), +but not actually doing anything yet. + +3. Treat "-" characters in classes that cannot be part of ranges as literals, +as Perl does (e.g. [-az] or [az-]). + +4. Set the anchored flag if a branch starts with .* or .*? because that tests +all possible positions. + +5. Split up into different modules to avoid including unneeded functions in a +compiled binary. However, compile and exec are still in one module. The "study" +function is split off. + +6. The character tables are now in a separate module whose source is generated +by an auxiliary program - but can then be edited by hand if required. There are +now no calls to isalnum(), isspace(), isdigit(), isxdigit(), tolower() or +toupper() in the code. + +7. Turn the malloc/free funtions variables into pcre_malloc and pcre_free and +make them global. Abolish the function for setting them, as the caller can now +set them directly. + + +Version 0.92 11-Sep-97 +---------------------- + +1. A repeat with a fixed maximum and a minimum of 1 for an ordinary character +(e.g. /a{1,3}/) was broken (I mis-optimized it). + +2. Caseless matching was not working in character classes if the characters in +the pattern were in upper case. + +3. Make ranges like [W-c] work in the same way as Perl for caseless matching. + +4. Make PCRE_ANCHORED public and accept as a compile option. + +5. Add an options word to pcre_exec() and accept PCRE_ANCHORED and +PCRE_CASELESS at run time. Add escapes \A and \I to pcretest to cause it to +pass them. + +6. Give an error if bad option bits passed at compile or run time. + +7. Add PCRE_MULTILINE at compile and exec time, and (?m) as well. Add \M to +pcretest to cause it to pass that flag. + +8. Add pcre_info(), to get the number of identifying subpatterns, the stored +options, and the first character, if set. + +9. Recognize C+ or C{n,m} where n >= 1 as providing a fixed starting character. + + +Version 0.91 10-Sep-97 +---------------------- + +1. PCRE was failing to diagnose unlimited repeats of subpatterns that could +match the empty string as in /(a*)*/. It was looping and ultimately crashing. + +2. PCRE was looping on encountering an indefinitely repeated back reference to +a subpattern that had matched an empty string, e.g. /(a|)\1*/. It now does what +Perl does - treats the match as successful. + +**** diff --git a/mk4/continuity/pcre/INSTALL b/mk4/continuity/pcre/INSTALL new file mode 100644 index 0000000..0880281 --- /dev/null +++ b/mk4/continuity/pcre/INSTALL @@ -0,0 +1,185 @@ +Basic Installation +================== + + These are generic installation instructions that apply to systems that +can run the `configure' shell script - Unix systems and any that imitate +it. They are not specific to PCRE. There are PCRE-specific instructions +for non-Unix systems in the file NON-UNIX-USE. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, a file +`config.cache' that saves the results of its tests to speed up +reconfiguring, and a file `config.log' containing compiler output +(useful mainly for debugging `configure'). + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If at some point `config.cache' +contains results you don't want to keep, you may remove or edit it. + + The file `configure.in' is used to create `configure' by a program +called `autoconf'. You only need `configure.in' if you want to change +it or regenerate `configure' using a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. You can give `configure' +initial values for variables by setting them in the environment. Using +a Bourne-compatible shell, you can do that on the command line like +this: + CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure + +Or on systems that have the `env' program, you can do it like this: + env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not supports the `VPATH' +variable, you have to compile the package for one architecture at a time +in the source code directory. After you have installed the package for +one architecture, use `make distclean' before reconfiguring for another +architecture. + +Installation Names +================== + + By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/man', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PATH'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PATH', the package will use +PATH as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=PATH' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + + There may be some features `configure' can not figure out +automatically, but needs to determine by the type of host the package +will run on. Usually `configure' can figure that out, but if it prints +a message saying it can not guess the host type, give it the +`--host=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name with three fields: + CPU-COMPANY-SYSTEM + +See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the host type. + + If you are building compiler tools for cross-compiling, you can also +use the `--target=TYPE' option to select the type of system they will +produce code for and the `--build=TYPE' option to select the type of +system on which you are compiling the package. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Operation Controls +================== + + `configure' recognizes the following options to control how it +operates. + +`--cache-file=FILE' + Use and save the results of the tests in FILE instead of + `./config.cache'. Set FILE to `/dev/null' to disable caching, for + debugging `configure'. + +`--help' + Print a summary of the options to `configure', and exit. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--version' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`configure' also accepts some other, not widely useful, options. diff --git a/mk4/continuity/pcre/LICENCE b/mk4/continuity/pcre/LICENCE new file mode 100644 index 0000000..8d68061 --- /dev/null +++ b/mk4/continuity/pcre/LICENCE @@ -0,0 +1,54 @@ +PCRE LICENCE +------------ + +PCRE is a library of functions to support regular expressions whose syntax +and semantics are as close as possible to those of the Perl 5 language. + +Written by: Philip Hazel + +University of Cambridge Computing Service, +Cambridge, England. Phone: +44 1223 334714. + +Copyright (c) 1997-2001 University of Cambridge + +Permission is granted to anyone to use this software for any purpose on any +computer system, and to redistribute it freely, subject to the following +restrictions: + +1. This software 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. + +2. The origin of this software must not be misrepresented, either by + explicit claim or by omission. In practice, this means that if you use + PCRE in software that you distribute to others, commercially or + otherwise, you must put a sentence like this + + Regular expression support is provided by the PCRE library package, + which is open source software, written by Philip Hazel, and copyright + by the University of Cambridge, England. + + somewhere reasonably visible in your documentation and in any relevant + files or online help data or similar. A reference to the ftp site for + the source, that is, to + + ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/ + + should also be given in the documentation. However, this condition is not + intended to apply to whole chains of software. If package A includes PCRE, + it must acknowledge it, but if package B is software that includes package + A, the condition is not imposed on package B (unless it uses PCRE + independently). + +3. Altered versions must be plainly marked as such, and must not be + misrepresented as being the original software. + +4. If PCRE is embedded in any software that is released under the GNU + General Purpose Licence (GPL), or Lesser General Purpose Licence (LGPL), + then the terms of that licence shall supersede any condition above with + which it is incompatible. + +The documentation for PCRE, supplied in the "doc" directory, is distributed +under the same terms as the software itself. + +End diff --git a/mk4/continuity/pcre/Makefile.in b/mk4/continuity/pcre/Makefile.in new file mode 100644 index 0000000..ecdd6ef --- /dev/null +++ b/mk4/continuity/pcre/Makefile.in @@ -0,0 +1,282 @@ + +# Makefile.in for PCRE (Perl-Compatible Regular Expression) library. + +#---------------------------------------------------------------------------# +# MinGW DLLs are built automatically with this configure.in and Makefile.in # +# as long you are using autoconf 2.50 or higher. The Win32 static libraries # +# have not been tested, but appear to be generated. This functionality is # +# by courtesy of Fred Cox. I (Philip Hazel) don't know anything about it, # +# as I live entirely in a non-Windows world. # +#---------------------------------------------------------------------------# + + +############################################################################# + +# PCRE is developed on a Unix system. I do not use Windows or Macs, and know +# nothing about building software on them. Although the code of PCRE should +# be very portable, the building system in this Makefile is designed for Unix +# systems, with the exception of the mingw32 stuff just mentioned. + +# This setting enables Unix-style directory scanning in pcregrep, triggered +# by the -f option. Maybe one day someone will add code for other systems. + +PCREGREP_OSTYPE=-DIS_UNIX + +############################################################################# + + +#---------------------------------------------------------------------------# +# The following lines are modified by "configure" to insert data that it is # +# given in its arguments, or which it finds out for itself. # +#---------------------------------------------------------------------------# + +SHELL = @SHELL@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ +top_srcdir = @top_srcdir@ + +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs + +# NB: top_builddir is not referred to directly below, but it is used in the +# setting of $(LIBTOOL), so don't remove it! + +top_builddir = . + +# BINDIR is the directory in which the pcregrep, pcretest, and pcre-config +# commands are installed. +# INCDIR is the directory in which the public header files pcre.h and +# pcreposix.h are installed. +# LIBDIR is the directory in which the libraries are installed. +# MANDIR is the directory in which the man pages are installed. + +BINDIR = @bindir@ +LIBDIR = @libdir@ +INCDIR = @includedir@ +MANDIR = @mandir@ + +# EXEEXT is set by configure to the extention of an executable file +# OBJEXT is set by configure to the extention of an object file +# The BUILD_* equivalents are the same but for the host we're building on + +EXEEXT = @EXEEXT@ +OBJEXT = @OBJEXT@ +# Note that these are just here to have a convenient place to look at the +# outcome. +BUILD_EXEEXT = @BUILD_EXEEXT@ +BUILD_OBJEXT = @BUILD_OBJEXT@ + +# The compiler, C flags, preprocessor flags, etc + +CC = @CC@ +CFLAGS = @CFLAGS@ +CPPFLAGS = @CPPFLAGS@ +CC_FOR_BUILD = @CC_FOR_BUILD@ +CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@ +CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@ +UTF8 = @UTF8@ +NEWLINE = @NEWLINE@ +POSIX_MALLOC_THRESHOLD = @POSIX_MALLOC_THRESHOLD@ +LINK_SIZE = @LINK_SIZE@ +MATCH_LIMIT= @MATCH_LIMIT@ + +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ + +# LIBTOOL enables the building of shared and static libraries. It is set up +# to do one or the other or both by ./configure. + +LIBTOOL = @LIBTOOL@ +LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) -c $(CFLAGS) -I. -I$(top_srcdir) $(NEWLINE) $(LINK_SIZE) $(MATCH_LIMIT) +@ON_WINDOWS@LINK = $(CC) $(CFLAGS) -I. -I$(top_srcdir) -L.libs +@NOT_ON_WINDOWS@LINK = $(LIBTOOL) --mode=link $(CC) $(CFLAGS) -I. -I$(top_srcdir) +LINKLIB = $(LIBTOOL) --mode=link $(CC) $(CFLAGS) -I. -I$(top_srcdir) +LINK_FOR_BUILD = $(LIBTOOL) --mode=link $(CC_FOR_BUILD) $(CFLAGS_FOR_BUILD) -I. -I$(top_srcdir) + +# These are the version numbers for the shared libraries + +PCRELIBVERSION = @PCRE_LIB_VERSION@ +PCREPOSIXLIBVERSION = @PCRE_POSIXLIB_VERSION@ + +############################################################################## + + +OBJ = maketables.@OBJEXT@ get.@OBJEXT@ study.@OBJEXT@ pcre.@OBJEXT@ @POSIX_OBJ@ +LOBJ = maketables.lo get.lo study.lo pcre.lo @POSIX_LOBJ@ + +all: libpcre.la @POSIX_LIB@ pcretest@EXEEXT@ pcregrep@EXEEXT@ @ON_WINDOWS@ winshared + +pcregrep@EXEEXT@: libpcre.la pcregrep.@OBJEXT@ @ON_WINDOWS@ winshared + $(LINK) -o pcregrep@EXEEXT@ pcregrep.@OBJEXT@ -lpcre + +pcretest@EXEEXT@: libpcre.la @POSIX_LIB@ pcretest.@OBJEXT@ @ON_WINDOWS@ winshared + $(LINK) $(PURIFY) $(EFENCE) -o pcretest@EXEEXT@ pcretest.@OBJEXT@ \ + -lpcre @POSIX_LIB@ + +libpcre.la: $(OBJ) + -rm -f libpcre.la + $(LINKLIB) -rpath $(LIBDIR) -version-info \ + '$(PCRELIBVERSION)' -o libpcre.la $(LOBJ) + +libpcreposix.la: pcreposix.@OBJEXT@ + -rm -f libpcreposix.la + $(LINKLIB) -rpath $(LIBDIR) -L. -lpcre -version-info \ + '$(PCREPOSIXLIBVERSION)' -o libpcreposix.la pcreposix.lo + +pcre.@OBJEXT@: $(top_srcdir)/chartables.c $(top_srcdir)/pcre.c \ + $(top_srcdir)/internal.h $(top_srcdir)/printint.c \ + pcre.h config.h Makefile + $(LTCOMPILE) $(UTF8) $(POSIX_MALLOC_THRESHOLD) $(top_srcdir)/pcre.c + +pcreposix.@OBJEXT@: $(top_srcdir)/pcreposix.c $(top_srcdir)/pcreposix.h \ + $(top_srcdir)/internal.h pcre.h config.h Makefile + $(LTCOMPILE) $(POSIX_MALLOC_THRESHOLD) $(top_srcdir)/pcreposix.c + +maketables.@OBJEXT@: $(top_srcdir)/maketables.c $(top_srcdir)/internal.h \ + pcre.h config.h Makefile + $(LTCOMPILE) $(top_srcdir)/maketables.c + +get.@OBJEXT@: $(top_srcdir)/get.c $(top_srcdir)/internal.h \ + pcre.h config.h Makefile + $(LTCOMPILE) $(top_srcdir)/get.c + +study.@OBJEXT@: $(top_srcdir)/study.c $(top_srcdir)/internal.h \ + pcre.h config.h Makefile + $(LTCOMPILE) $(UTF8) $(top_srcdir)/study.c + +pcretest.@OBJEXT@: $(top_srcdir)/pcretest.c $(top_srcdir)/internal.h \ + $(top_srcdir)/printint.c \ + pcre.h config.h Makefile + $(CC) -c $(CFLAGS) -I. $(UTF8) $(LINK_SIZE) $(top_srcdir)/pcretest.c + +pcregrep.@OBJEXT@: $(top_srcdir)/pcregrep.c pcre.h Makefile config.h + $(CC) -c $(CFLAGS) -I. $(UTF8) $(PCREGREP_OSTYPE) $(top_srcdir)/pcregrep.c + +# Some Windows-specific targets, for Cygwin and MinGW + +winshared : .libs/@WIN_PREFIX@pcre.dll .libs/@WIN_PREFIX@pcreposix.dll + +.libs/@WIN_PREFIX@pcre.dll : libpcre.la + $(CC) $(CFLAGS) -shared -o $@ \ + -Wl,--whole-archive .libs/libpcre.a \ + -Wl,--out-implib,.libs/libpcre.dll.a \ + -Wl,--output-def,.libs/@WIN_PREFIX@pcre.dll-def \ + -Wl,--export-all-symbols \ + -Wl,--no-whole-archive + sed -e "s#dlname=''#dlname='../bin/@WIN_PREFIX@pcre.dll'#" \ + -e "s#library_names=''#library_names='libpcre.dll.a'#" \ + < .libs/libpcre.lai > .libs/libpcre.lai.tmp && \ + mv .libs/libpcre.lai.tmp .libs/libpcre.lai + sed -e "s#dlname=''#dlname='../bin/@WIN_PREFIX@pcre.dll'#" \ + -e "s#library_names=''#library_names='libpcre.dll.a'#" \ + < libpcre.la > libpcre.la.tmp && \ + mv libpcre.la.tmp libpcre.la + + +.libs/@WIN_PREFIX@pcreposix.dll: libpcreposix.la libpcre.la + $(CC) $(CFLAGS) -shared -o $@ \ + -Wl,--whole-archive .libs/libpcreposix.a \ + -Wl,--out-implib,.libs/lib@WIN_PREFIX@pcreposix.dll.a \ + -Wl,--output-def,.libs/@WIN_PREFIX@pcreposix.dll-def \ + -Wl,--export-all-symbols \ + -Wl,--no-whole-archive .libs/libpcre.a + sed -e "s#dlname=''#dlname='../bin/@WIN_PREFIX@pcreposix.dll'#" \ + -e "s#library_names=''#library_names='libpcreposix.dll.a'#"\ + < .libs/libpcreposix.lai > .libs/libpcreposix.lai.tmp && \ + mv .libs/libpcreposix.lai.tmp .libs/libpcreposix.lai + sed -e "s#dlname=''#dlname='../bin/@WIN_PREFIX@pcreposix.dll'#" \ + -e "s#library_names=''#library_names='libpcreposix.dll.a'#"\ + < libpcreposix.la > libpcreposix.la.tmp && \ + mv libpcreposix.la.tmp libpcreposix.la + + +wininstall : winshared + $(mkinstalldirs) $(DESTDIR)$(LIBDIR) + $(mkinstalldirs) $(DESTDIR)$(BINDIR) + $(INSTALL) .libs/@WIN_PREFIX@pcre.dll $(DESTDIR)$(BINDIR)/@WIN_PREFIX@pcre.dll + $(INSTALL) .libs/@WIN_PREFIX@pcreposix.dll $(DESTDIR)$(BINDIR)/@WIN_PREFIX@pcreposix.dll + $(INSTALL) .libs/@WIN_PREFIX@libpcreposix.dll.a $(DESTDIR)$(LIBDIR)/@WIN_PREFIX@libpcreposix.dll.a + $(INSTALL) .libs/@WIN_PREFIX@libpcre.dll.a $(DESTDIR)$(LIBDIR)/@WIN_PREFIX@libpcre.dll.a + -strip -g $(DESTDIR)$(BINDIR)/@WIN_PREFIX@pcre.dll + -strip -g $(DESTDIR)$(BINDIR)/@WIN_PREFIX@pcreposix.dll + -strip $(DESTDIR)$(BINDIR)/pcregrep@EXEEXT@ + -strip $(DESTDIR)$(BINDIR)/pcretest@EXEEXT@ + +# An auxiliary program makes the default character table source + +$(top_srcdir)/chartables.c: dftables + ./dftables >$(top_srcdir)/chartables.c + +dftables.@BUILD_OBJEXT@: $(top_srcdir)/dftables.c $(top_srcdir)/maketables.c \ + $(top_srcdir)/internal.h pcre.h config.h Makefile + $(CC_FOR_BUILD) -c $(CFLAGS_FOR_BUILD) -I. $(top_srcdir)/dftables.c + +dftables: dftables.@BUILD_OBJEXT@ + $(LINK_FOR_BUILD) -o dftables dftables.@OBJEXT@ + +install: all @ON_WINDOWS@ wininstall +@NOT_ON_WINDOWS@ $(mkinstalldirs) $(DESTDIR)$(LIBDIR) +@NOT_ON_WINDOWS@ echo "$(LIBTOOL) --mode=install $(INSTALL) libpcre.la $(DESTDIR)$(LIBDIR)/libpcre.la" +@NOT_ON_WINDOWS@ $(LIBTOOL) --mode=install $(INSTALL) libpcre.la $(DESTDIR)$(LIBDIR)/libpcre.la +@NOT_ON_WINDOWS@ echo "$(LIBTOOL) --mode=install $(INSTALL) libpcreposix.la $(DESTDIR)$(LIBDIR)/libpcreposix.la" +@NOT_ON_WINDOWS@ $(LIBTOOL) --mode=install $(INSTALL) libpcreposix.la $(DESTDIR)$(LIBDIR)/libpcreposix.la +@NOT_ON_WINDOWS@ $(LIBTOOL) --finish $(DESTDIR)$(LIBDIR) + $(mkinstalldirs) $(DESTDIR)$(INCDIR) + $(INSTALL_DATA) pcre.h $(DESTDIR)$(INCDIR)/pcre.h + $(INSTALL_DATA) $(top_srcdir)/pcreposix.h $(DESTDIR)$(INCDIR)/pcreposix.h + $(mkinstalldirs) $(DESTDIR)$(MANDIR)/man3 + $(INSTALL_DATA) $(top_srcdir)/doc/pcre.3 $(DESTDIR)$(MANDIR)/man3/pcre.3 + $(INSTALL_DATA) $(top_srcdir)/doc/pcreapi.3 $(DESTDIR)$(MANDIR)/man3/pcreapi.3 + $(INSTALL_DATA) $(top_srcdir)/doc/pcrebuild.3 $(DESTDIR)$(MANDIR)/man3/pcrebuild.3 + $(INSTALL_DATA) $(top_srcdir)/doc/pcrecallout.3 $(DESTDIR)$(MANDIR)/man3/pcrecallout.3 + $(INSTALL_DATA) $(top_srcdir)/doc/pcrecompat.3 $(DESTDIR)$(MANDIR)/man3/pcrecompat.3 + $(INSTALL_DATA) $(top_srcdir)/doc/pcrepattern.3 $(DESTDIR)$(MANDIR)/man3/pcrepattern.3 + $(INSTALL_DATA) $(top_srcdir)/doc/pcreperform.3 $(DESTDIR)$(MANDIR)/man3/pcreperform.3 + $(INSTALL_DATA) $(top_srcdir)/doc/pcreposix.3 $(DESTDIR)$(MANDIR)/man3/pcreposix.3 + $(INSTALL_DATA) $(top_srcdir)/doc/pcresample.3 $(DESTDIR)$(MANDIR)/man3/pcresample.3 + $(INSTALL_DATA) $(top_srcdir)/doc/pcre_compile.3 $(DESTDIR)$(MANDIR)/man3/pcre_compile.3 + $(INSTALL_DATA) $(top_srcdir)/doc/pcre_config.3 $(DESTDIR)$(MANDIR)/man3/pcre_config.3 + $(INSTALL_DATA) $(top_srcdir)/doc/pcre_copy_named_substring.3 $(DESTDIR)$(MANDIR)/man3/pcre_copy_named_substring.3 + $(INSTALL_DATA) $(top_srcdir)/doc/pcre_copy_substring.3 $(DESTDIR)$(MANDIR)/man3/pcre_copy_substring.3 + $(INSTALL_DATA) $(top_srcdir)/doc/pcre_exec.3 $(DESTDIR)$(MANDIR)/man3/pcre_exec.3 + $(INSTALL_DATA) $(top_srcdir)/doc/pcre_free_substring.3 $(DESTDIR)$(MANDIR)/man3/pcre_free_substring.3 + $(INSTALL_DATA) $(top_srcdir)/doc/pcre_free_substring_list.3 $(DESTDIR)$(MANDIR)/man3/pcre_free_substring_list.3 + $(INSTALL_DATA) $(top_srcdir)/doc/pcre_fullinfo.3 $(DESTDIR)$(MANDIR)/man3/pcre_fullinfo.3 + $(INSTALL_DATA) $(top_srcdir)/doc/pcre_get_named_substring.3 $(DESTDIR)$(MANDIR)/man3/pcre_get_named_substring.3 + $(INSTALL_DATA) $(top_srcdir)/doc/pcre_get_stringnumber.3 $(DESTDIR)$(MANDIR)/man3/pcre_get_stringnumber.3 + $(INSTALL_DATA) $(top_srcdir)/doc/pcre_get_substring.3 $(DESTDIR)$(MANDIR)/man3/pcre_get_substring.3 + $(INSTALL_DATA) $(top_srcdir)/doc/pcre_get_substring_list.3 $(DESTDIR)$(MANDIR)/man3/pcre_get_substring_list.3 + $(INSTALL_DATA) $(top_srcdir)/doc/pcre_info.3 $(DESTDIR)$(MANDIR)/man3/pcre_info.3 + $(INSTALL_DATA) $(top_srcdir)/doc/pcre_maketables.3 $(DESTDIR)$(MANDIR)/man3/pcre_maketables.3 + $(INSTALL_DATA) $(top_srcdir)/doc/pcre_study.3 $(DESTDIR)$(MANDIR)/man3/pcre_study.3 + $(INSTALL_DATA) $(top_srcdir)/doc/pcre_version.3 $(DESTDIR)$(MANDIR)/man3/pcre_version.3 + $(mkinstalldirs) $(DESTDIR)$(MANDIR)/man1 + $(INSTALL_DATA) $(top_srcdir)/doc/pcregrep.1 $(DESTDIR)$(MANDIR)/man1/pcregrep.1 + $(INSTALL_DATA) $(top_srcdir)/doc/pcretest.1 $(DESTDIR)$(MANDIR)/man1/pcretest.1 + $(mkinstalldirs) $(DESTDIR)$(BINDIR) + $(LIBTOOL) --mode=install $(INSTALL) pcregrep@EXEEXT@ $(DESTDIR)$(BINDIR)/pcregrep@EXEEXT@ + $(LIBTOOL) --mode=install $(INSTALL) pcretest@EXEEXT@ $(DESTDIR)$(BINDIR)/pcretest@EXEEXT@ + $(INSTALL) pcre-config $(DESTDIR)$(BINDIR)/pcre-config + +# We deliberately omit dftables and chartables.c from 'make clean'; once made +# chartables.c shouldn't change, and if people have edited the tables by hand, +# you don't want to throw them away. + +clean:; -rm -rf *.@OBJEXT@ *.lo *.a *.la .libs pcretest@EXEEXT@ pcregrep@EXEEXT@ testtry + +# But "make distclean" should get back to a virgin distribution + +distclean: clean + -rm -f chartables.c libtool pcre-config pcre.h \ + Makefile config.h config.status config.log config.cache + +check: runtest + +@WIN_PREFIX@pcre.dll : winshared + cp .libs/@WIN_PREFIX@pcre.dll . + +test: runtest + +runtest: all @ON_WINDOWS@ @WIN_PREFIX@pcre.dll + ./RunTest + +# End diff --git a/mk4/continuity/pcre/NEWS b/mk4/continuity/pcre/NEWS new file mode 100644 index 0000000..e620b2d --- /dev/null +++ b/mk4/continuity/pcre/NEWS @@ -0,0 +1,123 @@ +News about PCRE releases +------------------------ + +Release 4.0 17-Feb-03 +--------------------- + +There have been a lot of changes for the 4.0 release, adding additional +functionality and mending bugs. Below is a list of the highlights of the new +functionality. For full details of these features, please consult the +documentation. For a complete list of changes, see the ChangeLog file. + +1. Support for Perl's \Q...\E escapes. + +2. "Possessive quantifiers" ?+, *+, ++, and {,}+ which come from Sun's Java +package. They provide some syntactic sugar for simple cases of "atomic +grouping". + +3. Support for the \G assertion. It is true when the current matching position +is at the start point of the match. + +4. A new feature that provides some of the functionality that Perl provides +with (?{...}). The facility is termed a "callout". The way it is done in PCRE +is for the caller to provide an optional function, by setting pcre_callout to +its entry point. To get the function called, the regex must include (?C) at +appropriate points. + +5. Support for recursive calls to individual subpatterns. This makes it really +easy to get totally confused. + +6. Support for named subpatterns. The Python syntax (?P...) is used to +name a group. + +7. Several extensions to UTF-8 support; it is now fairly complete. There is an +option for pcregrep to make it operate in UTF-8 mode. + +8. The single man page has been split into a number of separate man pages. +These also give rise to individual HTML pages which are put in a separate +directory. There is an index.html page that lists them all. Some hyperlinking +between the pages has been installed. + + +Release 3.5 15-Aug-01 +--------------------- + +1. The configuring system has been upgraded to use later versions of autoconf +and libtool. By default it builds both a shared and a static library if the OS +supports it. You can use --disable-shared or --disable-static on the configure +command if you want only one of them. + +2. The pcretest utility is now installed along with pcregrep because it is +useful for users (to test regexs) and by doing this, it automatically gets +relinked by libtool. The documentation has been turned into a man page, so +there are now .1, .txt, and .html versions in /doc. + +3. Upgrades to pcregrep: + (i) Added long-form option names like gnu grep. + (ii) Added --help to list all options with an explanatory phrase. + (iii) Added -r, --recursive to recurse into sub-directories. + (iv) Added -f, --file to read patterns from a file. + +4. Added --enable-newline-is-cr and --enable-newline-is-lf to the configure +script, to force use of CR or LF instead of \n in the source. On non-Unix +systems, the value can be set in config.h. + +5. The limit of 200 on non-capturing parentheses is a _nesting_ limit, not an +absolute limit. Changed the text of the error message to make this clear, and +likewise updated the man page. + +6. The limit of 99 on the number of capturing subpatterns has been removed. +The new limit is 65535, which I hope will not be a "real" limit. + + +Release 3.3 01-Aug-00 +--------------------- + +There is some support for UTF-8 character strings. This is incomplete and +experimental. The documentation describes what is and what is not implemented. +Otherwise, this is just a bug-fixing release. + + +Release 3.0 01-Feb-00 +--------------------- + +1. A "configure" script is now used to configure PCRE for Unix systems. It +builds a Makefile, a config.h file, and the pcre-config script. + +2. PCRE is built as a shared library by default. + +3. There is support for POSIX classes such as [:alpha:]. + +5. There is an experimental recursion feature. + +---------------------------------------------------------------------------- + IMPORTANT FOR THOSE UPGRADING FROM VERSIONS BEFORE 2.00 + +Please note that there has been a change in the API such that a larger +ovector is required at matching time, to provide some additional workspace. +The new man page has details. This change was necessary in order to support +some of the new functionality in Perl 5.005. + + IMPORTANT FOR THOSE UPGRADING FROM VERSION 2.00 + +Another (I hope this is the last!) change has been made to the API for the +pcre_compile() function. An additional argument has been added to make it +possible to pass over a pointer to character tables built in the current +locale by pcre_maketables(). To use the default tables, this new arguement +should be passed as NULL. + + IMPORTANT FOR THOSE UPGRADING FROM VERSION 2.05 + +Yet another (and again I hope this really is the last) change has been made +to the API for the pcre_exec() function. An additional argument has been +added to make it possible to start the match other than at the start of the +subject string. This is important if there are lookbehinds. The new man +page has the details, but you just want to convert existing programs, all +you need to do is to stick in a new fifth argument to pcre_exec(), with a +value of zero. For example, change + + pcre_exec(pattern, extra, subject, length, options, ovec, ovecsize) +to + pcre_exec(pattern, extra, subject, length, 0, options, ovec, ovecsize) + +**** diff --git a/mk4/continuity/pcre/NON-UNIX-USE b/mk4/continuity/pcre/NON-UNIX-USE new file mode 100644 index 0000000..a000c29 --- /dev/null +++ b/mk4/continuity/pcre/NON-UNIX-USE @@ -0,0 +1,113 @@ +Compiling PCRE on non-Unix systems +---------------------------------- + +See below for comments on Cygwin or MinGW usage. + +If you want to compile PCRE for a non-Unix system, note that it consists +entirely of code written in Standard C, and so should compile successfully +on any machine with a Standard C compiler and library, using normal compiling +commands to do the following: + +(1) Copy or rename the file config.in as config.h, and change the macros that +define HAVE_STRERROR and HAVE_MEMMOVE to define them as 1 rather than 0. +Unfortunately, because of the way Unix autoconf works, the default setting has +to be 0. You may also want to make changes to other macros in config.h. In +particular, if you want to force a specific value for newline, you can define +the NEWLINE macro. The default is to use '\n', thereby using whatever value +your compiler gives to '\n'. + +(2) Copy or rename the file pcre.in as pcre.h, and change the macro definitions +for PCRE_MAJOR, PCRE_MINOR, and PCRE_DATE near its start to the values set in +configure.in. + +(3) Compile dftables.c as a stand-alone program, and then run it with +the standard output sent to chartables.c. This generates a set of standard +character tables. + +(4) Compile maketables.c, get.c, study.c and pcre.c and link them all +together into an object library in whichever form your system keeps such +libraries. This is the pcre library (chartables.c is included by means of an +#include directive). + +(5) Similarly, compile pcreposix.c and link it as the pcreposix library. + +(6) Compile the test program pcretest.c. This needs the functions in the +pcre and pcreposix libraries when linking. + +(7) Run pcretest on the testinput files in the testdata directory, and check +that the output matches the corresponding testoutput files. You must use the +-i option when checking testinput2. Note that the supplied files are in Unix +format, with just LF characters as line terminators. You may need to edit them +to change this if your system uses a different convention. + +If you have a system without "configure" but where you can use a Makefile, edit +Makefile.in to create Makefile, substituting suitable values for the variables +at the head of the file. + +Some help in building a Win32 DLL of PCRE in GnuWin32 environments was +contributed by Paul Sokolovsky. These environments are Mingw32 +(http://www.xraylith.wisc.edu/~khan/software/gnu-win32/) and CygWin +(http://sourceware.cygnus.com/cygwin/). Paul comments: + + For CygWin, set CFLAGS=-mno-cygwin, and do 'make dll'. You'll get + pcre.dll (containing pcreposix also), libpcre.dll.a, and dynamically + linked pgrep and pcretest. If you have /bin/sh, run RunTest (three + main test go ok, locale not supported). + +Changes to do MinGW with autoconf 2.50 were supplied by Fred Cox +, who comments as follows: + + If you are using the PCRE DLL, the normal Unix style configure && make && + make check && make install should just work[*]. If you want to statically + link against the .a file, you must define PCRE_STATIC before including + pcre.h, otherwise the pcre_malloc and pcre_free exported functions will be + declared __declspec(dllimport), with hilarious results. See the configure.in + and pcretest.c for how it is done for the static test. + + Also, there will only be a libpcre.la, not a libpcreposix.la, as you + would expect from the Unix version. The single DLL includes the pcreposix + interface. + +[*] But note that the supplied test files are in Unix format, with just LF +characters as line terminators. You will have to edit them to change to CR LF +terminators. + +A script for building PCRE using Borland's C++ compiler for use with VPASCAL +was contributed by Alexander Tokarev. It is called makevp.bat. + +These are some further comments about Win32 builds from Mark Evans. They +were contributed before Fred Cox's changes were made, so it is possible that +they may no longer be relevant. + +The documentation for Win32 builds is a bit shy. Under MSVC6 I +followed their instructions to the letter, but there were still +some things missing. + +(1) Must #define STATIC for entire project if linking statically. + (I see no reason to use DLLs for code this compact.) This of + course is a project setting in MSVC under Preprocessor. + +(2) Missing some #ifdefs relating to the function pointers + pcre_malloc and pcre_free. See my solution below. (The stubs + may not be mandatory but they made me feel better.) + +========================= +#ifdef _WIN32 +#include + +void* malloc_stub(size_t N) +{ return malloc(N); } +void free_stub(void* p) +{ free(p); } +void *(*pcre_malloc)(size_t) = &malloc_stub; +void (*pcre_free)(void *) = &free_stub; + +#else + +void *(*pcre_malloc)(size_t) = malloc; +void (*pcre_free)(void *) = free; + +#endif +========================= + +**** diff --git a/mk4/continuity/pcre/README b/mk4/continuity/pcre/README new file mode 100644 index 0000000..6cef77c --- /dev/null +++ b/mk4/continuity/pcre/README @@ -0,0 +1,357 @@ +README file for PCRE (Perl-compatible regular expression library) +----------------------------------------------------------------- + +The latest release of PCRE is always available from + + ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-xxx.tar.gz + +Please read the NEWS file if you are upgrading from a previous release. + +PCRE has its own native API, but a set of "wrapper" functions that are based on +the POSIX API are also supplied in the library libpcreposix. Note that this +just provides a POSIX calling interface to PCRE: the regular expressions +themselves still follow Perl syntax and semantics. The header file +for the POSIX-style functions is called pcreposix.h. The official POSIX name is +regex.h, but I didn't want to risk possible problems with existing files of +that name by distributing it that way. To use it with an existing program that +uses the POSIX API, it will have to be renamed or pointed at by a link. + + +Contributions by users of PCRE +------------------------------ + +You can find contributions from PCRE users in the directory + + ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/Contrib + +where there is also a README file giving brief descriptions of what they are. +Several of them provide support for compiling PCRE on various flavours of +Windows systems (I myself do not use Windows). Some are complete in themselves; +others are pointers to URLs containing relevant files. + + +Building PCRE on a Unix-like system +----------------------------------- + +To build PCRE on a Unix-like system, first run the "configure" command from the +PCRE distribution directory, with your current directory set to the directory +where you want the files to be created. This command is a standard GNU +"autoconf" configuration script, for which generic instructions are supplied in +INSTALL. + +Most commonly, people build PCRE within its own distribution directory, and in +this case, on many systems, just running "./configure" is sufficient, but the +usual methods of changing standard defaults are available. For example, + +CFLAGS='-O2 -Wall' ./configure --prefix=/opt/local + +specifies that the C compiler should be run with the flags '-O2 -Wall' instead +of the default, and that "make install" should install PCRE under /opt/local +instead of the default /usr/local. + +If you want to build in a different directory, just run "configure" with that +directory as current. For example, suppose you have unpacked the PCRE source +into /source/pcre/pcre-xxx, but you want to build it in /build/pcre/pcre-xxx: + +cd /build/pcre/pcre-xxx +/source/pcre/pcre-xxx/configure + +There are some optional features that can be included or omitted from the PCRE +library. You can read more about them in the pcrebuild man page. + +. If you want to make use of the support for UTF-8 character strings in PCRE, + you must add --enable-utf8 to the "configure" command. Without it, the code + for handling UTF-8 is not included in the library. (Even when included, it + still has to be enabled by an option at run time.) + +. You can build PCRE to recognized CR or NL as the newline character, instead + of whatever your compiler uses for "\n", by adding --newline-is-cr or + --newline-is-nl to the "configure" command, respectively. Only do this if you + really understand what you are doing. On traditional Unix-like systems, the + newline character is NL. + +. When called via the POSIX interface, PCRE uses malloc() to get additional + storage for processing capturing parentheses if there are more than 10 of + them. You can increase this threshold by setting, for example, + + --with-posix-malloc-threshold=20 + + on the "configure" command. + +. PCRE has a counter which can be set to limit the amount of resources it uses. + If the limit is exceeded during a match, the match fails. The default is ten + million. You can change the default by setting, for example, + + --with-match-limit=500000 + + on the "configure" command. This is just the default; individual calls to + pcre_exec() can supply their own value. There is discussion on the pcreapi + man page. + +. The default maximum compiled pattern size is around 64K. You can increase + this by adding --with-link-size=3 to the "configure" command. You can + increase it even more by setting --with-link-size=4, but this is unlikely + ever to be necessary. If you build PCRE with an increased link size, test 2 + (and 5 if you are using UTF-8) will fail. Part of the output of these tests + is a representation of the compiled pattern, and this changes with the link + size. + +The "configure" script builds five files: + +. libtool is a script that builds shared and/or static libraries +. Makefile is built by copying Makefile.in and making substitutions. +. config.h is built by copying config.in and making substitutions. +. pcre-config is built by copying pcre-config.in and making substitutions. +. RunTest is a script for running tests + +Once "configure" has run, you can run "make". It builds two libraries called +libpcre and libpcreposix, a test program called pcretest, and the pcregrep +command. You can use "make install" to copy these, the public header files +pcre.h and pcreposix.h, and the man pages to appropriate live directories on +your system, in the normal way. + +Running "make install" also installs the command pcre-config, which can be used +to recall information about the PCRE configuration and installation. For +example, + + pcre-config --version + +prints the version number, and + + pcre-config --libs + +outputs information about where the library is installed. This command can be +included in makefiles for programs that use PCRE, saving the programmer from +having to remember too many details. + + +Cross-compiling PCRE on a Unix-like system +------------------------------------------ + +PCRE needs to compile and run an auxiliary program as part of the building +process. Obviously, if the real compilation is for some other system, it can't +use the same CC and CFLAGS values when it is doing this. For cross compilation, +therefore, you must set CC_FOR_BUILD to the local host's compiler, and you can +set flags in CFLAGS_FOR_BUILD if you need to. + + +Shared libraries on Unix-like systems +------------------------------------- + +The default distribution builds PCRE as two shared libraries and two static +libraries, as long as the operating system supports shared libraries. Shared +library support relies on the "libtool" script which is built as part of the +"configure" process. + +The libtool script is used to compile and link both shared and static +libraries. They are placed in a subdirectory called .libs when they are newly +built. The programs pcretest and pcregrep are built to use these uninstalled +libraries (by means of wrapper scripts in the case of shared libraries). When +you use "make install" to install shared libraries, pcregrep and pcretest are +automatically re-built to use the newly installed shared libraries before being +installed themselves. However, the versions left in the source directory still +use the uninstalled libraries. + +To build PCRE using static libraries only you must use --disable-shared when +configuring it. For example + +./configure --prefix=/usr/gnu --disable-shared + +Then run "make" in the usual way. Similarly, you can use --disable-static to +build only shared libraries. + + +Cross-compiling on a Unix-like system +------------------------------------- + +You can specify CC and CFLAGS in the normal way to the "configure" command, in +order to cross-compile PCRE for some other host. However, during the building +process, the dftables.c source file is compiled *and run* on the local host, in +order to generate the default character tables (the chartables.c file). It +therefore needs to be compiled with the local compiler, not the cross compiler. +You can do this by specifying HOST_CC (and if necessary HOST_CFLAGS) when +calling the "configure" command. If they are not specified, they default to the +values of CC and CFLAGS. + + +Building on non-Unix systems +---------------------------- + +For a non-Unix system, read the comments in the file NON-UNIX-USE. PCRE has +been compiled on Windows systems and on Macintoshes, but I don't know the +details because I don't use those systems. It should be straightforward to +build PCRE on any system that has a Standard C compiler, because it uses only +Standard C functions. + + +Testing PCRE +------------ + +To test PCRE on a Unix system, run the RunTest script that is created by the +configuring process. (This can also be run by "make runtest", "make check", or +"make test".) For other systems, see the instruction in NON-UNIX-USE. + +The script runs the pcretest test program (which is documented in its own man +page) on each of the testinput files (in the testdata directory) in turn, +and compares the output with the contents of the corresponding testoutput file. +A file called testtry is used to hold the output from pcretest. To run pcretest +on just one of the test files, give its number as an argument to RunTest, for +example: + + RunTest 2 + +The first file can also be fed directly into the perltest script to check that +Perl gives the same results. The only difference you should see is in the first +few lines, where the Perl version is given instead of the PCRE version. + +The second set of tests check pcre_fullinfo(), pcre_info(), pcre_study(), +pcre_copy_substring(), pcre_get_substring(), pcre_get_substring_list(), error +detection, and run-time flags that are specific to PCRE, as well as the POSIX +wrapper API. It also uses the debugging flag to check some of the internals of +pcre_compile(). + +If you build PCRE with a locale setting that is not the standard C locale, the +character tables may be different (see next paragraph). In some cases, this may +cause failures in the second set of tests. For example, in a locale where the +isprint() function yields TRUE for characters in the range 128-255, the use of +[:isascii:] inside a character class defines a different set of characters, and +this shows up in this test as a difference in the compiled code, which is being +listed for checking. Where the comparison test output contains [\x00-\x7f] the +test will contain [\x00-\xff], and similarly in some other cases. This is not a +bug in PCRE. + +The third set of tests checks pcre_maketables(), the facility for building a +set of character tables for a specific locale and using them instead of the +default tables. The tests make use of the "fr" (French) locale. Before running +the test, the script checks for the presence of this locale by running the +"locale" command. If that command fails, or if it doesn't include "fr" in the +list of available locales, the third test cannot be run, and a comment is +output to say why. If running this test produces instances of the error + + ** Failed to set locale "fr" + +in the comparison output, it means that locale is not available on your system, +despite being listed by "locale". This does not mean that PCRE is broken. + +The fourth test checks the UTF-8 support. It is not run automatically unless +PCRE is built with UTF-8 support. To do this you must set --enable-utf8 when +running "configure". This file can be also fed directly to the perltest script, +provided you are running Perl 5.8 or higher. (For Perl 5.6, a small patch, +commented in the script, can be be used.) + +The fifth and final file tests error handling with UTF-8 encoding, and internal +UTF-8 features of PCRE that are not relevant to Perl. + + +Character tables +---------------- + +PCRE uses four tables for manipulating and identifying characters. The final +argument of the pcre_compile() function is a pointer to a block of memory +containing the concatenated tables. A call to pcre_maketables() can be used to +generate a set of tables in the current locale. If the final argument for +pcre_compile() is passed as NULL, a set of default tables that is built into +the binary is used. + +The source file called chartables.c contains the default set of tables. This is +not supplied in the distribution, but is built by the program dftables +(compiled from dftables.c), which uses the ANSI C character handling functions +such as isalnum(), isalpha(), isupper(), islower(), etc. to build the table +sources. This means that the default C locale which is set for your system will +control the contents of these default tables. You can change the default tables +by editing chartables.c and then re-building PCRE. If you do this, you should +probably also edit Makefile to ensure that the file doesn't ever get +re-generated. + +The first two 256-byte tables provide lower casing and case flipping functions, +respectively. The next table consists of three 32-byte bit maps which identify +digits, "word" characters, and white space, respectively. These are used when +building 32-byte bit maps that represent character classes. + +The final 256-byte table has bits indicating various character types, as +follows: + + 1 white space character + 2 letter + 4 decimal digit + 8 hexadecimal digit + 16 alphanumeric or '_' + 128 regular expression metacharacter or binary zero + +You should not alter the set of characters that contain the 128 bit, as that +will cause PCRE to malfunction. + + +Manifest +-------- + +The distribution should contain the following files: + +(A) The actual source files of the PCRE library functions and their + headers: + + dftables.c auxiliary program for building chartables.c + get.c ) + maketables.c ) + study.c ) source of + pcre.c ) the functions + pcreposix.c ) + printint.c ) + pcre.in "source" for the header for the external API; pcre.h + is built from this by "configure" + pcreposix.h header for the external POSIX wrapper API + internal.h header for internal use + config.in template for config.h, which is built by configure + +(B) Auxiliary files: + + AUTHORS information about the author of PCRE + ChangeLog log of changes to the code + INSTALL generic installation instructions + LICENCE conditions for the use of PCRE + COPYING the same, using GNU's standard name + Makefile.in template for Unix Makefile, which is built by configure + NEWS important changes in this release + NON-UNIX-USE notes on building PCRE on non-Unix systems + README this file + RunTest.in template for a Unix shell script for running tests + config.guess ) files used by libtool, + config.sub ) used only when building a shared library + configure a configuring shell script (built by autoconf) + configure.in the autoconf input used to build configure + doc/Tech.Notes notes on the encoding + doc/*.3 man page sources for the PCRE functions + doc/*.1 man page sources for pcregrep and pcretest + doc/html/* HTML documentation + doc/pcre.txt plain text version of the man pages + doc/pcretest.txt plain text documentation of test program + doc/perltest.txt plain text documentation of Perl test program + install-sh a shell script for installing files + ltmain.sh file used to build a libtool script + pcretest.c comprehensive test program + pcredemo.c simple demonstration of coding calls to PCRE + perltest Perl test program + pcregrep.c source of a grep utility that uses PCRE + pcre-config.in source of script which retains PCRE information + testdata/testinput1 test data, compatible with Perl + testdata/testinput2 test data for error messages and non-Perl things + testdata/testinput3 test data for locale-specific tests + testdata/testinput4 test data for UTF-8 tests compatible with Perl + testdata/testinput5 test data for other UTF-8 tests + testdata/testoutput1 test results corresponding to testinput1 + testdata/testoutput2 test results corresponding to testinput2 + testdata/testoutput3 test results corresponding to testinput3 + testdata/testoutput4 test results corresponding to testinput4 + testdata/testoutput5 test results corresponding to testinput5 + +(C) Auxiliary files for Win32 DLL + + dll.mk + pcre.def + +(D) Auxiliary file for VPASCAL + + makevp.bat + +Philip Hazel +February 2003 diff --git a/mk4/continuity/pcre/RunTest.in b/mk4/continuity/pcre/RunTest.in new file mode 100644 index 0000000..dd5a02f --- /dev/null +++ b/mk4/continuity/pcre/RunTest.in @@ -0,0 +1,135 @@ +#! /bin/sh + +# This file is generated by configure from RunTest.in. Make any changes +# to that file. + +# Run PCRE tests + +cf=diff +testdata=@top_srcdir@/testdata + +# Select which tests to run; if no selection, run all + +do1=no +do2=no +do3=no +do4=no +do5=no + +while [ $# -gt 0 ] ; do + case $1 in + 1) do1=yes;; + 2) do2=yes;; + 3) do3=yes;; + 4) do4=yes;; + 5) do5=yes;; + *) echo "Unknown test number $1"; exit 1;; + esac + shift +done + +if [ "@UTF8@" = "" ] ; then + if [ $do4 = yes ] ; then + echo "Can't run test 4 because UFT8 support is not configured" + exit 1 + fi + if [ $do5 = yes ] ; then + echo "Can't run test 5 because UFT8 support is not configured" + exit 1 + fi +fi + +if [ $do1 = no -a $do2 = no -a $do3 = no -a $do4 = no -a\ + $do5 = no ] ; then + do1=yes + do2=yes + do3=yes + if [ "@UTF8@" != "" ] ; then do4=yes; fi + if [ "@UTF8@" != "" ] ; then do5=yes; fi +fi + +# Primary test, Perl-compatible + +if [ $do1 = yes ] ; then + echo "Testing main functionality (Perl compatible)" + ./pcretest $testdata/testinput1 testtry + if [ $? = 0 ] ; then + $cf testtry $testdata/testoutput1 + if [ $? != 0 ] ; then exit 1; fi + echo " " + else exit 1 + fi +fi + +# PCRE tests that are not Perl-compatible - API & error tests, mostly + +if [ $do2 = yes ] ; then + echo "Testing API and error handling (not Perl compatible)" + ./pcretest -i $testdata/testinput2 testtry + if [ $? = 0 ] ; then + $cf testtry $testdata/testoutput2 + if [ $? != 0 ] ; then exit 1; fi + else exit 1 + fi +fi + +if [ $do1 = yes -a $do2 = yes ] ; then + echo " " + echo "The two main tests ran OK" + echo " " +fi + +# Locale-specific tests, provided the "fr" locale is available + +if [ $do3 = yes ] ; then + locale -a | grep '^fr$' >/dev/null + if [ $? -eq 0 ] ; then + echo "Testing locale-specific features (using 'fr' locale)" + ./pcretest $testdata/testinput3 testtry + if [ $? = 0 ] ; then + $cf testtry $testdata/testoutput3 + if [ $? != 0 ] ; then + echo " " + echo "Locale test did not run entirely successfully." + echo "This usually means that there is a problem with the locale" + echo "settings rather than a bug in PCRE." + else + echo "Locale test ran OK" + fi + echo " " + else exit 1 + fi + else + echo "Cannot test locale-specific features - 'fr' locale not found," + echo "or the \"locale\" command is not available to check for it." + echo " " + fi +fi + +# Additional tests for UTF8 support + +if [ $do4 = yes ] ; then + echo "Testing UTF-8 support (Perl compatible)" + ./pcretest $testdata/testinput4 testtry + if [ $? = 0 ] ; then + $cf testtry $testdata/testoutput4 + if [ $? != 0 ] ; then exit 1; fi + else exit 1 + fi + echo "UTF8 test ran OK" + echo " " +fi + +if [ $do5 = yes ] ; then + echo "Testing API and internals for UTF-8 support (not Perl compatible)" + ./pcretest $testdata/testinput5 testtry + if [ $? = 0 ] ; then + $cf testtry $testdata/testoutput5 + if [ $? != 0 ] ; then exit 1; fi + else exit 1 + fi + echo "UTF8 internals test ran OK" + echo " " +fi + +# End diff --git a/mk4/continuity/pcre/config.guess b/mk4/continuity/pcre/config.guess new file mode 100644 index 0000000..9b1384b --- /dev/null +++ b/mk4/continuity/pcre/config.guess @@ -0,0 +1,1400 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002 Free Software Foundation, Inc. + +timestamp='2002-11-30' + +# 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 . +# Please send patches to . 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 ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 +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. + +# This shell variable is my proudest work .. or something. --bje + +set_cc_for_build='tmpdir=${TMPDIR-/tmp}/config-guess-$$ ; +(old=`umask` && umask 077 && mkdir $tmpdir && umask $old && unset old) + || (echo "$me: cannot create $tmpdir" >&2 && exit 1) ; +dummy=$tmpdir/dummy ; +files="$dummy.c $dummy.o $dummy.rel $dummy" ; +trap '"'"'rm -f $files; rmdir $tmpdir; exit 1'"'"' 1 2 15 ; +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 ; + rm -f $files ; + 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 ; +unset files' + +# 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 ;; + amiga:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + arc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + hp300:OpenBSD:*:*) + echo m68k-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 ;; + pmax:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sgi:OpenBSD:*:*) + echo mipseb-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sun3:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + wgrisc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + *:OpenBSD:*:*) + echo ${UNAME_MACHINE}-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + alpha:OSF1:*:*) + if test $UNAME_RELEASE = "V4.0"; then + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + fi + # 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. + eval $set_cc_for_build + cat <$dummy.s + .data +\$Lformat: + .byte 37,100,45,37,120,10,0 # "%d-%x\n" + + .text + .globl main + .align 4 + .ent main +main: + .frame \$30,16,\$26,0 + ldgp \$29,0(\$27) + .prologue 1 + .long 0x47e03d80 # implver \$0 + lda \$2,-1 + .long 0x47e20c21 # amask \$2,\$1 + lda \$16,\$Lformat + mov \$0,\$17 + not \$1,\$18 + jsr \$26,printf + ldgp \$29,0(\$26) + mov 0,\$16 + jsr \$26,exit + .end main +EOF + $CC_FOR_BUILD -o $dummy $dummy.s 2>/dev/null + if test "$?" = 0 ; then + case `$dummy` in + 0-0) + UNAME_MACHINE="alpha" + ;; + 1-0) + UNAME_MACHINE="alphaev5" + ;; + 1-1) + UNAME_MACHINE="alphaev56" + ;; + 1-101) + UNAME_MACHINE="alphapca56" + ;; + 2-303) + UNAME_MACHINE="alphaev6" + ;; + 2-307) + UNAME_MACHINE="alphaev67" + ;; + 2-1307) + UNAME_MACHINE="alphaev68" + ;; + 3-1307) + UNAME_MACHINE="alphaev7" + ;; + esac + fi + rm -f $dummy.s $dummy && rmdir $tmpdir + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | 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 ;; + 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_SV: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 ;; + 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 /* 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'` \ + && rm -f $dummy.c $dummy && rmdir $tmpdir && exit 0 + rm -f $dummy.c $dummy && rmdir $tmpdir + 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 + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && rm -f $dummy.c $dummy && rmdir $tmpdir && exit 0 + rm -f $dummy.c $dummy && rmdir $tmpdir + 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 + #include + + 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` + if test -z "$HP_ARCH"; then HP_ARCH=hppa; fi + rm -f $dummy.c $dummy && rmdir $tmpdir + fi ;; + esac + 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 + 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 && rm -f $dummy.c $dummy && rmdir $tmpdir && exit 0 + rm -f $dummy.c $dummy && rmdir $tmpdir + 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*T3D:*:*:*) + echo alpha-cray-unicosmk${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 ;; + 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 ;; + 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:*:*) + # Determine whether the default compiler uses glibc. + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + #if __GLIBC__ >= 2 + LIBC=gnu + #else + LIBC= + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` + rm -f $dummy.c && rmdir $tmpdir + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`${LIBC:+-$LIBC} + 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*:3*) + echo i586-pc-interix3 + 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:*:*) + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit 0 ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit 0 ;; + arm*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + ia64: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=` + rm -f $dummy.c && rmdir $tmpdir + 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=` + rm -f $dummy.c && rmdir $tmpdir + 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 ;; + 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 + #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 +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` + rm -f $dummy.c && rmdir $tmpdir + 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: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' /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[567]*:*) + test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; + 3[34]??:*: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) + 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 + echo i586-unisys-sysv4 + exit 0 ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # 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:*:*) + echo `uname -p`-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-[DGKLNPTVW]: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 ;; +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 < +# include +#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 + 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 +# 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 && rm -f $dummy.c $dummy && rmdir $tmpdir && exit 0 +rm -f $dummy.c $dummy && rmdir $tmpdir + +# 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 < 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/mk4/continuity/pcre/config.in b/mk4/continuity/pcre/config.in new file mode 100644 index 0000000..62a594e --- /dev/null +++ b/mk4/continuity/pcre/config.in @@ -0,0 +1,70 @@ + +/* On Unix systems config.in is converted by configure into config.h. PCRE is +written in Standard C, but there are a few non-standard things it can cope +with, allowing it to run on SunOS4 and other "close to standard" systems. + +On a non-Unix system you should just copy this file into config.h, and set up +the macros the way you need them. You should normally change the definitions of +HAVE_STRERROR and HAVE_MEMMOVE to 1. Unfortunately, because of the way autoconf +works, these cannot be made the defaults. If your system has bcopy() and not +memmove(), change the definition of HAVE_BCOPY instead of HAVE_MEMMOVE. If your +system has neither bcopy() nor memmove(), leave them both as 0; an emulation +function will be used. */ + +/* Define to empty if the keyword does not work. */ + +#undef const + +/* Define to `unsigned' if doesn't define size_t. */ + +#undef size_t + +/* The following two definitions are mainly for the benefit of SunOS4, which +doesn't have the strerror() or memmove() functions that should be present in +all Standard C libraries. The macros HAVE_STRERROR and HAVE_MEMMOVE should +normally be defined with the value 1 for other systems, but unfortunately we +can't make this the default because "configure" files generated by autoconf +will only change 0 to 1; they won't change 1 to 0 if the functions are not +found. */ + +#define HAVE_STRERROR 0 +#define HAVE_MEMMOVE 0 + +/* There are some non-Unix systems that don't even have bcopy(). If this macro +is false, an emulation is used. If HAVE_MEMMOVE is set to 1, the value of +HAVE_BCOPY is not relevant. */ + +#define HAVE_BCOPY 0 + +/* The value of NEWLINE determines the newline character. The default is to +leave it up to the compiler, but some sites want to force a particular value. +On Unix systems, "configure" can be used to override this default. */ + +#ifndef NEWLINE +#define NEWLINE '\n' +#endif + +/* The value of LINK_SIZE determines the number of bytes used to store +links as offsets within the compiled regex. The default is 2, which allows for +compiled patterns up to 64K long. This covers the vast majority of cases. +However, PCRE can also be compiled to use 3 or 4 bytes instead. This allows for +longer patterns in extreme cases. On Unix systems, "configure" can be used to +override this default. */ + +#ifndef LINK_SIZE +#define LINK_SIZE 2 +#endif + +/* The value of MATCH_LIMIT determines the default number of times the match() +function can be called during a single execution of pcre_exec(). (There is a +runtime method of setting a different limit.) The limit exists in order to +catch runaway regular expressions that take for ever to determine that they do +not match. The default is set very large so that it does not accidentally catch +legitimate cases. On Unix systems, "configure" can be used to override this +default default. */ + +#ifndef MATCH_LIMIT +#define MATCH_LIMIT 10000000 +#endif + +/* End */ diff --git a/mk4/continuity/pcre/config.sub b/mk4/continuity/pcre/config.sub new file mode 100644 index 0000000..f0675aa --- /dev/null +++ b/mk4/continuity/pcre/config.sub @@ -0,0 +1,1469 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002 Free Software Foundation, Inc. + +timestamp='2002-11-30' + +# 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 . 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 ." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 +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* | freebsd*-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) + 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] \ + | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \ + | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | i370 | i860 | i960 | ia64 \ + | ip2k \ + | m32r | m68000 | m68k | m88k | mcore \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64vr | mips64vrel \ + | mips64orion | mips64orionel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mipsisa32 | mipsisa32el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | ns16k | ns32k \ + | openrisc | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ + | pyramid \ + | sh | sh[1234] | sh3e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv9 | sparcv9b \ + | strongarm \ + | tahoe | thumb | tic80 | tron \ + | v850 | v850e \ + | we32k \ + | x86 | xscale | 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-* \ + | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* \ + | clipper-* | 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-* \ + | m32r-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | mcore-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipstx39 | mipstx39el \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ + | pyramid-* \ + | romp-* | rs6000-* \ + | sh-* | sh[1234]-* | sh3e-* | sh[34]eb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \ + | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \ + | tahoe-* | thumb-* | tic30-* | tic4x-* | tic54x-* | tic80-* | tron-* \ + | v850-* | v850e-* | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xps100-* | xscale-* | 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 + ;; + 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 + ;; + 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 + ;; + crds | unos) + basic_machine=m68k-crds + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + 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 + ;; + 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 + ;; + mmix*) + basic_machine=mmix-knuth + os=-mmixware + ;; + 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 + ;; + 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) + basic_machine=i686-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-*) + basic_machine=i686-`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 + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + 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 + ;; + t3d) + basic_machine=alpha-cray + os=-unicos + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tic4x | c4x*) + basic_machine=tic4x-unknown + os=-coff + ;; + tic54x | c54x*) + basic_machine=tic54x-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 + ;; + 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 + ;; + 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 + ;; + 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 | sh3eb | sh4eb | sh[1234]le | sh3ele) + basic_machine=sh-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparc | 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. + -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* | -netbsd* | -openbsd* | -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* | -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*) + # 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*) + 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 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -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 + ;; + -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 + ;; + -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 + ;; + # 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 + ;; + *-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 + ;; + -ptx*) + vendor=sequent + ;; + -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/mk4/continuity/pcre/configure b/mk4/continuity/pcre/configure new file mode 100644 index 0000000..51ac584 --- /dev/null +++ b/mk4/continuity/pcre/configure @@ -0,0 +1,8903 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.57. +# +# Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002 +# 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 + +# Support unset when possible. +if (FOO=FOO; unset FOO) >/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 -n "`(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 + as_mkdir_p=false +fi + +as_executable_p="test -f" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="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="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 + + +# Find the correct PATH separator. Usually this is `:', but +# DJGPP uses `;' like DOS. +if test "X${PATH_SEPARATOR+set}" != Xset; then + UNAME=${UNAME-`uname 2>/dev/null`} + case X$UNAME in + *-DOS) lt_cv_sys_path_separator=';' ;; + *) lt_cv_sys_path_separator=':' ;; + esac +fi + + +# Check that we are running under the correct shell. +SHELL=${CONFIG_SHELL-/bin/sh} + +case X$ECHO in +X*--fallback-echo) + # Remove one level of quotation (which was required for Make). + ECHO=`echo "$ECHO" | sed 's,\\\\\$\\$0,'$0','` + ;; +esac + +echo=${ECHO-echo} +if test "X$1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X$1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then + # Yippee, $echo works! + : +else + # Restart under the correct shell. + exec $SHELL "$0" --no-reexec ${1+"$@"} +fi + +if test "X$1" = X--fallback-echo; then + # used as fallback echo + shift + cat </dev/null && + echo_test_string="`eval $cmd`" && + (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null + then + break + fi + done +fi + +if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + : +else + # The Solaris, AIX, and Digital Unix default echo programs unquote + # backslashes. This makes it impossible to quote backslashes using + # echo "$something" | sed 's/\\/\\\\/g' + # + # So, first we look for a working echo in the user's PATH. + + IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}" + for dir in $PATH /usr/ucb; do + if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && + test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + echo="$dir/echo" + break + fi + done + IFS="$save_ifs" + + if test "X$echo" = Xecho; then + # We didn't find a better echo, so look for alternatives. + if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # This shell has a builtin print -r that does the trick. + echo='print -r' + elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) && + test "X$CONFIG_SHELL" != X/bin/ksh; then + # If we have ksh, try running configure again with it. + ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} + export ORIGINAL_CONFIG_SHELL + CONFIG_SHELL=/bin/ksh + export CONFIG_SHELL + exec $CONFIG_SHELL "$0" --no-reexec ${1+"$@"} + else + # Try using printf. + echo='printf %s\n' + if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # Cool, printf works + : + elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL + export CONFIG_SHELL + SHELL="$CONFIG_SHELL" + export SHELL + echo="$CONFIG_SHELL $0 --fallback-echo" + elif echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + echo="$CONFIG_SHELL $0 --fallback-echo" + else + # maybe with a smaller string... + prev=: + + for cmd in 'echo test' 'sed 2q "$0"' 'sed 10q "$0"' 'sed 20q "$0"' 'sed 50q "$0"'; do + if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null + then + break + fi + prev="$cmd" + done + + if test "$prev" != 'sed 50q "$0"'; then + echo_test_string=`eval $prev` + export echo_test_string + exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "$0" ${1+"$@"} + else + # Oops. We lost completely, so just stick with echo. + echo=echo + fi + fi + fi + fi +fi +fi + +# Copy echo and quote the copy suitably for passing to libtool from +# the Makefile, instead of quoting the original, which is used later. +ECHO=$echo +if test "X$ECHO" = "X$CONFIG_SHELL $0 --fallback-echo"; then + ECHO="$CONFIG_SHELL \\\$\$0 --fallback-echo" +fi + + + +# 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= +PACKAGE_TARNAME= +PACKAGE_VERSION= +PACKAGE_STRING= +PACKAGE_BUGREPORT= + +ac_unique_file="dftables.c" +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#if HAVE_SYS_TYPES_H +# include +#endif +#if HAVE_SYS_STAT_H +# include +#endif +#if STDC_HEADERS +# include +# include +#else +# if HAVE_STDLIB_H +# include +# endif +#endif +#if HAVE_STRING_H +# if !STDC_HEADERS && HAVE_MEMORY_H +# include +# endif +# include +#endif +#if HAVE_STRINGS_H +# include +#endif +#if HAVE_INTTYPES_H +# include +#else +# if HAVE_STDINT_H +# include +# endif +#endif +#if HAVE_UNISTD_H +# include +#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 CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA build build_cpu build_vendor build_os host host_cpu host_vendor host_os LN_S ECHO RANLIB ac_ct_RANLIB STRIP ac_ct_STRIP CPP EGREP LIBTOOL BUILD_EXEEXT BUILD_OBJEXT CC_FOR_BUILD CFLAGS_FOR_BUILD HAVE_MEMMOVE HAVE_STRERROR LINK_SIZE MATCH_LIMIT NEWLINE PCRE_MAJOR PCRE_MINOR PCRE_DATE PCRE_VERSION PCRE_LIB_VERSION PCRE_POSIXLIB_VERSION POSIX_MALLOC_THRESHOLD UTF8 WIN_PREFIX ON_WINDOWS NOT_ON_WINDOWS POSIX_OBJ POSIX_LOBJ POSIX_LIB 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_CC_set=${CC+set} +ac_env_CC_value=$CC +ac_cv_env_CC_set=${CC+set} +ac_cv_env_CC_value=$CC +ac_env_CFLAGS_set=${CFLAGS+set} +ac_env_CFLAGS_value=$CFLAGS +ac_cv_env_CFLAGS_set=${CFLAGS+set} +ac_cv_env_CFLAGS_value=$CFLAGS +ac_env_LDFLAGS_set=${LDFLAGS+set} +ac_env_LDFLAGS_value=$LDFLAGS +ac_cv_env_LDFLAGS_set=${LDFLAGS+set} +ac_cv_env_LDFLAGS_value=$LDFLAGS +ac_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_env_CPPFLAGS_value=$CPPFLAGS +ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_cv_env_CPPFLAGS_value=$CPPFLAGS +ac_env_CPP_set=${CPP+set} +ac_env_CPP_value=$CPP +ac_cv_env_CPP_set=${CPP+set} +ac_cv_env_CPP_value=$CPP + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # The list generated by autoconf has been trimmed to remove many + # options that are totally irrelevant to PCRE (e.g. relating to X), + # or are not supported by its Makefile. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures this package 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] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --mandir=DIR man documentation [PREFIX/man] +_ACEOF + + cat <<\_ACEOF + +_ACEOF +fi + +if test -n "$ac_init_help"; then + + cat <<\_ACEOF + +Optional Features: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --enable-shared build shared libraries default=yes + --enable-static build static libraries default=yes + --enable-fast-install optimize for fast installation default=yes + --disable-libtool-lock avoid locking (might break parallel builds) + --enable-utf8 enable UTF8 support + --enable-newline-is-cr use CR as the newline character + --enable-newline-is-lf use LF as the newline character + +Optional Packages: + --with-gnu-ld assume the C compiler uses GNU ld default=no + --with-pic try to use only PIC/non-PIC objects default=use both + --with-posix-malloc-threshold=5 threshold for POSIX malloc usage + --with-link-size=2 internal link size (2, 3, or 4 allowed) + --with-match-limit=10000000 default limit on internal looping) + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + CPPFLAGS C/C++ preprocessor flags, e.g. -I if you have + headers in a nonstandard directory + 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. + +_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 +# Don't blindly perform a `cd "$ac_dir"/$ac_foo && pwd` since $ac_foo can be +# absolute. +ac_abs_builddir=`cd "$ac_dir" && cd $ac_builddir && pwd` +ac_abs_top_builddir=`cd "$ac_dir" && cd ${ac_top_builddir}. && pwd` +ac_abs_srcdir=`cd "$ac_dir" && cd $ac_srcdir && pwd` +ac_abs_top_srcdir=`cd "$ac_dir" && cd $ac_top_srcdir && pwd` + + 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 + +Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002 +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 $as_me, which was +generated by GNU Autoconf 2.57. 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.* *.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 config.h:config.in" + + + +PCRE_MAJOR=4 +PCRE_MINOR=3 +PCRE_DATE=21-May-2003 +PCRE_VERSION=${PCRE_MAJOR}.${PCRE_MINOR} + + +POSIX_MALLOC_THRESHOLD=-DPOSIX_MALLOC_THRESHOLD=10 + + +PCRE_LIB_VERSION=0:1:0 +PCRE_POSIXLIB_VERSION=0:0:0 + + +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 &5\"") >&5 + (eval $ac_compiler --version &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 + (eval $ac_compiler -v &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 + (eval $ac_compiler -V &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* 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" >&5 +echo $ECHO_N "checking for C compiler default output... $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 +#line $LINENO "configure" +/* 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 +#line $LINENO "configure" +/* 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>&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.$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 +#line $LINENO "configure" +/* 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>&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.$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 +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include +/* 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; +} +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>&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.$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>&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 \ + ''\ + '#include ' \ + '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 +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +$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>&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.$ac_objext conftest.$ac_ext + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* 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>&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.$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.$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_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. + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 +echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6 +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in + ./ | .// | /cC/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + done + done + ;; +esac +done + + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL=$ac_install_sh + fi +fi +echo "$as_me:$LINENO: result: $INSTALL" >&5 +echo "${ECHO_T}$INSTALL" >&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + + +# Check whether --enable-shared or --disable-shared was given. +if test "${enable_shared+set}" = set; then + enableval="$enable_shared" + p=${PACKAGE-default} +case $enableval in +yes) enable_shared=yes ;; +no) enable_shared=no ;; +*) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," + for pkg in $enableval; do + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$ac_save_ifs" + ;; +esac +else + enable_shared=yes +fi; +# Check whether --enable-static or --disable-static was given. +if test "${enable_static+set}" = set; then + enableval="$enable_static" + p=${PACKAGE-default} +case $enableval in +yes) enable_static=yes ;; +no) enable_static=no ;; +*) + enable_static=no + # Look at the argument we got. We use all the common list separators. + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," + for pkg in $enableval; do + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$ac_save_ifs" + ;; +esac +else + enable_static=yes +fi; +# Check whether --enable-fast-install or --disable-fast-install was given. +if test "${enable_fast_install+set}" = set; then + enableval="$enable_fast_install" + p=${PACKAGE-default} +case $enableval in +yes) enable_fast_install=yes ;; +no) enable_fast_install=no ;; +*) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," + for pkg in $enableval; do + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$ac_save_ifs" + ;; +esac +else + enable_fast_install=yes +fi; +# 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/'` + + + +# Check whether --with-gnu-ld or --without-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then + withval="$with_gnu_ld" + test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi; +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + echo "$as_me:$LINENO: checking for ld used by GCC" >&5 +echo $ECHO_N "checking for ld used by GCC... $ECHO_C" >&6 + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | [A-Za-z]:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the path of ld + ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + echo "$as_me:$LINENO: checking for GNU ld" >&5 +echo $ECHO_N "checking for GNU ld... $ECHO_C" >&6 +else + echo "$as_me:$LINENO: checking for non-GNU ld" >&5 +echo $ECHO_N "checking for non-GNU ld... $ECHO_C" >&6 +fi +if test "${lt_cv_path_LD+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -z "$LD"; then + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + if "$lt_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then + test "$with_gnu_ld" != no && break + else + test "$with_gnu_ld" != yes && break + fi + fi + done + IFS="$ac_save_ifs" +else + lt_cv_path_LD="$LD" # Let the user override the test with a path. +fi +fi + +LD="$lt_cv_path_LD" +if test -n "$LD"; then + echo "$as_me:$LINENO: result: $LD" >&5 +echo "${ECHO_T}$LD" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +test -z "$LD" && { { echo "$as_me:$LINENO: error: no acceptable ld found in \$PATH" >&5 +echo "$as_me: error: no acceptable ld found in \$PATH" >&2;} + { (exit 1); exit 1; }; } +echo "$as_me:$LINENO: checking if the linker ($LD) is GNU ld" >&5 +echo $ECHO_N "checking if the linker ($LD) is GNU ld... $ECHO_C" >&6 +if test "${lt_cv_prog_gnu_ld+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # I'd rather use --version here, but apparently some GNU ld's only accept -v. +if $LD -v 2>&1 &5; then + lt_cv_prog_gnu_ld=yes +else + lt_cv_prog_gnu_ld=no +fi +fi +echo "$as_me:$LINENO: result: $lt_cv_prog_gnu_ld" >&5 +echo "${ECHO_T}$lt_cv_prog_gnu_ld" >&6 +with_gnu_ld=$lt_cv_prog_gnu_ld + + +echo "$as_me:$LINENO: checking for $LD option to reload object files" >&5 +echo $ECHO_N "checking for $LD option to reload object files... $ECHO_C" >&6 +if test "${lt_cv_ld_reload_flag+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_ld_reload_flag='-r' +fi +echo "$as_me:$LINENO: result: $lt_cv_ld_reload_flag" >&5 +echo "${ECHO_T}$lt_cv_ld_reload_flag" >&6 +reload_flag=$lt_cv_ld_reload_flag +test -n "$reload_flag" && reload_flag=" $reload_flag" + +echo "$as_me:$LINENO: checking for BSD-compatible nm" >&5 +echo $ECHO_N "checking for BSD-compatible nm... $ECHO_C" >&6 +if test "${lt_cv_path_NM+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" + for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do + test -z "$ac_dir" && ac_dir=. + tmp_nm=$ac_dir/${ac_tool_prefix}nm + if test -f $tmp_nm || test -f $tmp_nm$ac_exeext ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + if ($tmp_nm -B /dev/null 2>&1 | sed '1q'; exit 0) | egrep '(/dev/null|Invalid file or object type)' >/dev/null; then + lt_cv_path_NM="$tmp_nm -B" + break + elif ($tmp_nm -p /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then + lt_cv_path_NM="$tmp_nm -p" + break + else + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + fi + fi + done + IFS="$ac_save_ifs" + test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm +fi +fi + +NM="$lt_cv_path_NM" +echo "$as_me:$LINENO: result: $NM" >&5 +echo "${ECHO_T}$NM" >&6 + +echo "$as_me:$LINENO: checking whether ln -s works" >&5 +echo $ECHO_N "checking whether ln -s works... $ECHO_C" >&6 +LN_S=$as_ln_s +if test "$LN_S" = "ln -s"; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 +else + echo "$as_me:$LINENO: result: no, using $LN_S" >&5 +echo "${ECHO_T}no, using $LN_S" >&6 +fi + +echo "$as_me:$LINENO: checking how to recognise dependant libraries" >&5 +echo $ECHO_N "checking how to recognise dependant libraries... $ECHO_C" >&6 +if test "${lt_cv_deplibs_check_method+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_file_magic_cmd='$MAGIC_CMD' +lt_cv_file_magic_test_file= +lt_cv_deplibs_check_method='unknown' +# Need to set the preceding variable on all platforms that support +# interlibrary dependencies. +# 'none' -- dependencies not supported. +# `unknown' -- same as none, but documents that we really don't know. +# 'pass_all' -- all dependencies passed with no checks. +# 'test_compile' -- check by making test program. +# ['file_magic [regex]'] -- check by looking for files in library path +# which responds to the $file_magic_cmd with a given egrep regex. +# If you have `file' or equivalent on your system and you're not sure +# whether `pass_all' will *always* work, you probably want this one. + +case $host_os in +aix4* | aix5*) + lt_cv_deplibs_check_method=pass_all + ;; + +beos*) + lt_cv_deplibs_check_method=pass_all + ;; + +bsdi4*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' + lt_cv_file_magic_cmd='/usr/bin/file -L' + lt_cv_file_magic_test_file=/shlib/libc.so + ;; + +cygwin* | mingw* | pw32*) + lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method='file_magic Mach-O dynamically linked shared library' + lt_cv_file_magic_cmd='/usr/bin/file -L' + case "$host_os" in + rhapsody* | darwin1.012) + lt_cv_file_magic_test_file=`echo /System/Library/Frameworks/System.framework/Versions/*/System | head -1` + ;; + *) # Darwin 1.3 on + lt_cv_file_magic_test_file='/usr/lib/libSystem.dylib' + ;; + esac + ;; + +freebsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD)/i[3-9]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20*|hpux11*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9].[0-9]) shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + +irix5* | irix6*) + case $host_os in + irix5*) + # this will be overridden with pass_all, but let us keep it just in case + lt_cv_deplibs_check_method="file_magic ELF 32-bit MSB dynamic lib MIPS - version 1" + ;; + *) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + # this will be overridden with pass_all, but let us keep it just in case + lt_cv_deplibs_check_method="file_magic ELF ${libmagic} MSB mips-[1234] dynamic lib MIPS - version 1" + ;; + esac + lt_cv_file_magic_test_file=`echo /lib${libsuff}/libc.so*` + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be Linux ELF. +linux-gnu*) + case $host_cpu in + alpha* | i*86 | powerpc* | sparc* | ia64* ) + lt_cv_deplibs_check_method=pass_all ;; + *) + # glibc up to 2.1.1 does not perform some relocations on ARM + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' ;; + esac + lt_cv_file_magic_test_file=`echo /lib/libc.so* /lib/libc-*.so` + ;; + +netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[^/\.]+\.so\.[0-9]+\.[0-9]+$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/\.]+\.so$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +osf3* | osf4* | osf5*) + # this will be overridden with pass_all, but let us keep it just in case + lt_cv_deplibs_check_method='file_magic COFF format alpha shared library' + lt_cv_file_magic_test_file=/shlib/libc.so + lt_cv_deplibs_check_method=pass_all + ;; + +sco3.2v5*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + lt_cv_file_magic_test_file=/lib/libc.so + ;; + +sysv5uw[78]* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + esac + ;; +esac + +fi +echo "$as_me:$LINENO: result: $lt_cv_deplibs_check_method" >&5 +echo "${ECHO_T}$lt_cv_deplibs_check_method" >&6 +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method + + + + + + + + +# Check for command to grab the raw symbol name followed by C symbol from nm. +echo "$as_me:$LINENO: checking command to parse $NM output" >&5 +echo $ECHO_N "checking command to parse $NM output... $ECHO_C" >&6 +if test "${lt_cv_sys_global_symbol_pipe+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[BCDEGRST]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([_A-Za-z][_A-Za-z0-9]*\)' + +# Transform the above into a raw symbol and a C symbol. +symxfrm='\1 \2\3 \3' + +# Transform an extracted symbol line into a proper C declaration +lt_cv_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern char \1;/p'" + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[BCDT]' + ;; +cygwin* | mingw* | pw32*) + symcode='[ABCDGISTW]' + ;; +hpux*) # Its linker distinguishes data from code symbols + lt_cv_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern char \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + ;; +irix*) + symcode='[BCDEGRST]' + ;; +solaris* | sysv5*) + symcode='[BDT]' + ;; +sysv4) + symcode='[DFNSTU]' + ;; +esac + +# Handle CRLF in mingw tool chain +opt_cr= +case $host_os in +mingw*) + opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +if $NM -V 2>&1 | egrep '(GNU|with BFD)' > /dev/null; then + symcode='[ABCDGISTW]' +fi + +# Try without a prefix undercore, then with it. +for ac_symprfx in "" "_"; do + + # Write the raw and C identifiers. +lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*\($ac_symprfx\)$sympat$opt_cr$/$symxfrm/p'" + + # Check to see that the pipe works correctly. + pipe_works=no + rm -f conftest* + cat > conftest.$ac_ext <&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Now try to grab the symbols. + nlist=conftest.nm + if { (eval echo "$as_me:$LINENO: \"$NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist\"") >&5 + (eval $NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if egrep ' nm_test_var$' "$nlist" >/dev/null; then + if egrep ' nm_test_func$' "$nlist" >/dev/null; then + cat < conftest.$ac_ext +#ifdef __cplusplus +extern "C" { +#endif + +EOF + # Now generate the symbol file. + eval "$lt_cv_global_symbol_to_cdecl"' < "$nlist" >> conftest.$ac_ext' + + cat <> conftest.$ac_ext +#if defined (__STDC__) && __STDC__ +# define lt_ptr_t void * +#else +# define lt_ptr_t char * +# define const +#endif + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + lt_ptr_t address; +} +lt_preloaded_symbols[] = +{ +EOF + sed "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (lt_ptr_t) \&\2},/" < "$nlist" >> conftest.$ac_ext + cat <<\EOF >> conftest.$ac_ext + {0, (lt_ptr_t) 0} +}; + +#ifdef __cplusplus +} +#endif +EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + save_LIBS="$LIBS" + save_CFLAGS="$CFLAGS" + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$no_builtin_flag" + 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); } && test -s conftest; then + pipe_works=yes + fi + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" + else + echo "cannot find nm_test_func in $nlist" >&5 + fi + else + echo "cannot find nm_test_var in $nlist" >&5 + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 + fi + else + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + fi + rm -f conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done + +fi + +global_symbol_pipe="$lt_cv_sys_global_symbol_pipe" +if test -z "$lt_cv_sys_global_symbol_pipe"; then + global_symbol_to_cdecl= +else + global_symbol_to_cdecl="$lt_cv_global_symbol_to_cdecl" +fi +if test -z "$global_symbol_pipe$global_symbol_to_cdecl"; then + echo "$as_me:$LINENO: result: failed" >&5 +echo "${ECHO_T}failed" >&6 +else + echo "$as_me:$LINENO: result: ok" >&5 +echo "${ECHO_T}ok" >&6 +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 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 to if __STDC__ is defined, since + # 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 +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#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 + 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 +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_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 + 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 to if __STDC__ is defined, since + # 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 +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#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 + 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 +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_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 + 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 +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +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); } && + { 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.$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 +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_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 +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_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 +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#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.* *.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 +#line $LINENO "configure" +/* 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>&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.$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 dlfcn.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 +#line $LINENO "configure" +/* 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>&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.$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 +#line $LINENO "configure" +/* 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 + 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 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 preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------ ## +## Report this to bug-autoconf@gnu.org. ## +## ------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; + 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: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------ ## +## Report this to bug-autoconf@gnu.org. ## +## ------------------------------------ ## +_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 + + + + + +# Only perform the check for file, if the check method requires it +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + echo "$as_me:$LINENO: checking for ${ac_tool_prefix}file" >&5 +echo $ECHO_N "checking for ${ac_tool_prefix}file... $ECHO_C" >&6 +if test "${lt_cv_path_MAGIC_CMD+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + case $MAGIC_CMD in + /*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; + ?:/*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a dos path. + ;; + *) + ac_save_MAGIC_CMD="$MAGIC_CMD" + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="/usr/bin:$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/${ac_tool_prefix}file; then + lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`" + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + egrep "$file_magic_regex" > /dev/null; then + : + else + cat <&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +EOF + fi ;; + esac + fi + break + fi + done + IFS="$ac_save_ifs" + MAGIC_CMD="$ac_save_MAGIC_CMD" + ;; +esac +fi + +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + echo "$as_me:$LINENO: result: $MAGIC_CMD" >&5 +echo "${ECHO_T}$MAGIC_CMD" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + echo "$as_me:$LINENO: checking for file" >&5 +echo $ECHO_N "checking for file... $ECHO_C" >&6 +if test "${lt_cv_path_MAGIC_CMD+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + case $MAGIC_CMD in + /*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; + ?:/*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a dos path. + ;; + *) + ac_save_MAGIC_CMD="$MAGIC_CMD" + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="/usr/bin:$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/file; then + lt_cv_path_MAGIC_CMD="$ac_dir/file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`" + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + egrep "$file_magic_regex" > /dev/null; then + : + else + cat <&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +EOF + fi ;; + esac + fi + break + fi + done + IFS="$ac_save_ifs" + MAGIC_CMD="$ac_save_MAGIC_CMD" + ;; +esac +fi + +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + echo "$as_me:$LINENO: result: $MAGIC_CMD" >&5 +echo "${ECHO_T}$MAGIC_CMD" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + else + MAGIC_CMD=: + fi +fi + + fi + ;; +esac + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; 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_RANLIB+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # 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_RANLIB="${ac_tool_prefix}ranlib" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + echo "$as_me:$LINENO: result: $RANLIB" >&5 +echo "${ECHO_T}$RANLIB" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; 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_RANLIB+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # 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_RANLIB="ranlib" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + test -z "$ac_cv_prog_ac_ct_RANLIB" && ac_cv_prog_ac_ct_RANLIB=":" +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5 +echo "${ECHO_T}$ac_ct_RANLIB" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + RANLIB=$ac_ct_RANLIB +else + RANLIB="$ac_cv_prog_RANLIB" +fi + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; 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_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # 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_STRIP="${ac_tool_prefix}strip" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + echo "$as_me:$LINENO: result: $STRIP" >&5 +echo "${ECHO_T}$STRIP" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; 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_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # 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_STRIP="strip" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + test -z "$ac_cv_prog_ac_ct_STRIP" && ac_cv_prog_ac_ct_STRIP=":" +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5 +echo "${ECHO_T}$ac_ct_STRIP" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + STRIP=$ac_ct_STRIP +else + STRIP="$ac_cv_prog_STRIP" +fi + + +enable_dlopen=no +enable_win32_dll=no + +# Check whether --enable-libtool-lock or --disable-libtool-lock was given. +if test "${enable_libtool_lock+set}" = set; then + enableval="$enable_libtool_lock" + +fi; +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +*-*-irix6*) + # Find out which ABI we are using. + echo '#line 4012 "configure"' > conftest.$ac_ext + 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 + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + echo "$as_me:$LINENO: checking whether the C compiler needs -belf" >&5 +echo $ECHO_N "checking whether the C compiler needs -belf... $ECHO_C" >&6 +if test "${lt_cv_cc_needs_belf+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + + + 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 + + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* 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 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='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 + lt_cv_cc_needs_belf=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +lt_cv_cc_needs_belf=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext 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 + +fi +echo "$as_me:$LINENO: result: $lt_cv_cc_needs_belf" >&5 +echo "${ECHO_T}$lt_cv_cc_needs_belf" >&6 + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; + + +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='sed -e s/^X//' +sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Constants: +rm="rm -f" + +# Global variables: +default_ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except M$VC, +# which needs '.lib'). +libext=a +ltmain="$ac_aux_dir/ltmain.sh" +ofile="$default_ofile" +with_gnu_ld="$lt_cv_prog_gnu_ld" +need_locks="$enable_libtool_lock" + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$AR" && AR=ar +test -z "$AR_FLAGS" && AR_FLAGS=cru +test -z "$AS" && AS=as +test -z "$CC" && CC=cc +test -z "$DLLTOOL" && DLLTOOL=dlltool +test -z "$LD" && LD=ld +test -z "$LN_S" && LN_S="ln -s" +test -z "$MAGIC_CMD" && MAGIC_CMD=file +test -z "$NM" && NM=nm +test -z "$OBJDUMP" && OBJDUMP=objdump +test -z "$RANLIB" && RANLIB=: +test -z "$STRIP" && STRIP=: +test -z "$ac_objext" && ac_objext=o + +if test x"$host" != x"$build"; then + ac_tool_prefix=${host_alias}- +else + ac_tool_prefix= +fi + +# Transform linux* to *-*-linux-gnu*, to support old configure scripts. +case $host_os in +linux-gnu*) ;; +linux*) host=`echo $host | sed 's/^\(.*-.*-linux\)\(.*\)$/\1-gnu\2/'` +esac + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" + old_postinstall_cmds="\$RANLIB \$oldlib~$old_postinstall_cmds" +fi + +# Allow CC to be a program name with arguments. +set dummy $CC +compiler="$2" + +## FIXME: this should be a separate macro +## +echo "$as_me:$LINENO: checking for objdir" >&5 +echo $ECHO_N "checking for objdir... $ECHO_C" >&6 +rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + objdir=_libs +fi +rmdir .libs 2>/dev/null +echo "$as_me:$LINENO: result: $objdir" >&5 +echo "${ECHO_T}$objdir" >&6 +## +## END FIXME + + +## FIXME: this should be a separate macro +## + +# Check whether --with-pic or --without-pic was given. +if test "${with_pic+set}" = set; then + withval="$with_pic" + pic_mode="$withval" +else + pic_mode=default +fi; +test -z "$pic_mode" && pic_mode=default + +# We assume here that the value for lt_cv_prog_cc_pic will not be cached +# in isolation, and that seeing it set (from the cache) indicates that +# the associated values are set (in the cache) correctly too. +echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5 +echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6 +if test "${lt_cv_prog_cc_pic+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_prog_cc_pic= + lt_cv_prog_cc_shlib= + lt_cv_prog_cc_wl= + lt_cv_prog_cc_static= + lt_cv_prog_cc_no_builtin= + lt_cv_prog_cc_can_build_shared=$can_build_shared + + if test "$GCC" = yes; then + lt_cv_prog_cc_wl='-Wl,' + lt_cv_prog_cc_static='-static' + + case $host_os in + aix*) + # Below there is a dirty hack to force normal static linking with -ldl + # The problem is because libdl dynamically linked with both libc and + # libC (AIX C++ library), which obviously doesn't included in libraries + # list by gcc. This cause undefined symbols with -static flags. + # This hack allows C programs to be linked with "-static -ldl", but + # we not sure about C++ programs. + lt_cv_prog_cc_static="$lt_cv_prog_cc_static ${lt_cv_prog_cc_wl}-lC" + ;; + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + lt_cv_prog_cc_pic='-m68020 -resident32 -malways-restore-a4' + ;; + beos* | irix5* | irix6* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_cv_prog_cc_pic='-fno-common' + ;; + cygwin* | mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_cv_prog_cc_pic='-DDLL_EXPORT' + ;; + sysv4*MP*) + if test -d /usr/nec; then + lt_cv_prog_cc_pic=-Kconform_pic + fi + ;; + *) + lt_cv_prog_cc_pic='-fPIC' + ;; + esac + else + # PORTME Check for PIC flags for the system compiler. + case $host_os in + aix3* | aix4* | aix5*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_cv_prog_cc_static='-Bstatic' + lt_cv_prog_cc_wl='-Wl,' + else + lt_cv_prog_cc_static='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + hpux9* | hpux10* | hpux11*) + # Is there a better lt_cv_prog_cc_static that works with the bundled CC? + lt_cv_prog_cc_wl='-Wl,' + lt_cv_prog_cc_static="${lt_cv_prog_cc_wl}-a ${lt_cv_prog_cc_wl}archive" + lt_cv_prog_cc_pic='+Z' + ;; + + irix5* | irix6*) + lt_cv_prog_cc_wl='-Wl,' + lt_cv_prog_cc_static='-non_shared' + # PIC (with -KPIC) is the default. + ;; + + cygwin* | mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_cv_prog_cc_pic='-DDLL_EXPORT' + ;; + + newsos6) + lt_cv_prog_cc_pic='-KPIC' + lt_cv_prog_cc_static='-Bstatic' + ;; + + osf3* | osf4* | osf5*) + # All OSF/1 code is PIC. + lt_cv_prog_cc_wl='-Wl,' + lt_cv_prog_cc_static='-non_shared' + ;; + + sco3.2v5*) + lt_cv_prog_cc_pic='-Kpic' + lt_cv_prog_cc_static='-dn' + lt_cv_prog_cc_shlib='-belf' + ;; + + solaris*) + lt_cv_prog_cc_pic='-KPIC' + lt_cv_prog_cc_static='-Bstatic' + lt_cv_prog_cc_wl='-Wl,' + ;; + + sunos4*) + lt_cv_prog_cc_pic='-PIC' + lt_cv_prog_cc_static='-Bstatic' + lt_cv_prog_cc_wl='-Qoption ld ' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + lt_cv_prog_cc_pic='-KPIC' + lt_cv_prog_cc_static='-Bstatic' + if test "x$host_vendor" = xsni; then + lt_cv_prog_cc_wl='-LD' + else + lt_cv_prog_cc_wl='-Wl,' + fi + ;; + + uts4*) + lt_cv_prog_cc_pic='-pic' + lt_cv_prog_cc_static='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + lt_cv_prog_cc_pic='-Kconform_pic' + lt_cv_prog_cc_static='-Bstatic' + fi + ;; + + *) + lt_cv_prog_cc_can_build_shared=no + ;; + esac + fi + +fi + +if test -z "$lt_cv_prog_cc_pic"; then + echo "$as_me:$LINENO: result: none" >&5 +echo "${ECHO_T}none" >&6 +else + echo "$as_me:$LINENO: result: $lt_cv_prog_cc_pic" >&5 +echo "${ECHO_T}$lt_cv_prog_cc_pic" >&6 + + # Check to make sure the pic_flag actually works. + echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_cv_prog_cc_pic works" >&5 +echo $ECHO_N "checking if $compiler PIC flag $lt_cv_prog_cc_pic works... $ECHO_C" >&6 + if test "${lt_cv_prog_cc_pic_works+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $lt_cv_prog_cc_pic -DPIC" + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* 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>&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 + case $host_os in + hpux9* | hpux10* | hpux11*) + # On HP-UX, both CC and GCC only warn that PIC is supported... then + # they create non-PIC objects. So, if there were any warnings, we + # assume that PIC is not supported. + if test -s conftest.err; then + lt_cv_prog_cc_pic_works=no + else + lt_cv_prog_cc_pic_works=yes + fi + ;; + *) + lt_cv_prog_cc_pic_works=yes + ;; + esac + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + lt_cv_prog_cc_pic_works=no + +fi +rm -f conftest.$ac_objext conftest.$ac_ext + CFLAGS="$save_CFLAGS" + +fi + + + if test "X$lt_cv_prog_cc_pic_works" = Xno; then + lt_cv_prog_cc_pic= + lt_cv_prog_cc_can_build_shared=no + else + lt_cv_prog_cc_pic=" $lt_cv_prog_cc_pic" + fi + + echo "$as_me:$LINENO: result: $lt_cv_prog_cc_pic_works" >&5 +echo "${ECHO_T}$lt_cv_prog_cc_pic_works" >&6 +fi +## +## END FIXME + +# Check for any special shared library compilation flags. +if test -n "$lt_cv_prog_cc_shlib"; then + { echo "$as_me:$LINENO: WARNING: \`$CC' requires \`$lt_cv_prog_cc_shlib' to build shared libraries" >&5 +echo "$as_me: WARNING: \`$CC' requires \`$lt_cv_prog_cc_shlib' to build shared libraries" >&2;} + if echo "$old_CC $old_CFLAGS " | egrep -e "[ ]$lt_cv_prog_cc_shlib[ ]" >/dev/null; then : + else + { echo "$as_me:$LINENO: WARNING: add \`$lt_cv_prog_cc_shlib' to the CC or CFLAGS env variable and reconfigure" >&5 +echo "$as_me: WARNING: add \`$lt_cv_prog_cc_shlib' to the CC or CFLAGS env variable and reconfigure" >&2;} + lt_cv_prog_cc_can_build_shared=no + fi +fi + +## FIXME: this should be a separate macro +## +echo "$as_me:$LINENO: checking if $compiler static flag $lt_cv_prog_cc_static works" >&5 +echo $ECHO_N "checking if $compiler static flag $lt_cv_prog_cc_static works... $ECHO_C" >&6 +if test "${lt_cv_prog_cc_static_works+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_prog_cc_static_works=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $lt_cv_prog_cc_static" + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* 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 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='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 + lt_cv_prog_cc_static_works=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext + LDFLAGS="$save_LDFLAGS" + +fi + + +# Belt *and* braces to stop my trousers falling down: +test "X$lt_cv_prog_cc_static_works" = Xno && lt_cv_prog_cc_static= +echo "$as_me:$LINENO: result: $lt_cv_prog_cc_static_works" >&5 +echo "${ECHO_T}$lt_cv_prog_cc_static_works" >&6 + +pic_flag="$lt_cv_prog_cc_pic" +special_shlib_compile_flags="$lt_cv_prog_cc_shlib" +wl="$lt_cv_prog_cc_wl" +link_static_flag="$lt_cv_prog_cc_static" +no_builtin_flag="$lt_cv_prog_cc_no_builtin" +can_build_shared="$lt_cv_prog_cc_can_build_shared" +## +## END FIXME + + +## FIXME: this should be a separate macro +## +# Check to see if options -o and -c are simultaneously supported by compiler +echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5 +echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6 +if test "${lt_cv_compiler_c_o+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + +$rm -r conftest 2>/dev/null +mkdir conftest +cd conftest +echo "int some_variable = 0;" > conftest.$ac_ext +mkdir out +# According to Tom Tromey, Ian Lance Taylor reported there are C compilers +# that will create temporary files in the current directory regardless of +# the output directory. Thus, making CWD read-only will cause this test +# to fail, enabling locking or at least warning the user not to do parallel +# builds. +chmod -w . +save_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -o out/conftest2.$ac_objext" +compiler_c_o=no +if { (eval echo configure:4552: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>out/conftest.err; } && test -s out/conftest2.$ac_objext; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s out/conftest.err; then + lt_cv_compiler_c_o=no + else + lt_cv_compiler_c_o=yes + fi +else + # Append any errors to the config.log. + cat out/conftest.err 1>&5 + lt_cv_compiler_c_o=no +fi +CFLAGS="$save_CFLAGS" +chmod u+w . +$rm conftest* out/* +rmdir out +cd .. +rmdir conftest +$rm -r conftest 2>/dev/null + +fi + +compiler_c_o=$lt_cv_compiler_c_o +echo "$as_me:$LINENO: result: $compiler_c_o" >&5 +echo "${ECHO_T}$compiler_c_o" >&6 + +if test x"$compiler_c_o" = x"yes"; then + # Check to see if we can write to a .lo + echo "$as_me:$LINENO: checking if $compiler supports -c -o file.lo" >&5 +echo $ECHO_N "checking if $compiler supports -c -o file.lo... $ECHO_C" >&6 + if test "${lt_cv_compiler_o_lo+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + + lt_cv_compiler_o_lo=no + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -c -o conftest.lo" + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +int some_variable = 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +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); } && + { 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 + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + lt_cv_compiler_o_lo=no + else + lt_cv_compiler_o_lo=yes + fi + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.$ac_objext conftest.$ac_ext + CFLAGS="$save_CFLAGS" + +fi + + compiler_o_lo=$lt_cv_compiler_o_lo + echo "$as_me:$LINENO: result: $compiler_c_lo" >&5 +echo "${ECHO_T}$compiler_c_lo" >&6 +else + compiler_o_lo=no +fi +## +## END FIXME + +## FIXME: this should be a separate macro +## +# Check to see if we can do hard links to lock some files if needed +hard_links="nottested" +if test "$compiler_c_o" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + echo "$as_me:$LINENO: checking if we can lock with hard links" >&5 +echo $ECHO_N "checking if we can lock with hard links... $ECHO_C" >&6 + hard_links=yes + $rm conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + echo "$as_me:$LINENO: result: $hard_links" >&5 +echo "${ECHO_T}$hard_links" >&6 + if test "$hard_links" = no; then + { echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 +echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi +## +## END FIXME + +## FIXME: this should be a separate macro +## +if test "$GCC" = yes; then + # Check to see if options -fno-rtti -fno-exceptions are supported by compiler + echo "$as_me:$LINENO: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 +echo $ECHO_N "checking if $compiler supports -fno-rtti -fno-exceptions... $ECHO_C" >&6 + echo "int some_variable = 0;" > conftest.$ac_ext + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -fno-rtti -fno-exceptions -c conftest.$ac_ext" + compiler_rtti_exceptions=no + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +int some_variable = 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +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); } && + { 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 + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + compiler_rtti_exceptions=no + else + compiler_rtti_exceptions=yes + fi + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.$ac_objext conftest.$ac_ext + CFLAGS="$save_CFLAGS" + echo "$as_me:$LINENO: result: $compiler_rtti_exceptions" >&5 +echo "${ECHO_T}$compiler_rtti_exceptions" >&6 + + if test "$compiler_rtti_exceptions" = "yes"; then + no_builtin_flag=' -fno-builtin -fno-rtti -fno-exceptions' + else + no_builtin_flag=' -fno-builtin' + fi +fi +## +## END FIXME + +## FIXME: this should be a separate macro +## +# See if the linker supports building shared libraries. +echo "$as_me:$LINENO: checking whether the linker ($LD) supports shared libraries" >&5 +echo $ECHO_N "checking whether the linker ($LD) supports shared libraries... $ECHO_C" >&6 + +allow_undefined_flag= +no_undefined_flag= +need_lib_prefix=unknown +need_version=unknown +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +archive_cmds= +archive_expsym_cmds= +old_archive_from_new_cmds= +old_archive_from_expsyms_cmds= +export_dynamic_flag_spec= +whole_archive_flag_spec= +thread_safe_flag_spec= +hardcode_into_libs=no +hardcode_libdir_flag_spec= +hardcode_libdir_separator= +hardcode_direct=no +hardcode_minus_L=no +hardcode_shlibpath_var=unsupported +runpath_var= +link_all_deplibs=unknown +always_export_symbols=no +export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | sed '\''s/.* //'\'' | sort | uniq > $export_symbols' +# include_expsyms should be a list of space-separated symbols to be *always* +# included in the symbol list +include_expsyms= +# exclude_expsyms can be an egrep regular expression of symbols to exclude +# it will be wrapped by ` (' and `)$', so one must not match beginning or +# end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', +# as well as any symbol that contains `d'. +exclude_expsyms="_GLOBAL_OFFSET_TABLE_" +# Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out +# platforms (ab)use it in PIC code, but their linkers get confused if +# the symbol is explicitly referenced. Since portable code cannot +# rely on this symbol name, it's probably fine to never include it in +# preloaded symbol tables. +extract_expsyms_cmds= + +case $host_os in +cygwin* | mingw* | pw32* ) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + +esac + +ld_shlibs=yes +if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # See if GNU ld supports shared libraries. + case $host_os in + aix3* | aix4* | aix5*) + # On AIX, the GNU linker is very broken + # Note:Check GNU linker on AIX 5-IA64 when/if it becomes available. + ld_shlibs=no + cat <&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +EOF + ;; + + amigaos*) + archive_cmds='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + + # Samuel A. Falvo II reports + # that the semantics of dynamic libraries on AmigaOS, at least up + # to version 4, is to share data among multiple programs linked + # with the same dynamic library. Since this doesn't match the + # behavior of shared libraries on other platforms, we can use + # them. + ld_shlibs=no + ;; + + beos*) + if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs=no + fi + ;; + + cygwin* | mingw* | pw32*) + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec='-L$libdir' + allow_undefined_flag=unsupported + always_export_symbols=yes + + extract_expsyms_cmds='test -f $output_objdir/impgen.c || \ + sed -e "/^# \/\* impgen\.c starts here \*\//,/^# \/\* impgen.c ends here \*\// { s/^# //;s/^# *$//; p; }" -e d < $''0 > $output_objdir/impgen.c~ + test -f $output_objdir/impgen.exe || (cd $output_objdir && \ + if test "x$HOST_CC" != "x" ; then $HOST_CC -o impgen impgen.c ; \ + else $CC -o impgen impgen.c ; fi)~ + $output_objdir/impgen $dir/$soroot > $output_objdir/$soname-def' + + old_archive_from_expsyms_cmds='$DLLTOOL --as=$AS --dllname $soname --def $output_objdir/$soname-def --output-lib $output_objdir/$newlib' + + # cygwin and mingw dlls have different entry points and sets of symbols + # to exclude. + # FIXME: what about values for MSVC? + dll_entry=__cygwin_dll_entry@12 + dll_exclude_symbols=DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12~ + case $host_os in + mingw*) + # mingw values + dll_entry=_DllMainCRTStartup@12 + dll_exclude_symbols=DllMain@12,DllMainCRTStartup@12,DllEntryPoint@12~ + ;; + esac + + # mingw and cygwin differ, and it's simplest to just exclude the union + # of the two symbol sets. + dll_exclude_symbols=DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12,DllMainCRTStartup@12,DllEntryPoint@12 + + # recent cygwin and mingw systems supply a stub DllMain which the user + # can override, but on older systems we have to supply one (in ltdll.c) + if test "x$lt_cv_need_dllmain" = "xyes"; then + ltdll_obj='$output_objdir/$soname-ltdll.'"$ac_objext " + ltdll_cmds='test -f $output_objdir/$soname-ltdll.c || sed -e "/^# \/\* ltdll\.c starts here \*\//,/^# \/\* ltdll.c ends here \*\// { s/^# //; p; }" -e d < [$]0 > $output_objdir/$soname-ltdll.c~ + test -f $output_objdir/$soname-ltdll.$ac_objext || (cd $output_objdir && $CC -c $soname-ltdll.c)~' + else + ltdll_obj= + ltdll_cmds= + fi + + # Extract the symbol export list from an `--export-all' def file, + # then regenerate the def file from the symbol export list, so that + # the compiled dll only exports the symbol export list. + # Be careful not to strip the DATA tag left be newer dlltools. + export_symbols_cmds="$ltdll_cmds"' + $DLLTOOL --export-all --exclude-symbols '$dll_exclude_symbols' --output-def $output_objdir/$soname-def '$ltdll_obj'$libobjs $convenience~ + sed -e "1,/EXPORTS/d" -e "s/ @ [0-9]*//" -e "s/ *;.*$//" < $output_objdir/$soname-def > $export_symbols' + + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is. + # If DATA tags from a recent dlltool are present, honour them! + archive_expsym_cmds='if test "x`head -1 $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname-def; + else + echo EXPORTS > $output_objdir/$soname-def; + _lt_hint=1; + cat $export_symbols | while read symbol; do + set dummy \$symbol; + case \$# in + 2) echo " \$2 @ \$_lt_hint ; " >> $output_objdir/$soname-def;; + *) echo " \$2 @ \$_lt_hint \$3 ; " >> $output_objdir/$soname-def;; + esac; + _lt_hint=`expr 1 + \$_lt_hint`; + done; + fi~ + '"$ltdll_cmds"' + $CC -Wl,--base-file,$output_objdir/$soname-base '$lt_cv_cc_dll_switch' -Wl,-e,'$dll_entry' -o $output_objdir/$soname '$ltdll_obj'$libobjs $deplibs $compiler_flags~ + $DLLTOOL --as=$AS --dllname $soname --exclude-symbols '$dll_exclude_symbols' --def $output_objdir/$soname-def --base-file $output_objdir/$soname-base --output-exp $output_objdir/$soname-exp~ + $CC -Wl,--base-file,$output_objdir/$soname-base $output_objdir/$soname-exp '$lt_cv_cc_dll_switch' -Wl,-e,'$dll_entry' -o $output_objdir/$soname '$ltdll_obj'$libobjs $deplibs $compiler_flags~ + $DLLTOOL --as=$AS --dllname $soname --exclude-symbols '$dll_exclude_symbols' --def $output_objdir/$soname-def --base-file $output_objdir/$soname-base --output-exp $output_objdir/$soname-exp --output-lib $output_objdir/$libname.dll.a~ + $CC $output_objdir/$soname-exp '$lt_cv_cc_dll_switch' -Wl,-e,'$dll_entry' -o $output_objdir/$soname '$ltdll_obj'$libobjs $deplibs $compiler_flags' + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + archive_cmds='$CC -shared -nodefaultlibs $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared -nodefaultlibs $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris* | sysv5*) + if $LD -v 2>&1 | egrep 'BFD 2\.8' > /dev/null; then + ld_shlibs=no + cat <&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +EOF + elif $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + + sunos4*) + archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + *) + if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + + if test "$ld_shlibs" = yes; then + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec='${wl}--rpath ${wl}$libdir' + export_dynamic_flag_spec='${wl}--export-dynamic' + case $host_os in + cygwin* | mingw* | pw32*) + # dlltool doesn't understand --whole-archive et. al. + whole_archive_flag_spec= + ;; + *) + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | egrep 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec= + fi + ;; + esac + fi +else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + allow_undefined_flag=unsupported + always_export_symbols=yes + archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L=yes + if test "$GCC" = yes && test -z "$link_static_flag"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct=unsupported + fi + ;; + + aix4* | aix5*) + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds='' + hardcode_libdir_separator=':' + if test "$GCC" = yes; then + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + hardcode_direct=yes + else + # We have old collect2 + hardcode_direct=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L=yes + hardcode_libdir_flag_spec='-L$libdir' + hardcode_libdir_separator= + fi + shared_flag='-shared' + else + if test "$host_cpu" = ia64; then + shared_flag='-G' + else + shared_flag='${wl}-bM:SRE' + fi + hardcode_direct=yes + fi + + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # Test if we are trying to use run time linking, or normal AIX style linking. + # If -brtl is somewhere in LDFLAGS, we need to do run time linking. + aix_use_runtimelinking=no + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl" ); then + aix_use_runtimelinking=yes + break + fi + done + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + # It seems that -bexpall can do strange things, so it is better to + # generate a list of symbols to export. + always_export_symbols=yes + if test "$aix_use_runtimelinking" = yes; then + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:/usr/lib:/lib' + allow_undefined_flag=' -Wl,-G' + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag="-znodefs" + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname ${wl}-h$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols" + else + hardcode_libdir_flag_spec='${wl}-bnolibpath ${wl}-blibpath:$libdir:/usr/lib:/lib' + # Warning - without using the other run time loading flags, -berok will + # link without error, but may produce a broken library. + allow_undefined_flag='${wl}-berok" + # This is a bit strange, but is similar to how AIX traditionally builds + # it's shared libraries. + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols"' ~$AR -crlo $objdir/$libname$release.a $objdir/$soname' + fi + fi + ;; + + amigaos*) + archive_cmds='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + # see comment about different semantics on the GNU ld section + ld_shlibs=no + ;; + + cygwin* | mingw* | pw32*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec=' ' + allow_undefined_flag=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # FIXME: Setting linknames here is a bad hack. + archive_cmds='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | sed -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + old_archive_from_new_cmds='true' + # FIXME: Should let the user specify the lib program. + old_archive_cmds='lib /OUT:$oldlib$oldobjs$old_deplibs' + fix_srcfile_path='`cygpath -w "$srcfile"`' + ;; + + darwin* | rhapsody*) + # This patch put in by hand by PH (22-May-2003) for Darwin 1.3. + case "$host_os" in + rhapsody* | darwin1.[[012]]) + allow_undefined_flag='-undefined suppress' + ;; + *) # Darwin 1.3 on + allow_undefined_flag='-flat_namespace -undefined suppress' + ;; + esac + # End of hand-inserted patch + + # FIXME: Relying on posixy $() will cause problems for + # cross-compilation, but unfortunately the echo tests do not + # yet detect zsh echo's removal of \ escapes. + archive_cmds='$CC $(test .$module = .yes && echo -bundle || echo -dynamiclib) $allow_undefined_flag -o $lib $libobjs $deplibs$linkopts -install_name $rpath/$soname $(test -n "$verstring" -a x$verstring != x0.0 && echo $verstring)' + # We need to add '_' to the symbols in $export_symbols first + #archive_expsym_cmds="$archive_cmds"' && strip -s $export_symbols' + hardcode_direct=yes + hardcode_shlibpath_var=no + whole_archive_flag_spec='-all_load $convenience' + ;; + + freebsd1*) + ld_shlibs=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd*) + archive_cmds='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + hpux9* | hpux10* | hpux11*) + case $host_os in + hpux9*) archive_cmds='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' ;; + *) archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' ;; + esac + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + hardcode_minus_L=yes # Not in the search PATH, but as the default + # location of the library. + export_dynamic_flag_spec='${wl}-E' + ;; + + irix5* | irix6*) + if test "$GCC" = yes; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + fi + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + link_all_deplibs=yes + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + newsos6) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts' + hardcode_direct=yes + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_shlibpath_var=no + ;; + + openbsd*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + allow_undefined_flag=unsupported + archive_cmds='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + fi + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds='for i in `cat $export_symbols`; do printf "-exported_symbol " >> $lib.exp; echo "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ + $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib~$rm $lib.exp' + + #Both c and cxx compiler support -rpath directly + hardcode_libdir_flag_spec='-rpath $libdir' + fi + hardcode_libdir_separator=: + ;; + + sco3.2v5*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ;; + + solaris*) + no_undefined_flag=' -z defs' + # $CC -shared without GNU ld will not create a library from C++ + # object files and a static libstdc++, better avoid it by now + archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_shlibpath_var=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) # Supported since Solaris 2.6 (maybe 2.5.1?) + whole_archive_flag_spec='-z allextract$convenience -z defaultextract' ;; + esac + link_all_deplibs=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + sysv4) + if test "x$host_vendor" = xsno; then + archive_cmds='$LD -G -Bsymbolic -h $soname -o $lib $libobjs $deplibs $linkopts' + hardcode_direct=yes # is this really true??? + else + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=no #Motorola manual says yes, but my tests say they lie + fi + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var=no + ;; + + sysv4.3*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + export_dynamic_flag_spec='-Bexport' + ;; + + sysv5*) + no_undefined_flag=' -z text' + # $CC -shared without GNU ld will not create a library from C++ + # object files and a static libstdc++, better avoid it by now + archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' + hardcode_libdir_flag_spec= + hardcode_shlibpath_var=no + runpath_var='LD_RUN_PATH' + ;; + + uts4*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + dgux*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + sysv4*MP*) + if test -d /usr/nec; then + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ld_shlibs=yes + fi + ;; + + sysv4.2uw2*) + archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_minus_L=no + hardcode_shlibpath_var=no + hardcode_runpath_var=yes + runpath_var=LD_RUN_PATH + ;; + + sysv5uw7* | unixware7*) + no_undefined_flag='${wl}-z ${wl}text' + if test "$GCC" = yes; then + archive_cmds='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var=no + ;; + + *) + ld_shlibs=no + ;; + esac +fi +echo "$as_me:$LINENO: result: $ld_shlibs" >&5 +echo "${ECHO_T}$ld_shlibs" >&6 +test "$ld_shlibs" = no && can_build_shared=no +## +## END FIXME + +## FIXME: this should be a separate macro +## +# Check hardcoding attributes. +echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5 +echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&6 +hardcode_action= +if test -n "$hardcode_libdir_flag_spec" || \ + test -n "$runpath_var"; then + + # We can hardcode non-existant directories. + if test "$hardcode_direct" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$hardcode_shlibpath_var" != no && + test "$hardcode_minus_L" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action=unsupported +fi +echo "$as_me:$LINENO: result: $hardcode_action" >&5 +echo "${ECHO_T}$hardcode_action" >&6 +## +## END FIXME + +## FIXME: this should be a separate macro +## +striplib= +old_striplib= +echo "$as_me:$LINENO: checking whether stripping libraries is possible" >&5 +echo $ECHO_N "checking whether stripping libraries is possible... $ECHO_C" >&6 +if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +## +## END FIXME + +reload_cmds='$LD$reload_flag -o $output$reload_objs' +test -z "$deplibs_check_method" && deplibs_check_method=unknown + +## FIXME: this should be a separate macro +## +# PORTME Fill in your ld.so characteristics +echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5 +echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6 +library_names_spec= +libname_spec='lib$name' +soname_spec= +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}.so$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}.so$major' + ;; + +aix4* | aix5*) + version_type=linux + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}.so$major ${libname}${release}.so$versuffix $libname.so' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so instead of + # lib.a to let people know that these are not typical AIX shared libraries. + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}.so$major' + fi + shlibpath_var=LIBPATH + deplibs_check_method=pass_all + fi + ;; + +amigaos*) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "(cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a)"; (cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a) || exit 1; done' + ;; + +beos*) + library_names_spec='${libname}.so' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi4*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + export_dynamic_flag_spec=-rdynamic + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32*) + version_type=windows + need_version=no + need_lib_prefix=no + case $GCC,$host_os in + yes,cygwin*) + library_names_spec='$libname.dll.a' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | sed -e 's/[.]/-/g'`${versuffix}.dll' + postinstall_cmds='dlpath=`bash 2>&1 -c '\''. $dir/${file}i;echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog .libs/$dlname \$dldir/$dlname' + postuninstall_cmds='dldll=`bash 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $rm \$dlpath' + ;; + yes,mingw*) + library_names_spec='${libname}`echo ${release} | sed -e 's/[.]/-/g'`${versuffix}.dll' + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | sed -e "s/^libraries://" -e "s/;/ /g"` + ;; + yes,pw32*) + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | sed -e 's/./-/g'`${versuffix}.dll' + ;; + *) + library_names_spec='${libname}`echo ${release} | sed -e 's/[.]/-/g'`${versuffix}.dll $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + # FIXME: Relying on posixy $() will cause problems for + # cross-compilation, but unfortunately the echo tests do not + # yet detect zsh echo's removal of \ escapes. + library_names_spec='${libname}${release}${versuffix}.$(test .$module = .yes && echo so || echo dylib) ${libname}${release}${major}.$(test .$module = .yes && echo so || echo dylib) ${libname}.$(test .$module = .yes && echo so || echo dylib)' + soname_spec='${libname}${release}${major}.$(test .$module = .yes && echo so || echo dylib)' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +freebsd*) + objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout` + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so $libname.so' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}.so$versuffix $libname.so$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + *) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so${major} ${libname}.so' + soname_spec='${libname}${release}.so$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + dynamic_linker="$host_os dld.sl" + version_type=sunos + need_lib_prefix=no + need_version=no + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}.sl$versuffix ${libname}${release}.sl$major $libname.sl' + soname_spec='${libname}${release}.sl$major' + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +irix5* | irix6*) + version_type=irix + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}.so$major' + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major ${libname}${release}.so $libname.so' + case $host_os in + irix5*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 ") libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 ") libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux-gnuoldld* | linux-gnuaout* | linux-gnucoff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux-gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major ${libname}${release}.so ${libname}.so' + soname_spec='${libname}${release}.so$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +openbsd*) + version_type=sunos + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + need_version=no + fi + library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + ;; + +os2*) + libname_spec='$name' + need_lib_prefix=no + library_names_spec='$libname.dll $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_version=no + soname_spec='${libname}${release}.so' + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so $libname.so' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +sco3.2v5*) + version_type=osf + soname_spec='${libname}${release}.so$major' + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + shlibpath_var=LD_LIBRARY_PATH + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + version_type=linux + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname.so.$versuffix $libname.so.$major $libname.so' + soname_spec='$libname.so.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +*) + dynamic_linker=no + ;; +esac +echo "$as_me:$LINENO: result: $dynamic_linker" >&5 +echo "${ECHO_T}$dynamic_linker" >&6 +test "$dynamic_linker" = no && can_build_shared=no +## +## END FIXME + +## FIXME: this should be a separate macro +## +# Report the final consequences. +echo "$as_me:$LINENO: checking if libtool supports shared libraries" >&5 +echo $ECHO_N "checking if libtool supports shared libraries... $ECHO_C" >&6 +echo "$as_me:$LINENO: result: $can_build_shared" >&5 +echo "${ECHO_T}$can_build_shared" >&6 +## +## END FIXME + +if test "$hardcode_action" = relink; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + cygwin* | mingw* | pw32*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + *) + echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5 +echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6 +if test "${ac_cv_lib_dl_dlopen+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* 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 dlopen (); +int +main () +{ +dlopen (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext 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='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_lib_dl_dlopen=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_dl_dlopen=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5 +echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6 +if test $ac_cv_lib_dl_dlopen = yes; then + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" +else + echo "$as_me:$LINENO: checking for dlopen" >&5 +echo $ECHO_N "checking for dlopen... $ECHO_C" >&6 +if test "${ac_cv_func_dlopen+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char dlopen (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ +#ifdef __STDC__ +# include +#else +# include +#endif +/* 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 dlopen (); +/* 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_dlopen) || defined (__stub___dlopen) +choke me +#else +char (*f) () = dlopen; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != dlopen; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext 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='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_dlopen=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_func_dlopen=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_func_dlopen" >&5 +echo "${ECHO_T}$ac_cv_func_dlopen" >&6 +if test $ac_cv_func_dlopen = yes; then + lt_cv_dlopen="dlopen" +else + echo "$as_me:$LINENO: checking for shl_load" >&5 +echo $ECHO_N "checking for shl_load... $ECHO_C" >&6 +if test "${ac_cv_func_shl_load+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char shl_load (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ +#ifdef __STDC__ +# include +#else +# include +#endif +/* 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 shl_load (); +/* 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_shl_load) || defined (__stub___shl_load) +choke me +#else +char (*f) () = shl_load; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != shl_load; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext 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='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_shl_load=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_func_shl_load=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_func_shl_load" >&5 +echo "${ECHO_T}$ac_cv_func_shl_load" >&6 +if test $ac_cv_func_shl_load = yes; then + lt_cv_dlopen="shl_load" +else + echo "$as_me:$LINENO: checking for dlopen in -lsvld" >&5 +echo $ECHO_N "checking for dlopen in -lsvld... $ECHO_C" >&6 +if test "${ac_cv_lib_svld_dlopen+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsvld $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* 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 dlopen (); +int +main () +{ +dlopen (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext 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='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_lib_svld_dlopen=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_svld_dlopen=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_svld_dlopen" >&5 +echo "${ECHO_T}$ac_cv_lib_svld_dlopen" >&6 +if test $ac_cv_lib_svld_dlopen = yes; then + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" +else + echo "$as_me:$LINENO: checking for shl_load in -ldld" >&5 +echo $ECHO_N "checking for shl_load in -ldld... $ECHO_C" >&6 +if test "${ac_cv_lib_dld_shl_load+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* 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 shl_load (); +int +main () +{ +shl_load (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext 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='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_lib_dld_shl_load=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_dld_shl_load=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_dld_shl_load" >&5 +echo "${ECHO_T}$ac_cv_lib_dld_shl_load" >&6 +if test $ac_cv_lib_dld_shl_load = yes; then + lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld" +fi + + +fi + + +fi + + +fi + + +fi + + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + echo "$as_me:$LINENO: checking whether a program can dlopen itself" >&5 +echo $ECHO_N "checking whether a program can dlopen itself... $ECHO_C" >&6 +if test "${lt_cv_dlopen_self+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$cross_compiling" = yes; then : + lt_cv_dlopen_self=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext < +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +#ifdef __cplusplus +extern "C" void exit (int); +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + + exit (status); +} +EOF + 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); } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; + x$lt_unknown|x*) lt_cv_dlopen_self=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self=no + fi +fi +rm -fr conftest* + + +fi +echo "$as_me:$LINENO: result: $lt_cv_dlopen_self" >&5 +echo "${ECHO_T}$lt_cv_dlopen_self" >&6 + + if test "x$lt_cv_dlopen_self" = xyes; then + LDFLAGS="$LDFLAGS $link_static_flag" + echo "$as_me:$LINENO: checking whether a statically linked program can dlopen itself" >&5 +echo $ECHO_N "checking whether a statically linked program can dlopen itself... $ECHO_C" >&6 +if test "${lt_cv_dlopen_self_static+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$cross_compiling" = yes; then : + lt_cv_dlopen_self_static=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext < +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +#ifdef __cplusplus +extern "C" void exit (int); +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + + exit (status); +} +EOF + 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); } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_unknown|x*) lt_cv_dlopen_self_static=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self_static=no + fi +fi +rm -fr conftest* + + +fi +echo "$as_me:$LINENO: result: $lt_cv_dlopen_self_static" >&5 +echo "${ECHO_T}$lt_cv_dlopen_self_static" >&6 + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi + + +## FIXME: this should be a separate macro +## +if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5 +echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&6 + if test "${lt_cv_archive_cmds_need_lc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + $rm conftest* + echo 'static int dummy;' > conftest.$ac_ext + + 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 + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_cv_prog_cc_wl + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + save_allow_undefined_flag=$allow_undefined_flag + allow_undefined_flag= + if { (eval echo "$as_me:$LINENO: \"$archive_cmds 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\"") >&5 + (eval $archive_cmds 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + then + lt_cv_archive_cmds_need_lc=no + else + lt_cv_archive_cmds_need_lc=yes + fi + allow_undefined_flag=$save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi +fi + + echo "$as_me:$LINENO: result: $lt_cv_archive_cmds_need_lc" >&5 +echo "${ECHO_T}$lt_cv_archive_cmds_need_lc" >&6 + ;; + esac +fi +need_lc=${lt_cv_archive_cmds_need_lc-yes} +## +## END FIXME + +## FIXME: this should be a separate macro +## +# The second clause should only fire when bootstrapping the +# libtool distribution, otherwise you forgot to ship ltmain.sh +# with your package, and you will get complaints that there are +# no rules to generate ltmain.sh. +if test -f "$ltmain"; then + : +else + # If there is no Makefile yet, we rely on a make rule to execute + # `config.status --recheck' to rerun these tests and create the + # libtool script then. + test -f Makefile && make "$ltmain" +fi + +if test -f "$ltmain"; then + trap "$rm \"${ofile}T\"; exit 1" 1 2 15 + $rm -f "${ofile}T" + + echo creating $ofile + + # Now quote all the things that may contain metacharacters while being + # careful not to overquote the AC_SUBSTed values. We take copies of the + # variables and quote the copies for generation of the libtool script. + for var in echo old_CC old_CFLAGS \ + AR AR_FLAGS CC LD LN_S NM SHELL \ + reload_flag reload_cmds wl \ + pic_flag link_static_flag no_builtin_flag export_dynamic_flag_spec \ + thread_safe_flag_spec whole_archive_flag_spec libname_spec \ + library_names_spec soname_spec \ + RANLIB old_archive_cmds old_archive_from_new_cmds old_postinstall_cmds \ + old_postuninstall_cmds archive_cmds archive_expsym_cmds postinstall_cmds \ + postuninstall_cmds extract_expsyms_cmds old_archive_from_expsyms_cmds \ + old_striplib striplib file_magic_cmd export_symbols_cmds \ + deplibs_check_method allow_undefined_flag no_undefined_flag \ + finish_cmds finish_eval global_symbol_pipe global_symbol_to_cdecl \ + hardcode_libdir_flag_spec hardcode_libdir_separator \ + sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ + compiler_c_o compiler_o_lo need_locks exclude_expsyms include_expsyms; do + + case $var in + reload_cmds | old_archive_cmds | old_archive_from_new_cmds | \ + old_postinstall_cmds | old_postuninstall_cmds | \ + export_symbols_cmds | archive_cmds | archive_expsym_cmds | \ + extract_expsyms_cmds | old_archive_from_expsyms_cmds | \ + postinstall_cmds | postuninstall_cmds | \ + finish_cmds | sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) + # Double-quote double-evaled strings. + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" + ;; + *) + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" + ;; + esac + done + + cat <<__EOF__ > "${ofile}T" +#! $SHELL + +# `$echo "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP) +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +# Copyright (C) 1996-2000 Free Software Foundation, Inc. +# Originally by Gordon Matzigkeit , 1996 +# +# 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. +# +# 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. + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="sed -e s/^X//" + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +if test "X\${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi + +# ### BEGIN LIBTOOL CONFIG + +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$need_lc + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host + +# An echo program that does not interpret backslashes. +echo=$lt_echo + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# The default C compiler. +CC=$lt_CC + +# Is the compiler the GNU C compiler? +with_gcc=$GCC + +# The linker used to build libraries. +LD=$lt_LD + +# Whether we need hard or soft links. +LN_S=$lt_LN_S + +# A BSD-compatible nm program. +NM=$lt_NM + +# A symbol stripping program +STRIP=$STRIP + +# Used to examine libraries when file_magic_cmd begins "file" +MAGIC_CMD=$MAGIC_CMD + +# Used on cygwin: DLL creation program. +DLLTOOL="$DLLTOOL" + +# Used on cygwin: object dumper. +OBJDUMP="$OBJDUMP" + +# Used on cygwin: assembler. +AS="$AS" + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# How to pass a linker flag through the compiler. +wl=$lt_wl + +# Object file suffix (normally "o"). +objext="$ac_objext" + +# Old archive suffix (normally "a"). +libext="$libext" + +# Executable file suffix (normally ""). +exeext="$exeext" + +# Additional compiler flags for building library objects. +pic_flag=$lt_pic_flag +pic_mode=$pic_mode + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_compiler_c_o + +# Can we write directly to a .lo ? +compiler_o_lo=$lt_compiler_o_lo + +# Must we lock files when doing compilation ? +need_locks=$lt_need_locks + +# Do we need the lib prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_link_static_flag + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_no_builtin_flag + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec=$lt_thread_safe_flag_spec + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Commands used to build and install an old-style archive. +RANLIB=$lt_RANLIB +old_archive_cmds=$lt_old_archive_cmds +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds + +# Commands used to build and install a shared archive. +archive_cmds=$lt_archive_cmds +archive_expsym_cmds=$lt_archive_expsym_cmds +postinstall_cmds=$lt_postinstall_cmds +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd=$lt_file_magic_cmd + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag + +# Flag that forces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval=$lt_finish_eval + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_global_symbol_pipe + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl=$lt_global_symbol_to_cdecl + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator + +# Set to yes if using DIR/libNAME.so during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$hardcode_direct + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$hardcode_minus_L + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at relink time. +variables_saved_for_relink="$variables_saved_for_relink" + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs + +# Compile-time system search path for libraries +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path="$fix_srcfile_path" + +# Set to yes if exported symbols are required. +always_export_symbols=$always_export_symbols + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms + +# ### END LIBTOOL CONFIG + +__EOF__ + + case $host_os in + aix3*) + cat <<\EOF >> "${ofile}T" + +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +EOF + ;; + esac + + case $host_os in + cygwin* | mingw* | pw32* | os2*) + cat <<'EOF' >> "${ofile}T" + # This is a source program that is used to create dlls on Windows + # Don't remove nor modify the starting and closing comments +# /* ltdll.c starts here */ +# #define WIN32_LEAN_AND_MEAN +# #include +# #undef WIN32_LEAN_AND_MEAN +# #include +# +# #ifndef __CYGWIN__ +# # ifdef __CYGWIN32__ +# # define __CYGWIN__ __CYGWIN32__ +# # endif +# #endif +# +# #ifdef __cplusplus +# extern "C" { +# #endif +# BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved); +# #ifdef __cplusplus +# } +# #endif +# +# #ifdef __CYGWIN__ +# #include +# DECLARE_CYGWIN_DLL( DllMain ); +# #endif +# HINSTANCE __hDllInstance_base; +# +# BOOL APIENTRY +# DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved) +# { +# __hDllInstance_base = hInst; +# return TRUE; +# } +# /* ltdll.c ends here */ + # This is a source program that is used to create import libraries + # on Windows for dlls which lack them. Don't remove nor modify the + # starting and closing comments +# /* impgen.c starts here */ +# /* Copyright (C) 1999-2000 Free Software Foundation, Inc. +# +# This file is part of GNU libtool. +# +# 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. +# */ +# +# #include /* for printf() */ +# #include /* for open(), lseek(), read() */ +# #include /* for O_RDONLY, O_BINARY */ +# #include /* for strdup() */ +# +# /* O_BINARY isn't required (or even defined sometimes) under Unix */ +# #ifndef O_BINARY +# #define O_BINARY 0 +# #endif +# +# static unsigned int +# pe_get16 (fd, offset) +# int fd; +# int offset; +# { +# unsigned char b[2]; +# lseek (fd, offset, SEEK_SET); +# read (fd, b, 2); +# return b[0] + (b[1]<<8); +# } +# +# static unsigned int +# pe_get32 (fd, offset) +# int fd; +# int offset; +# { +# unsigned char b[4]; +# lseek (fd, offset, SEEK_SET); +# read (fd, b, 4); +# return b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24); +# } +# +# static unsigned int +# pe_as32 (ptr) +# void *ptr; +# { +# unsigned char *b = ptr; +# return b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24); +# } +# +# int +# main (argc, argv) +# int argc; +# char *argv[]; +# { +# int dll; +# unsigned long pe_header_offset, opthdr_ofs, num_entries, i; +# unsigned long export_rva, export_size, nsections, secptr, expptr; +# unsigned long name_rvas, nexp; +# unsigned char *expdata, *erva; +# char *filename, *dll_name; +# +# filename = argv[1]; +# +# dll = open(filename, O_RDONLY|O_BINARY); +# if (dll < 1) +# return 1; +# +# dll_name = filename; +# +# for (i=0; filename[i]; i++) +# if (filename[i] == '/' || filename[i] == '\\' || filename[i] == ':') +# dll_name = filename + i +1; +# +# pe_header_offset = pe_get32 (dll, 0x3c); +# opthdr_ofs = pe_header_offset + 4 + 20; +# num_entries = pe_get32 (dll, opthdr_ofs + 92); +# +# if (num_entries < 1) /* no exports */ +# return 1; +# +# export_rva = pe_get32 (dll, opthdr_ofs + 96); +# export_size = pe_get32 (dll, opthdr_ofs + 100); +# nsections = pe_get16 (dll, pe_header_offset + 4 +2); +# secptr = (pe_header_offset + 4 + 20 + +# pe_get16 (dll, pe_header_offset + 4 + 16)); +# +# expptr = 0; +# for (i = 0; i < nsections; i++) +# { +# char sname[8]; +# unsigned long secptr1 = secptr + 40 * i; +# unsigned long vaddr = pe_get32 (dll, secptr1 + 12); +# unsigned long vsize = pe_get32 (dll, secptr1 + 16); +# unsigned long fptr = pe_get32 (dll, secptr1 + 20); +# lseek(dll, secptr1, SEEK_SET); +# read(dll, sname, 8); +# if (vaddr <= export_rva && vaddr+vsize > export_rva) +# { +# expptr = fptr + (export_rva - vaddr); +# if (export_rva + export_size > vaddr + vsize) +# export_size = vsize - (export_rva - vaddr); +# break; +# } +# } +# +# expdata = (unsigned char*)malloc(export_size); +# lseek (dll, expptr, SEEK_SET); +# read (dll, expdata, export_size); +# erva = expdata - export_rva; +# +# nexp = pe_as32 (expdata+24); +# name_rvas = pe_as32 (expdata+32); +# +# printf ("EXPORTS\n"); +# for (i = 0; i> "${ofile}T" || (rm -f "${ofile}T"; exit 1) + + mv -f "${ofile}T" "$ofile" || \ + (rm -f "$ofile" && cp "${ofile}T" "$ofile" && rm -f "${ofile}T") + chmod +x "$ofile" +fi +## +## END FIXME + + + + + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ac_aux_dir/ltmain.sh" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' + +# Prevent multiple expansion + + + + +CC_FOR_BUILD=${CC_FOR_BUILD:-'$(CC)'} +CFLAGS_FOR_BUILD=${CFLAGS_FOR_BUILD:-'$(CFLAGS)'} +BUILD_EXEEXT=${BUILD_EXEEXT:-'$(EXEEXT)'} +BUILD_OBJEXT=${BUILD_OBJEXT:-'$(OBJEXT)'} + + +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 +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +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); } && + { 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.$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 +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_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 +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_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 +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#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.* *.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_header in limits.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 +#line $LINENO "configure" +/* 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>&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.$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 +#line $LINENO "configure" +/* 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 + 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 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 preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------ ## +## Report this to bug-autoconf@gnu.org. ## +## ------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; + 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: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------ ## +## Report this to bug-autoconf@gnu.org. ## +## ------------------------------------ ## +_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 + + + +echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5 +echo $ECHO_N "checking for an ANSI C-conforming const... $ECHO_C" >&6 +if test "${ac_cv_c_const+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +/* FIXME: Include the comments suggested by Paul. */ +#ifndef __cplusplus + /* Ultrix mips cc rejects this. */ + typedef int charset[2]; + const charset x; + /* SunOS 4.1.1 cc rejects this. */ + char const *const *ccp; + char **p; + /* NEC SVR4.0.2 mips cc rejects this. */ + struct point {int x, y;}; + static struct point const zero = {0,0}; + /* AIX XL C 1.02.0.0 rejects this. + It does not let you subtract one const X* pointer from another in + an arm of an if-expression whose if-part is not a constant + expression */ + const char *g = "string"; + ccp = &g + (g ? g-g : 0); + /* HPUX 7.0 cc rejects these. */ + ++ccp; + p = (char**) ccp; + ccp = (char const *const *) p; + { /* SCO 3.2v4 cc rejects this. */ + char *t; + char const *s = 0 ? (char *) 0 : (char const *) 0; + + *t++ = 0; + } + { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ + int x[] = {25, 17}; + const int *foo = &x[0]; + ++foo; + } + { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ + typedef const int *iptr; + iptr p = 0; + ++p; + } + { /* AIX XL C 1.02.0.0 rejects this saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; }; + struct s *b; b->j = 5; + } + { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; + } +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +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); } && + { 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_const=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_c_const=no +fi +rm -f conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_c_const" >&5 +echo "${ECHO_T}$ac_cv_c_const" >&6 +if test $ac_cv_c_const = no; then + +cat >>confdefs.h <<\_ACEOF +#define const +_ACEOF + +fi + +echo "$as_me:$LINENO: checking for size_t" >&5 +echo $ECHO_N "checking for size_t... $ECHO_C" >&6 +if test "${ac_cv_type_size_t+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +if ((size_t *) 0) + return 0; +if (sizeof (size_t)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +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); } && + { 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_size_t=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_type_size_t=no +fi +rm -f conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_type_size_t" >&5 +echo "${ECHO_T}$ac_cv_type_size_t" >&6 +if test $ac_cv_type_size_t = yes; then + : +else + +cat >>confdefs.h <<_ACEOF +#define size_t unsigned +_ACEOF + +fi + + + + + + +for ac_func in bcopy memmove strerror +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 +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ +#ifdef __STDC__ +# include +#else +# include +#endif +/* 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>&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.$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 + + + +# Check whether --enable-utf8 or --disable-utf8 was given. +if test "${enable_utf8+set}" = set; then + enableval="$enable_utf8" + if test "$enableval" = "yes"; then + UTF8=-DSUPPORT_UTF8 +fi + +fi; + + +# Check whether --enable-newline-is-cr or --disable-newline-is-cr was given. +if test "${enable_newline_is_cr+set}" = set; then + enableval="$enable_newline_is_cr" + if test "$enableval" = "yes"; then + NEWLINE=-DNEWLINE=13 +fi + +fi; + + +# Check whether --enable-newline-is-lf or --disable-newline-is-lf was given. +if test "${enable_newline_is_lf+set}" = set; then + enableval="$enable_newline_is_lf" + if test "$enableval" = "yes"; then + NEWLINE=-DNEWLINE=10 +fi + +fi; + + + + +# Check whether --with-posix-malloc-threshold or --without-posix-malloc-threshold was given. +if test "${with_posix_malloc_threshold+set}" = set; then + withval="$with_posix_malloc_threshold" + POSIX_MALLOC_THRESHOLD=-DPOSIX_MALLOC_THRESHOLD=$withval + +fi; + + + +# Check whether --with-link-size or --without-link-size was given. +if test "${with_link_size+set}" = set; then + withval="$with_link_size" + LINK_SIZE=-DLINK_SIZE=$withval + +fi; + + + +# Check whether --with-match-limit or --without-match-limit was given. +if test "${with_match_limit+set}" = set; then + withval="$with_match_limit" + MATCH_LIMIT=-DMATCH_LIMIT=$withval + +fi; + + + + + + + + + + + + + + + + + + + + + + + + +case $host_os in +mingw* ) + POSIX_OBJ=pcreposix.o + POSIX_LOBJ=pcreposix.lo + POSIX_LIB= + ON_WINDOWS= + NOT_ON_WINDOWS="#" + WIN_PREFIX= + ;; +cygwin* ) + ON_WINDOWS= + POSIX_OBJ=pcreposix.o + POSIX_LOBJ=pcreposix.lo + POSIX_LIB= + WIN_PREFIX=cyg + NOT_ON_WINDOWS="#" + ;; +* ) + ON_WINDOWS="#" + NOT_ON_WINDOWS= + POSIX_OBJ= + POSIX_LOBJ= + POSIX_LIB=libpcreposix.la + WIN_PREFIX= + ;; +esac + + + + + + + +if test "x$enable_shared" = "xno" ; then + cat >>confdefs.h <<\_ACEOF +#define PCRE_STATIC 1 +_ACEOF + +fi + + ac_config_files="$ac_config_files Makefile pcre.h:pcre.in pcre-config:pcre-config.in RunTest:RunTest.in" + ac_config_commands="$ac_config_commands default" +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 + +# Support unset when possible. +if (FOO=FOO; unset FOO) >/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 -n "`(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 + as_mkdir_p=false +fi + +as_executable_p="test -f" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="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="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 $as_me, which was +generated by GNU Autoconf 2.57. 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 commands: +$config_commands + +Report bugs to ." +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF +ac_cs_version="\\ +config.status +configured by $0, generated by GNU Autoconf 2.57, + with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" + +Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001 +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 +INSTALL="$INSTALL" +_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 +for ac_config_target in $ac_config_targets +do + case "$ac_config_target" in + # Handling of arguments. + "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "pcre.h" ) CONFIG_FILES="$CONFIG_FILES pcre.h:pcre.in" ;; + "pcre-config" ) CONFIG_FILES="$CONFIG_FILES pcre-config:pcre-config.in" ;; + "RunTest" ) CONFIG_FILES="$CONFIG_FILES RunTest:RunTest.in" ;; + "default" ) CONFIG_COMMANDS="$CONFIG_COMMANDS default" ;; + "config.h" ) CONFIG_HEADERS="$CONFIG_HEADERS config.h:config.in" ;; + *) { { 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_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,@CC@,$CC,;t t +s,@CFLAGS@,$CFLAGS,;t t +s,@LDFLAGS@,$LDFLAGS,;t t +s,@CPPFLAGS@,$CPPFLAGS,;t t +s,@ac_ct_CC@,$ac_ct_CC,;t t +s,@EXEEXT@,$EXEEXT,;t t +s,@OBJEXT@,$OBJEXT,;t t +s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t +s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t +s,@INSTALL_DATA@,$INSTALL_DATA,;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,@LN_S@,$LN_S,;t t +s,@ECHO@,$ECHO,;t t +s,@RANLIB@,$RANLIB,;t t +s,@ac_ct_RANLIB@,$ac_ct_RANLIB,;t t +s,@STRIP@,$STRIP,;t t +s,@ac_ct_STRIP@,$ac_ct_STRIP,;t t +s,@CPP@,$CPP,;t t +s,@EGREP@,$EGREP,;t t +s,@LIBTOOL@,$LIBTOOL,;t t +s,@BUILD_EXEEXT@,$BUILD_EXEEXT,;t t +s,@BUILD_OBJEXT@,$BUILD_OBJEXT,;t t +s,@CC_FOR_BUILD@,$CC_FOR_BUILD,;t t +s,@CFLAGS_FOR_BUILD@,$CFLAGS_FOR_BUILD,;t t +s,@HAVE_MEMMOVE@,$HAVE_MEMMOVE,;t t +s,@HAVE_STRERROR@,$HAVE_STRERROR,;t t +s,@LINK_SIZE@,$LINK_SIZE,;t t +s,@MATCH_LIMIT@,$MATCH_LIMIT,;t t +s,@NEWLINE@,$NEWLINE,;t t +s,@PCRE_MAJOR@,$PCRE_MAJOR,;t t +s,@PCRE_MINOR@,$PCRE_MINOR,;t t +s,@PCRE_DATE@,$PCRE_DATE,;t t +s,@PCRE_VERSION@,$PCRE_VERSION,;t t +s,@PCRE_LIB_VERSION@,$PCRE_LIB_VERSION,;t t +s,@PCRE_POSIXLIB_VERSION@,$PCRE_POSIXLIB_VERSION,;t t +s,@POSIX_MALLOC_THRESHOLD@,$POSIX_MALLOC_THRESHOLD,;t t +s,@UTF8@,$UTF8,;t t +s,@WIN_PREFIX@,$WIN_PREFIX,;t t +s,@ON_WINDOWS@,$ON_WINDOWS,;t t +s,@NOT_ON_WINDOWS@,$NOT_ON_WINDOWS,;t t +s,@POSIX_OBJ@,$POSIX_OBJ,;t t +s,@POSIX_LOBJ@,$POSIX_LOBJ,;t t +s,@POSIX_LIB@,$POSIX_LIB,;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 +# Don't blindly perform a `cd "$ac_dir"/$ac_foo && pwd` since $ac_foo can be +# absolute. +ac_abs_builddir=`cd "$ac_dir" && cd $ac_builddir && pwd` +ac_abs_top_builddir=`cd "$ac_dir" && cd ${ac_top_builddir}. && pwd` +ac_abs_srcdir=`cd "$ac_dir" && cd $ac_srcdir && pwd` +ac_abs_top_srcdir=`cd "$ac_dir" && cd $ac_top_srcdir && pwd` + + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_builddir$INSTALL ;; + esac + + 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 + # 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; } +_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 +s,@INSTALL@,$ac_INSTALL,;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; }; } + 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 <>$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 <>$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_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'` + 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 +# Don't blindly perform a `cd "$ac_dir"/$ac_foo && pwd` since $ac_foo can be +# absolute. +ac_abs_builddir=`cd "$ac_dir" && cd $ac_builddir && pwd` +ac_abs_top_builddir=`cd "$ac_dir" && cd ${ac_top_builddir}. && pwd` +ac_abs_srcdir=`cd "$ac_dir" && cd $ac_srcdir && pwd` +ac_abs_top_srcdir=`cd "$ac_dir" && cd $ac_top_srcdir && pwd` + + + { echo "$as_me:$LINENO: executing $ac_dest commands" >&5 +echo "$as_me: executing $ac_dest commands" >&6;} + case $ac_dest in + default ) chmod a+x RunTest pcre-config ;; + 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/mk4/continuity/pcre/configure.in b/mk4/continuity/pcre/configure.in new file mode 100644 index 0000000..5394f4f --- /dev/null +++ b/mk4/continuity/pcre/configure.in @@ -0,0 +1,189 @@ +dnl Process this file with autoconf to produce a configure script. + +dnl This is required at the start; the name is the name of a file +dnl it should be seeing, to verify it is in the same directory. + +AC_INIT(dftables.c) + +dnl A safety precaution + +AC_PREREQ(2.57) + +dnl Arrange to build config.h from config.in. Note that pcre.h is +dnl built differently, as it is just a "substitution" file. +dnl Manual says this macro should come right after AC_INIT. +AC_CONFIG_HEADER(config.h:config.in) + +dnl Provide the current PCRE version information. Do not use numbers +dnl with leading zeros for the minor version, as they end up in a C +dnl macro, and may be treated as octal constants. Stick to single +dnl digits for minor numbers less than 10. There are unlikely to be +dnl that many releases anyway. + +PCRE_MAJOR=4 +PCRE_MINOR=3 +PCRE_DATE=21-May-2003 +PCRE_VERSION=${PCRE_MAJOR}.${PCRE_MINOR} + +dnl Default values for miscellaneous macros + +POSIX_MALLOC_THRESHOLD=-DPOSIX_MALLOC_THRESHOLD=10 + +dnl Provide versioning information for libtool shared libraries that +dnl are built by default on Unix systems. + +PCRE_LIB_VERSION=0:1:0 +PCRE_POSIXLIB_VERSION=0:0:0 + +dnl Checks for programs. + +AC_PROG_CC +AC_PROG_INSTALL +AC_LIBTOOL_WIN32_DLL +AC_PROG_LIBTOOL + +dnl We need to find a compiler for compiling a program to run on the local host +dnl while building. It needs to be different from CC when cross-compiling. +dnl There is a macro called AC_PROG_CC_FOR_BUILD in the GNU archive for +dnl figuring this out automatically. Unfortunately, it does not work with the +dnl latest versions of autoconf. So for the moment, we just default to the +dnl same values as the "main" compiler. People who are corss-compiling will +dnl just have to adjust the Makefile by hand or set these values when they +dnl run "configure". + +CC_FOR_BUILD=${CC_FOR_BUILD:-'$(CC)'} +CFLAGS_FOR_BUILD=${CFLAGS_FOR_BUILD:-'$(CFLAGS)'} +BUILD_EXEEXT=${BUILD_EXEEXT:-'$(EXEEXT)'} +BUILD_OBJEXT=${BUILD_OBJEXT:-'$(OBJEXT)'} + +dnl Checks for header files. + +AC_HEADER_STDC +AC_CHECK_HEADERS(limits.h) + +dnl Checks for typedefs, structures, and compiler characteristics. + +AC_C_CONST +AC_TYPE_SIZE_T + +dnl Checks for library functions. + +AC_CHECK_FUNCS(bcopy memmove strerror) + +dnl Handle --enable-utf8 + +AC_ARG_ENABLE(utf8, +[ --enable-utf8 enable UTF8 support], +if test "$enableval" = "yes"; then + UTF8=-DSUPPORT_UTF8 +fi +) + +dnl Handle --enable-newline-is-cr + +AC_ARG_ENABLE(newline-is-cr, +[ --enable-newline-is-cr use CR as the newline character], +if test "$enableval" = "yes"; then + NEWLINE=-DNEWLINE=13 +fi +) + +dnl Handle --enable-newline-is-lf + +AC_ARG_ENABLE(newline-is-lf, +[ --enable-newline-is-lf use LF as the newline character], +if test "$enableval" = "yes"; then + NEWLINE=-DNEWLINE=10 +fi +) + +dnl There doesn't seem to be a straightforward way of having parameters +dnl that set values, other than fudging the --with thing. So that's what +dnl I've done. + +dnl Handle --with-posix-malloc-threshold=n + +AC_ARG_WITH(posix-malloc-threshold, +[ --with-posix-malloc-threshold=5 threshold for POSIX malloc usage], + POSIX_MALLOC_THRESHOLD=-DPOSIX_MALLOC_THRESHOLD=$withval +) + +dnl Handle --with-link-size=n + +AC_ARG_WITH(link-size, +[ --with-link-size=2 internal link size (2, 3, or 4 allowed)], + LINK_SIZE=-DLINK_SIZE=$withval +) + +dnl Handle --with-match_limit=n + +AC_ARG_WITH(match-limit, +[ --with-match-limit=10000000 default limit on internal looping)], + MATCH_LIMIT=-DMATCH_LIMIT=$withval +) + +dnl Now arrange to build libtool + +AC_PROG_LIBTOOL + +dnl "Export" these variables + +AC_SUBST(BUILD_EXEEXT) +AC_SUBST(BUILD_OBJEXT) +AC_SUBST(CC_FOR_BUILD) +AC_SUBST(CFLAGS_FOR_BUILD) +AC_SUBST(HAVE_MEMMOVE) +AC_SUBST(HAVE_STRERROR) +AC_SUBST(LINK_SIZE) +AC_SUBST(MATCH_LIMIT) +AC_SUBST(NEWLINE) +AC_SUBST(PCRE_MAJOR) +AC_SUBST(PCRE_MINOR) +AC_SUBST(PCRE_DATE) +AC_SUBST(PCRE_VERSION) +AC_SUBST(PCRE_LIB_VERSION) +AC_SUBST(PCRE_POSIXLIB_VERSION) +AC_SUBST(POSIX_MALLOC_THRESHOLD) +AC_SUBST(UTF8) + +dnl Stuff to make Win32 work better + +case $host_os in +mingw* ) + POSIX_OBJ=pcreposix.o + POSIX_LOBJ=pcreposix.lo + POSIX_LIB= + ON_WINDOWS= + NOT_ON_WINDOWS="#" + WIN_PREFIX= + ;; +cygwin* ) + ON_WINDOWS= + POSIX_OBJ=pcreposix.o + POSIX_LOBJ=pcreposix.lo + POSIX_LIB= + WIN_PREFIX=cyg + NOT_ON_WINDOWS="#" + ;; +* ) + ON_WINDOWS="#" + NOT_ON_WINDOWS= + POSIX_OBJ= + POSIX_LOBJ= + POSIX_LIB=libpcreposix.la + WIN_PREFIX= + ;; +esac +AC_SUBST(WIN_PREFIX) +AC_SUBST(ON_WINDOWS) +AC_SUBST(NOT_ON_WINDOWS) +AC_SUBST(POSIX_OBJ) +AC_SUBST(POSIX_LOBJ) +AC_SUBST(POSIX_LIB) + +if test "x$enable_shared" = "xno" ; then + AC_DEFINE(PCRE_STATIC,1) +fi + +dnl This must be last; it determines what files are written as well as config.h +AC_OUTPUT(Makefile pcre.h:pcre.in pcre-config:pcre-config.in RunTest:RunTest.in,[chmod a+x RunTest pcre-config]) diff --git a/mk4/continuity/pcre/dftables.c b/mk4/continuity/pcre/dftables.c new file mode 100644 index 0000000..9aa7b77 --- /dev/null +++ b/mk4/continuity/pcre/dftables.c @@ -0,0 +1,152 @@ +/************************************************* +* Perl-Compatible Regular Expressions * +*************************************************/ + +/* +PCRE is a library of functions to support regular expressions whose syntax +and semantics are as close as possible to those of the Perl 5 language. + +Written by: Philip Hazel + + Copyright (c) 1997-2001 University of Cambridge + +----------------------------------------------------------------------------- +Permission is granted to anyone to use this software for any purpose on any +computer system, and to redistribute it freely, subject to the following +restrictions: + +1. This software 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. + +2. The origin of this software must not be misrepresented, either by + explicit claim or by omission. + +3. Altered versions must be plainly marked as such, and must not be + misrepresented as being the original software. + +4. If PCRE is embedded in any software that is released under the GNU + General Purpose Licence (GPL), then the terms of that licence shall + supersede any condition above with which it is incompatible. +----------------------------------------------------------------------------- + +See the file Tech.Notes for some information on the internals. +*/ + + +/* This is a support program to generate the file chartables.c, containing +character tables of various kinds. They are built according to the default C +locale and used as the default tables by PCRE. Now that pcre_maketables is +a function visible to the outside world, we make use of its code from here in +order to be consistent. */ + +#include +#include +#include + +#include "internal.h" + +#define DFTABLES /* maketables.c notices this */ +#include "maketables.c" + + +int main(void) +{ +int i; +const unsigned char *tables = pcre_maketables(); + +/* There are two printf() calls here, because gcc in pedantic mode complains +about the very long string otherwise. */ + +printf( + "/*************************************************\n" + "* Perl-Compatible Regular Expressions *\n" + "*************************************************/\n\n" + "/* This file is automatically written by the dftables auxiliary \n" + "program. If you edit it by hand, you might like to edit the Makefile to \n" + "prevent its ever being regenerated.\n\n"); +printf( + "This file is #included in the compilation of pcre.c to build the default\n" + "character tables which are used when no tables are passed to the compile\n" + "function. */\n\n" + "static unsigned char pcre_default_tables[] = {\n\n" + "/* This table is a lower casing table. */\n\n"); + +printf(" "); +for (i = 0; i < 256; i++) + { + if ((i & 7) == 0 && i != 0) printf("\n "); + printf("%3d", *tables++); + if (i != 255) printf(","); + } +printf(",\n\n"); + +printf("/* This table is a case flipping table. */\n\n"); + +printf(" "); +for (i = 0; i < 256; i++) + { + if ((i & 7) == 0 && i != 0) printf("\n "); + printf("%3d", *tables++); + if (i != 255) printf(","); + } +printf(",\n\n"); + +printf( + "/* This table contains bit maps for various character classes.\n" + "Each map is 32 bytes long and the bits run from the least\n" + "significant end of each byte. The classes that have their own\n" + "maps are: space, xdigit, digit, upper, lower, word, graph\n" + "print, punct, and cntrl. Other classes are built from combinations. */\n\n"); + +printf(" "); +for (i = 0; i < cbit_length; i++) + { + if ((i & 7) == 0 && i != 0) + { + if ((i & 31) == 0) printf("\n"); + printf("\n "); + } + printf("0x%02x", *tables++); + if (i != cbit_length - 1) printf(","); + } +printf(",\n\n"); + +printf( + "/* This table identifies various classes of character by individual bits:\n" + " 0x%02x white space character\n" + " 0x%02x letter\n" + " 0x%02x decimal digit\n" + " 0x%02x hexadecimal digit\n" + " 0x%02x alphanumeric or '_'\n" + " 0x%02x regular expression metacharacter or binary zero\n*/\n\n", + ctype_space, ctype_letter, ctype_digit, ctype_xdigit, ctype_word, + ctype_meta); + +printf(" "); +for (i = 0; i < 256; i++) + { + if ((i & 7) == 0 && i != 0) + { + printf(" /* "); + if (isprint(i-8)) printf(" %c -", i-8); + else printf("%3d-", i-8); + if (isprint(i-1)) printf(" %c ", i-1); + else printf("%3d", i-1); + printf(" */\n "); + } + printf("0x%02x", *tables++); + if (i != 255) printf(","); + } + +printf("};/* "); +if (isprint(i-8)) printf(" %c -", i-8); + else printf("%3d-", i-8); +if (isprint(i-1)) printf(" %c ", i-1); + else printf("%3d", i-1); +printf(" */\n\n/* End of chartables.c */\n"); + +return 0; +} + +/* End of dftables.c */ diff --git a/mk4/continuity/pcre/get.c b/mk4/continuity/pcre/get.c new file mode 100644 index 0000000..a20473c --- /dev/null +++ b/mk4/continuity/pcre/get.c @@ -0,0 +1,349 @@ +/************************************************* +* Perl-Compatible Regular Expressions * +*************************************************/ + +/* +This is a library of functions to support regular expressions whose syntax +and semantics are as close as possible to those of the Perl 5 language. See +the file Tech.Notes for some information on the internals. + +Written by: Philip Hazel + + Copyright (c) 1997-2003 University of Cambridge + +----------------------------------------------------------------------------- +Permission is granted to anyone to use this software for any purpose on any +computer system, and to redistribute it freely, subject to the following +restrictions: + +1. This software 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. + +2. The origin of this software must not be misrepresented, either by + explicit claim or by omission. + +3. Altered versions must be plainly marked as such, and must not be + misrepresented as being the original software. + +4. If PCRE is embedded in any software that is released under the GNU + General Purpose Licence (GPL), then the terms of that licence shall + supersede any condition above with which it is incompatible. +----------------------------------------------------------------------------- +*/ + +/* This module contains some convenience functions for extracting substrings +from the subject string after a regex match has succeeded. The original idea +for these functions came from Scott Wimer . */ + + +/* Include the internals header, which itself includes Standard C headers plus +the external pcre header. */ + +#include "internal.h" + + +/************************************************* +* Find number for named string * +*************************************************/ + +/* This function is used by the two extraction functions below, as well +as being generally available. + +Arguments: + code the compiled regex + stringname the name whose number is required + +Returns: the number of the named parentheses, or a negative number + (PCRE_ERROR_NOSUBSTRING) if not found +*/ + +int +pcre_get_stringnumber(const pcre *code, const char *stringname) +{ +int rc; +int entrysize; +int top, bot; +uschar *nametable; + +if ((rc = pcre_fullinfo(code, NULL, PCRE_INFO_NAMECOUNT, &top)) != 0) + return rc; +if (top <= 0) return PCRE_ERROR_NOSUBSTRING; + +if ((rc = pcre_fullinfo(code, NULL, PCRE_INFO_NAMEENTRYSIZE, &entrysize)) != 0) + return rc; +if ((rc = pcre_fullinfo(code, NULL, PCRE_INFO_NAMETABLE, &nametable)) != 0) + return rc; + +bot = 0; +while (top > bot) + { + int mid = (top + bot) / 2; + uschar *entry = nametable + entrysize*mid; + int c = strcmp(stringname, (char *)(entry + 2)); + if (c == 0) return (entry[0] << 8) + entry[1]; + if (c > 0) bot = mid + 1; else top = mid; + } + +return PCRE_ERROR_NOSUBSTRING; +} + + + +/************************************************* +* Copy captured string to given buffer * +*************************************************/ + +/* This function copies a single captured substring into a given buffer. +Note that we use memcpy() rather than strncpy() in case there are binary zeros +in the string. + +Arguments: + subject the subject string that was matched + ovector pointer to the offsets table + stringcount the number of substrings that were captured + (i.e. the yield of the pcre_exec call, unless + that was zero, in which case it should be 1/3 + of the offset table size) + stringnumber the number of the required substring + buffer where to put the substring + size the size of the buffer + +Returns: if successful: + the length of the copied string, not including the zero + that is put on the end; can be zero + if not successful: + PCRE_ERROR_NOMEMORY (-6) buffer too small + PCRE_ERROR_NOSUBSTRING (-7) no such captured substring +*/ + +int +pcre_copy_substring(const char *subject, int *ovector, int stringcount, + int stringnumber, char *buffer, int size) +{ +int yield; +if (stringnumber < 0 || stringnumber >= stringcount) + return PCRE_ERROR_NOSUBSTRING; +stringnumber *= 2; +yield = ovector[stringnumber+1] - ovector[stringnumber]; +if (size < yield + 1) return PCRE_ERROR_NOMEMORY; +memcpy(buffer, subject + ovector[stringnumber], yield); +buffer[yield] = 0; +return yield; +} + + + +/************************************************* +* Copy named captured string to given buffer * +*************************************************/ + +/* This function copies a single captured substring into a given buffer, +identifying it by name. + +Arguments: + code the compiled regex + subject the subject string that was matched + ovector pointer to the offsets table + stringcount the number of substrings that were captured + (i.e. the yield of the pcre_exec call, unless + that was zero, in which case it should be 1/3 + of the offset table size) + stringname the name of the required substring + buffer where to put the substring + size the size of the buffer + +Returns: if successful: + the length of the copied string, not including the zero + that is put on the end; can be zero + if not successful: + PCRE_ERROR_NOMEMORY (-6) buffer too small + PCRE_ERROR_NOSUBSTRING (-7) no such captured substring +*/ + +int +pcre_copy_named_substring(const pcre *code, const char *subject, int *ovector, + int stringcount, const char *stringname, char *buffer, int size) +{ +int n = pcre_get_stringnumber(code, stringname); +if (n <= 0) return n; +return pcre_copy_substring(subject, ovector, stringcount, n, buffer, size); +} + + + +/************************************************* +* Copy all captured strings to new store * +*************************************************/ + +/* This function gets one chunk of store and builds a list of pointers and all +of the captured substrings in it. A NULL pointer is put on the end of the list. + +Arguments: + subject the subject string that was matched + ovector pointer to the offsets table + stringcount the number of substrings that were captured + (i.e. the yield of the pcre_exec call, unless + that was zero, in which case it should be 1/3 + of the offset table size) + listptr set to point to the list of pointers + +Returns: if successful: 0 + if not successful: + PCRE_ERROR_NOMEMORY (-6) failed to get store +*/ + +int +pcre_get_substring_list(const char *subject, int *ovector, int stringcount, + const char ***listptr) +{ +int i; +int size = sizeof(char *); +int double_count = stringcount * 2; +char **stringlist; +char *p; + +for (i = 0; i < double_count; i += 2) + size += sizeof(char *) + ovector[i+1] - ovector[i] + 1; + +stringlist = (char **)(pcre_malloc)(size); +if (stringlist == NULL) return PCRE_ERROR_NOMEMORY; + +*listptr = (const char **)stringlist; +p = (char *)(stringlist + stringcount + 1); + +for (i = 0; i < double_count; i += 2) + { + int len = ovector[i+1] - ovector[i]; + memcpy(p, subject + ovector[i], len); + *stringlist++ = p; + p += len; + *p++ = 0; + } + +*stringlist = NULL; +return 0; +} + + + +/************************************************* +* Free store obtained by get_substring_list * +*************************************************/ + +/* This function exists for the benefit of people calling PCRE from non-C +programs that can call its functions, but not free() or (pcre_free)() directly. + +Argument: the result of a previous pcre_get_substring_list() +Returns: nothing +*/ + +void +pcre_free_substring_list(const char **pointer) +{ +(pcre_free)((void *)pointer); +} + + + +/************************************************* +* Copy captured string to new store * +*************************************************/ + +/* This function copies a single captured substring into a piece of new +store + +Arguments: + subject the subject string that was matched + ovector pointer to the offsets table + stringcount the number of substrings that were captured + (i.e. the yield of the pcre_exec call, unless + that was zero, in which case it should be 1/3 + of the offset table size) + stringnumber the number of the required substring + stringptr where to put a pointer to the substring + +Returns: if successful: + the length of the string, not including the zero that + is put on the end; can be zero + if not successful: + PCRE_ERROR_NOMEMORY (-6) failed to get store + PCRE_ERROR_NOSUBSTRING (-7) substring not present +*/ + +int +pcre_get_substring(const char *subject, int *ovector, int stringcount, + int stringnumber, const char **stringptr) +{ +int yield; +char *substring; +if (stringnumber < 0 || stringnumber >= stringcount) + return PCRE_ERROR_NOSUBSTRING; +stringnumber *= 2; +yield = ovector[stringnumber+1] - ovector[stringnumber]; +substring = (char *)(pcre_malloc)(yield + 1); +if (substring == NULL) return PCRE_ERROR_NOMEMORY; +memcpy(substring, subject + ovector[stringnumber], yield); +substring[yield] = 0; +*stringptr = substring; +return yield; +} + + + +/************************************************* +* Copy named captured string to new store * +*************************************************/ + +/* This function copies a single captured substring, identified by name, into +new store. + +Arguments: + code the compiled regex + subject the subject string that was matched + ovector pointer to the offsets table + stringcount the number of substrings that were captured + (i.e. the yield of the pcre_exec call, unless + that was zero, in which case it should be 1/3 + of the offset table size) + stringname the name of the required substring + stringptr where to put the pointer + +Returns: if successful: + the length of the copied string, not including the zero + that is put on the end; can be zero + if not successful: + PCRE_ERROR_NOMEMORY (-6) couldn't get memory + PCRE_ERROR_NOSUBSTRING (-7) no such captured substring +*/ + +int +pcre_get_named_substring(const pcre *code, const char *subject, int *ovector, + int stringcount, const char *stringname, const char **stringptr) +{ +int n = pcre_get_stringnumber(code, stringname); +if (n <= 0) return n; +return pcre_get_substring(subject, ovector, stringcount, n, stringptr); +} + + + + +/************************************************* +* Free store obtained by get_substring * +*************************************************/ + +/* This function exists for the benefit of people calling PCRE from non-C +programs that can call its functions, but not free() or (pcre_free)() directly. + +Argument: the result of a previous pcre_get_substring() +Returns: nothing +*/ + +void +pcre_free_substring(const char *pointer) +{ +(pcre_free)((void *)pointer); +} + +/* End of get.c */ diff --git a/mk4/continuity/pcre/install-sh b/mk4/continuity/pcre/install-sh new file mode 100644 index 0000000..e9de238 --- /dev/null +++ b/mk4/continuity/pcre/install-sh @@ -0,0 +1,251 @@ +#!/bin/sh +# +# install - install a program, script, or datafile +# This comes from X11R5 (mit/util/scripts/install.sh). +# +# Copyright 1991 by the Massachusetts Institute of Technology +# +# Permission to use, copy, modify, distribute, and sell this software and its +# documentation for any purpose is hereby granted without fee, 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 M.I.T. not be used in advertising or +# publicity pertaining to distribution of the software without specific, +# written prior permission. M.I.T. makes no representations about the +# suitability of this software for any purpose. It is provided "as is" +# without express or implied warranty. +# +# 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 "install: no input file specified" + exit 1 +else + true +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d $dst ]; then + instcmd=: + chmodcmd="" + else + instcmd=mkdir + 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 -o -d $src ] + then + true + else + echo "install: $src does not exist" + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "install: no destination specified" + exit 1 + else + true + 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 + true + 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 + true + fi + + pathcomp="${pathcomp}/" +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd $dst && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; 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 + true + fi + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + + $doit $instcmd $src $dsttmp && + + trap "rm -f ${dsttmp}" 0 && + +# 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 true;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && + +# Now rename the file to the real destination. + + $doit $rmcmd -f $dstdir/$dstfile && + $doit $mvcmd $dsttmp $dstdir/$dstfile + +fi && + + +exit 0 diff --git a/mk4/continuity/pcre/internal.h b/mk4/continuity/pcre/internal.h new file mode 100644 index 0000000..973e7ee --- /dev/null +++ b/mk4/continuity/pcre/internal.h @@ -0,0 +1,662 @@ +/************************************************* +* Perl-Compatible Regular Expressions * +*************************************************/ + + +/* This is a library of functions to support regular expressions whose syntax +and semantics are as close as possible to those of the Perl 5 language. See +the file Tech.Notes for some information on the internals. + +Written by: Philip Hazel + + Copyright (c) 1997-2003 University of Cambridge + +----------------------------------------------------------------------------- +Permission is granted to anyone to use this software for any purpose on any +computer system, and to redistribute it freely, subject to the following +restrictions: + +1. This software 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. + +2. The origin of this software must not be misrepresented, either by + explicit claim or by omission. + +3. Altered versions must be plainly marked as such, and must not be + misrepresented as being the original software. + +4. If PCRE is embedded in any software that is released under the GNU + General Purpose Licence (GPL), then the terms of that licence shall + supersede any condition above with which it is incompatible. +----------------------------------------------------------------------------- +*/ + +/* This header contains definitions that are shared between the different +modules, but which are not relevant to the outside. */ + +/* Get the definitions provided by running "configure" */ + +#include "config.h" + +/* When compiling for use with the Virtual Pascal compiler, these functions +need to have their names changed. PCRE must be compiled with the -DVPCOMPAT +option on the command line. */ + +#ifdef VPCOMPAT +#define strncmp(s1,s2,m) _strncmp(s1,s2,m) +#define memcpy(d,s,n) _memcpy(d,s,n) +#define memmove(d,s,n) _memmove(d,s,n) +#define memset(s,c,n) _memset(s,c,n) +#else /* VPCOMPAT */ + +/* To cope with SunOS4 and other systems that lack memmove() but have bcopy(), +define a macro for memmove() if HAVE_MEMMOVE is false, provided that HAVE_BCOPY +is set. Otherwise, include an emulating function for those systems that have +neither (there some non-Unix environments where this is the case). This assumes +that all calls to memmove are moving strings upwards in store, which is the +case in PCRE. */ + +#if ! HAVE_MEMMOVE +#undef memmove /* some systems may have a macro */ +#if HAVE_BCOPY +#define memmove(a, b, c) bcopy(b, a, c) +#else /* HAVE_BCOPY */ +void * +pcre_memmove(unsigned char *dest, const unsigned char *src, size_t n) +{ +int i; +dest += n; +src += n; +for (i = 0; i < n; ++i) *(--dest) = *(--src); +} +#define memmove(a, b, c) pcre_memmove(a, b, c) +#endif /* not HAVE_BCOPY */ +#endif /* not HAVE_MEMMOVE */ +#endif /* not VPCOMPAT */ + + +/* PCRE keeps offsets in its compiled code as 2-byte quantities by default. +These are used, for example, to link from the start of a subpattern to its +alternatives and its end. The use of 2 bytes per offset limits the size of the +compiled regex to around 64K, which is big enough for almost everybody. +However, I received a request for an even bigger limit. For this reason, and +also to make the code easier to maintain, the storing and loading of offsets +from the byte string is now handled by the macros that are defined here. + +The macros are controlled by the value of LINK_SIZE. This defaults to 2 in +the config.h file, but can be overridden by using -D on the command line. This +is automated on Unix systems via the "configure" command. */ + +#if LINK_SIZE == 2 + +#define PUT(a,n,d) \ + (a[n] = (d) >> 8), \ + (a[(n)+1] = (d) & 255) + +#define GET(a,n) \ + (((a)[n] << 8) | (a)[(n)+1]) + +#define MAX_PATTERN_SIZE (1 << 16) + + +#elif LINK_SIZE == 3 + +#define PUT(a,n,d) \ + (a[n] = (d) >> 16), \ + (a[(n)+1] = (d) >> 8), \ + (a[(n)+2] = (d) & 255) + +#define GET(a,n) \ + (((a)[n] << 16) | ((a)[(n)+1] << 8) | (a)[(n)+2]) + +#define MAX_PATTERN_SIZE (1 << 24) + + +#elif LINK_SIZE == 4 + +#define PUT(a,n,d) \ + (a[n] = (d) >> 24), \ + (a[(n)+1] = (d) >> 16), \ + (a[(n)+2] = (d) >> 8), \ + (a[(n)+3] = (d) & 255) + +#define GET(a,n) \ + (((a)[n] << 24) | ((a)[(n)+1] << 16) | ((a)[(n)+2] << 8) | (a)[(n)+3]) + +#define MAX_PATTERN_SIZE (1 << 30) /* Keep it positive */ + + +#else +#error LINK_SIZE must be either 2, 3, or 4 +#endif + + +/* Convenience macro defined in terms of the others */ + +#define PUTINC(a,n,d) PUT(a,n,d), a += LINK_SIZE + + +/* PCRE uses some other 2-byte quantities that do not change when the size of +offsets changes. There are used for repeat counts and for other things such as +capturing parenthesis numbers in back references. */ + +#define PUT2(a,n,d) \ + a[n] = (d) >> 8; \ + a[(n)+1] = (d) & 255 + +#define GET2(a,n) \ + (((a)[n] << 8) | (a)[(n)+1]) + +#define PUT2INC(a,n,d) PUT2(a,n,d), a += 2 + + +/* Standard C headers plus the external interface definition */ + +#include +#include +#include +#include +#include +#include + +#ifndef PCRE_SPY +#define PCRE_DEFINITION /* Win32 __declspec(export) trigger for .dll */ +#endif + +#include "pcre.h" + +/* In case there is no definition of offsetof() provided - though any proper +Standard C system should have one. */ + +#ifndef offsetof +#define offsetof(p_type,field) ((size_t)&(((p_type *)0)->field)) +#endif + +/* These are the public options that can change during matching. */ + +#define PCRE_IMS (PCRE_CASELESS|PCRE_MULTILINE|PCRE_DOTALL) + +/* Private options flags start at the most significant end of the four bytes, +but skip the top bit so we can use ints for convenience without getting tangled +with negative values. The public options defined in pcre.h start at the least +significant end. Make sure they don't overlap, though now that we have expanded +to four bytes there is plenty of space. */ + +#define PCRE_FIRSTSET 0x40000000 /* first_byte is set */ +#define PCRE_REQCHSET 0x20000000 /* req_byte is set */ +#define PCRE_STARTLINE 0x10000000 /* start after \n for multiline */ +#define PCRE_ICHANGED 0x08000000 /* i option changes within regex */ + +/* Options for the "extra" block produced by pcre_study(). */ + +#define PCRE_STUDY_MAPPED 0x01 /* a map of starting chars exists */ + +/* Masks for identifying the public options which are permitted at compile +time, run time or study time, respectively. */ + +#define PUBLIC_OPTIONS \ + (PCRE_CASELESS|PCRE_EXTENDED|PCRE_ANCHORED|PCRE_MULTILINE| \ + PCRE_DOTALL|PCRE_DOLLAR_ENDONLY|PCRE_EXTRA|PCRE_UNGREEDY|PCRE_UTF8| \ + PCRE_NO_AUTO_CAPTURE) + +#define PUBLIC_EXEC_OPTIONS \ + (PCRE_ANCHORED|PCRE_NOTBOL|PCRE_NOTEOL|PCRE_NOTEMPTY) + +#define PUBLIC_STUDY_OPTIONS 0 /* None defined */ + +/* Magic number to provide a small check against being handed junk. */ + +#define MAGIC_NUMBER 0x50435245UL /* 'PCRE' */ + +/* Negative values for the firstchar and reqchar variables */ + +#define REQ_UNSET (-2) +#define REQ_NONE (-1) + +/* Flags added to firstbyte or reqbyte; a "non-literal" item is either a +variable-length repeat, or a anything other than literal characters. */ + +#define REQ_CASELESS 0x0100 /* indicates caselessness */ +#define REQ_VARY 0x0200 /* reqbyte followed non-literal item */ + +/* Miscellaneous definitions */ + +typedef int BOOL; + +#define FALSE 0 +#define TRUE 1 + +/* Escape items that are just an encoding of a particular data value. Note that +ESC_n is defined as yet another macro, which is set in config.h to either \n +(the default) or \r (which some people want). */ + +#ifndef ESC_e +#define ESC_e 27 +#endif + +#ifndef ESC_f +#define ESC_f '\f' +#endif + +#ifndef ESC_n +#define ESC_n NEWLINE +#endif + +#ifndef ESC_r +#define ESC_r '\r' +#endif + +/* We can't officially use ESC_t because it is a POSIX reserved identifier +(presumably because of all the others like size_t). */ + +#ifndef ESC_tee +#define ESC_tee '\t' +#endif + +/* These are escaped items that aren't just an encoding of a particular data +value such as \n. They must have non-zero values, as check_escape() returns +their negation. Also, they must appear in the same order as in the opcode +definitions below, up to ESC_z. There's a dummy for OP_ANY because it +corresponds to "." rather than an escape sequence. The final one must be +ESC_REF as subsequent values are used for \1, \2, \3, etc. There is are two +tests in the code for an escape greater than ESC_b and less than ESC_Z to +detect the types that may be repeated. These are the types that consume a +character. If any new escapes are put in between that don't consume a +character, that code will have to change. */ + +enum { ESC_A = 1, ESC_G, ESC_B, ESC_b, ESC_D, ESC_d, ESC_S, ESC_s, ESC_W, + ESC_w, ESC_dum1, ESC_C, ESC_Z, ESC_z, ESC_E, ESC_Q, ESC_REF }; + +/* Flag bits and data types for the extended class (OP_XCLASS) for classes that +contain UTF-8 characters with values greater than 255. */ + +#define XCL_NOT 0x01 /* Flag: this is a negative class */ +#define XCL_MAP 0x02 /* Flag: a 32-byte map is present */ + +#define XCL_END 0 /* Marks end of individual items */ +#define XCL_SINGLE 1 /* Single item (one multibyte char) follows */ +#define XCL_RANGE 2 /* A range (two multibyte chars) follows */ + + +/* Opcode table: OP_BRA must be last, as all values >= it are used for brackets +that extract substrings. Starting from 1 (i.e. after OP_END), the values up to +OP_EOD must correspond in order to the list of escapes immediately above. +Note that whenever this list is updated, the two macro definitions that follow +must also be updated to match. */ + +enum { + OP_END, /* 0 End of pattern */ + + /* Values corresponding to backslashed metacharacters */ + + OP_SOD, /* 1 Start of data: \A */ + OP_SOM, /* 2 Start of match (subject + offset): \G */ + OP_NOT_WORD_BOUNDARY, /* 3 \B */ + OP_WORD_BOUNDARY, /* 4 \b */ + OP_NOT_DIGIT, /* 5 \D */ + OP_DIGIT, /* 6 \d */ + OP_NOT_WHITESPACE, /* 7 \S */ + OP_WHITESPACE, /* 8 \s */ + OP_NOT_WORDCHAR, /* 9 \W */ + OP_WORDCHAR, /* 10 \w */ + OP_ANY, /* 11 Match any character */ + OP_ANYBYTE, /* 12 Match any byte (\C); different to OP_ANY for UTF-8 */ + OP_EODN, /* 13 End of data or \n at end of data: \Z. */ + OP_EOD, /* 14 End of data: \z */ + + OP_OPT, /* 15 Set runtime options */ + OP_CIRC, /* 16 Start of line - varies with multiline switch */ + OP_DOLL, /* 17 End of line - varies with multiline switch */ + OP_CHARS, /* 18 Match string of characters */ + OP_NOT, /* 19 Match anything but the following char */ + + OP_STAR, /* 20 The maximizing and minimizing versions of */ + OP_MINSTAR, /* 21 all these opcodes must come in pairs, with */ + OP_PLUS, /* 22 the minimizing one second. */ + OP_MINPLUS, /* 23 This first set applies to single characters */ + OP_QUERY, /* 24 */ + OP_MINQUERY, /* 25 */ + OP_UPTO, /* 26 From 0 to n matches */ + OP_MINUPTO, /* 27 */ + OP_EXACT, /* 28 Exactly n matches */ + + OP_NOTSTAR, /* 29 The maximizing and minimizing versions of */ + OP_NOTMINSTAR, /* 30 all these opcodes must come in pairs, with */ + OP_NOTPLUS, /* 31 the minimizing one second. */ + OP_NOTMINPLUS, /* 32 This set applies to "not" single characters */ + OP_NOTQUERY, /* 33 */ + OP_NOTMINQUERY, /* 34 */ + OP_NOTUPTO, /* 35 From 0 to n matches */ + OP_NOTMINUPTO, /* 36 */ + OP_NOTEXACT, /* 37 Exactly n matches */ + + OP_TYPESTAR, /* 38 The maximizing and minimizing versions of */ + OP_TYPEMINSTAR, /* 39 all these opcodes must come in pairs, with */ + OP_TYPEPLUS, /* 40 the minimizing one second. These codes must */ + OP_TYPEMINPLUS, /* 41 be in exactly the same order as those above. */ + OP_TYPEQUERY, /* 42 This set applies to character types such as \d */ + OP_TYPEMINQUERY, /* 43 */ + OP_TYPEUPTO, /* 44 From 0 to n matches */ + OP_TYPEMINUPTO, /* 45 */ + OP_TYPEEXACT, /* 46 Exactly n matches */ + + OP_CRSTAR, /* 47 The maximizing and minimizing versions of */ + OP_CRMINSTAR, /* 48 all these opcodes must come in pairs, with */ + OP_CRPLUS, /* 49 the minimizing one second. These codes must */ + OP_CRMINPLUS, /* 50 be in exactly the same order as those above. */ + OP_CRQUERY, /* 51 These are for character classes and back refs */ + OP_CRMINQUERY, /* 52 */ + OP_CRRANGE, /* 53 These are different to the three seta above. */ + OP_CRMINRANGE, /* 54 */ + + OP_CLASS, /* 55 Match a character class, chars < 256 only */ + OP_NCLASS, /* 56 Same, but the bitmap was created from a negative + class - the difference is relevant only when a UTF-8 + character > 255 is encountered. */ + + OP_XCLASS, /* 56 Extended class for handling UTF-8 chars within the + class. This does both positive and negative. */ + + OP_REF, /* 57 Match a back reference */ + OP_RECURSE, /* 58 Match a numbered subpattern (possibly recursive) */ + OP_CALLOUT, /* 59 Call out to external function if provided */ + + OP_ALT, /* 60 Start of alternation */ + OP_KET, /* 61 End of group that doesn't have an unbounded repeat */ + OP_KETRMAX, /* 62 These two must remain together and in this */ + OP_KETRMIN, /* 63 order. They are for groups the repeat for ever. */ + + /* The assertions must come before ONCE and COND */ + + OP_ASSERT, /* 64 Positive lookahead */ + OP_ASSERT_NOT, /* 65 Negative lookahead */ + OP_ASSERTBACK, /* 66 Positive lookbehind */ + OP_ASSERTBACK_NOT, /* 67 Negative lookbehind */ + OP_REVERSE, /* 68 Move pointer back - used in lookbehind assertions */ + + /* ONCE and COND must come after the assertions, with ONCE first, as there's + a test for >= ONCE for a subpattern that isn't an assertion. */ + + OP_ONCE, /* 69 Once matched, don't back up into the subpattern */ + OP_COND, /* 70 Conditional group */ + OP_CREF, /* 71 Used to hold an extraction string number (cond ref) */ + + OP_BRAZERO, /* 72 These two must remain together and in this */ + OP_BRAMINZERO, /* 73 order. */ + + OP_BRANUMBER, /* 74 Used for extracting brackets whose number is greater + than can fit into an opcode. */ + + OP_BRA /* 75 This and greater values are used for brackets that + extract substrings up to a basic limit. After that, + use is made of OP_BRANUMBER. */ +}; + +/* WARNING: There is an implicit assumption in study.c that all opcodes are +less than 128 in value. This makes handling UTF-8 character sequences easier. +*/ + + +/* This macro defines textual names for all the opcodes. There are used only +for debugging, in pcre.c when DEBUG is defined, and also in pcretest.c. The +macro is referenced only in printint.c. */ + +#define OP_NAME_LIST \ + "End", "\\A", "\\G", "\\B", "\\b", "\\D", "\\d", \ + "\\S", "\\s", "\\W", "\\w", "Any", "Anybyte", "\\Z", "\\z", \ + "Opt", "^", "$", "chars", "not", \ + "*", "*?", "+", "+?", "?", "??", "{", "{", "{", \ + "*", "*?", "+", "+?", "?", "??", "{", "{", "{", \ + "*", "*?", "+", "+?", "?", "??", "{", "{", "{", \ + "*", "*?", "+", "+?", "?", "??", "{", "{", \ + "class", "nclass", "xclass", "Ref", "Recurse", "Callout", \ + "Alt", "Ket", "KetRmax", "KetRmin", "Assert", "Assert not", \ + "AssertB", "AssertB not", "Reverse", "Once", "Cond", "Cond ref",\ + "Brazero", "Braminzero", "Branumber", "Bra" + + +/* This macro defines the length of fixed length operations in the compiled +regex. The lengths are used when searching for specific things, and also in the +debugging printing of a compiled regex. We use a macro so that it can be +incorporated both into pcre.c and pcretest.c without being publicly exposed. + +As things have been extended, some of these are no longer fixed lenths, but are +minima instead. For example, the length of a single-character repeat may vary +in UTF-8 mode. The code that uses this table must know about such things. */ + +#define OP_LENGTHS \ + 1, /* End */ \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* \A, \G, \B, \B, \D, \d, \S, \s, \W, \w */ \ + 1, 1, 1, 1, 2, 1, 1, /* Any, Anybyte, \Z, \z, Opt, ^, $ */ \ + 2, /* Chars - the minimum length */ \ + 2, /* not */ \ + /* Positive single-char repeats */ \ + 2, 2, 2, 2, 2, 2, /* *, *?, +, +?, ?, ?? ** These are */ \ + 4, 4, 4, /* upto, minupto, exact ** minima */ \ + /* Negative single-char repeats */ \ + 2, 2, 2, 2, 2, 2, /* NOT *, *?, +, +?, ?, ?? */ \ + 4, 4, 4, /* NOT upto, minupto, exact */ \ + /* Positive type repeats */ \ + 2, 2, 2, 2, 2, 2, /* Type *, *?, +, +?, ?, ?? */ \ + 4, 4, 4, /* Type upto, minupto, exact */ \ + /* Character class & ref repeats */ \ + 1, 1, 1, 1, 1, 1, /* *, *?, +, +?, ?, ?? */ \ + 5, 5, /* CRRANGE, CRMINRANGE */ \ + 33, /* CLASS */ \ + 33, /* NCLASS */ \ + 0, /* XCLASS - variable length */ \ + 3, /* REF */ \ + 1+LINK_SIZE, /* RECURSE */ \ + 2, /* CALLOUT */ \ + 1+LINK_SIZE, /* Alt */ \ + 1+LINK_SIZE, /* Ket */ \ + 1+LINK_SIZE, /* KetRmax */ \ + 1+LINK_SIZE, /* KetRmin */ \ + 1+LINK_SIZE, /* Assert */ \ + 1+LINK_SIZE, /* Assert not */ \ + 1+LINK_SIZE, /* Assert behind */ \ + 1+LINK_SIZE, /* Assert behind not */ \ + 1+LINK_SIZE, /* Reverse */ \ + 1+LINK_SIZE, /* Once */ \ + 1+LINK_SIZE, /* COND */ \ + 3, /* CREF */ \ + 1, 1, /* BRAZERO, BRAMINZERO */ \ + 3, /* BRANUMBER */ \ + 1+LINK_SIZE /* BRA */ \ + + +/* The highest extraction number before we have to start using additional +bytes. (Originally PCRE didn't have support for extraction counts highter than +this number.) The value is limited by the number of opcodes left after OP_BRA, +i.e. 255 - OP_BRA. We actually set it a bit lower to leave room for additional +opcodes. */ + +#define EXTRACT_BASIC_MAX 150 + +/* A magic value for OP_CREF to indicate the "in recursion" condition. */ + +#define CREF_RECURSE 0xffff + +/* The texts of compile-time error messages are defined as macros here so that +they can be accessed by the POSIX wrapper and converted into error codes. Yes, +I could have used error codes in the first place, but didn't feel like changing +just to accommodate the POSIX wrapper. */ + +#define ERR1 "\\ at end of pattern" +#define ERR2 "\\c at end of pattern" +#define ERR3 "unrecognized character follows \\" +#define ERR4 "numbers out of order in {} quantifier" +#define ERR5 "number too big in {} quantifier" +#define ERR6 "missing terminating ] for character class" +#define ERR7 "invalid escape sequence in character class" +#define ERR8 "range out of order in character class" +#define ERR9 "nothing to repeat" +#define ERR10 "operand of unlimited repeat could match the empty string" +#define ERR11 "internal error: unexpected repeat" +#define ERR12 "unrecognized character after (?" +#define ERR13 "POSIX named classes are supported only within a class" +#define ERR14 "missing )" +#define ERR15 "reference to non-existent subpattern" +#define ERR16 "erroffset passed as NULL" +#define ERR17 "unknown option bit(s) set" +#define ERR18 "missing ) after comment" +#define ERR19 "parentheses nested too deeply" +#define ERR20 "regular expression too large" +#define ERR21 "failed to get memory" +#define ERR22 "unmatched parentheses" +#define ERR23 "internal error: code overflow" +#define ERR24 "unrecognized character after (?<" +#define ERR25 "lookbehind assertion is not fixed length" +#define ERR26 "malformed number after (?(" +#define ERR27 "conditional group contains more than two branches" +#define ERR28 "assertion expected after (?(" +#define ERR29 "(?R or (?digits must be followed by )" +#define ERR30 "unknown POSIX class name" +#define ERR31 "POSIX collating elements are not supported" +#define ERR32 "this version of PCRE is not compiled with PCRE_UTF8 support" +#define ERR33 "spare error" +#define ERR34 "character value in \\x{...} sequence is too large" +#define ERR35 "invalid condition (?(0)" +#define ERR36 "\\C not allowed in lookbehind assertion" +#define ERR37 "PCRE does not support \\L, \\l, \\N, \\P, \\p, \\U, \\u, or \\X" +#define ERR38 "number after (?C is > 255" +#define ERR39 "closing ) for (?C expected" +#define ERR40 "recursive call could loop indefinitely" +#define ERR41 "unrecognized character after (?P" +#define ERR42 "syntax error after (?P" +#define ERR43 "two named groups have the same name" + +/* All character handling must be done as unsigned characters. Otherwise there +are problems with top-bit-set characters and functions such as isspace(). +However, we leave the interface to the outside world as char *, because that +should make things easier for callers. We define a short type for unsigned char +to save lots of typing. I tried "uchar", but it causes problems on Digital +Unix, where it is defined in sys/types, so use "uschar" instead. */ + +typedef unsigned char uschar; + +/* The real format of the start of the pcre block; the index of names and the +code vector run on as long as necessary after the end. */ + +typedef struct real_pcre { + unsigned long int magic_number; + size_t size; /* Total that was malloced */ + const unsigned char *tables; /* Pointer to tables */ + unsigned long int options; + unsigned short int top_bracket; + unsigned short int top_backref; + unsigned short int first_byte; + unsigned short int req_byte; + unsigned short int name_entry_size; /* Size of any name items; 0 => none */ + unsigned short int name_count; /* Number of name items */ +} real_pcre; + +/* The format of the block used to store data from pcre_study(). */ + +typedef struct pcre_study_data { + size_t size; /* Total that was malloced */ + uschar options; + uschar start_bits[32]; +} pcre_study_data; + +/* Structure for passing "static" information around between the functions +doing the compiling, so that they are thread-safe. */ + +typedef struct compile_data { + const uschar *lcc; /* Points to lower casing table */ + const uschar *fcc; /* Points to case-flipping table */ + const uschar *cbits; /* Points to character type table */ + const uschar *ctypes; /* Points to table of type maps */ + const uschar *start_code; /* The start of the compiled code */ + uschar *name_table; /* The name/number table */ + int names_found; /* Number of entries so far */ + int name_entry_size; /* Size of each entry */ + int top_backref; /* Maximum back reference */ + unsigned int backref_map; /* Bitmap of low back refs */ + int req_varyopt; /* "After variable item" flag for reqbyte */ +} compile_data; + +/* Structure for maintaining a chain of pointers to the currently incomplete +branches, for testing for left recursion. */ + +typedef struct branch_chain { + struct branch_chain *outer; + uschar *current; +} branch_chain; + +/* Structure for items in a linked list that represents an explicit recursive +call within the pattern. */ + +typedef struct recursion_info { + struct recursion_info *prev; /* Previous recursion record (or NULL) */ + int group_num; /* Number of group that was called */ + const uschar *after_call; /* "Return value": points after the call in the expr */ + const uschar *save_start; /* Old value of md->start_match */ + int *offset_save; /* Pointer to start of saved offsets */ + int saved_max; /* Number of saved offsets */ +} recursion_info; + +/* Structure for passing "static" information around between the functions +doing the matching, so that they are thread-safe. */ + +typedef struct match_data { + unsigned long int match_call_count; /* As it says */ + unsigned long int match_limit;/* As it says */ + int *offset_vector; /* Offset vector */ + int offset_end; /* One past the end */ + int offset_max; /* The maximum usable for return data */ + const uschar *lcc; /* Points to lower casing table */ + const uschar *ctypes; /* Points to table of type maps */ + BOOL offset_overflow; /* Set if too many extractions */ + BOOL notbol; /* NOTBOL flag */ + BOOL noteol; /* NOTEOL flag */ + BOOL utf8; /* UTF8 flag */ + BOOL endonly; /* Dollar not before final \n */ + BOOL notempty; /* Empty string match not wanted */ + const uschar *start_code; /* For use when recursing */ + const uschar *start_subject; /* Start of the subject string */ + const uschar *end_subject; /* End of the subject string */ + const uschar *start_match; /* Start of this match attempt */ + const uschar *end_match_ptr; /* Subject position at end match */ + int end_offset_top; /* Highwater mark at end of match */ + int capture_last; /* Most recent capture number */ + int start_offset; /* The start offset value */ + recursion_info *recursive; /* Linked list of recursion data */ + void *callout_data; /* To pass back to callouts */ +} match_data; + +/* Bit definitions for entries in the pcre_ctypes table. */ + +#define ctype_space 0x01 +#define ctype_letter 0x02 +#define ctype_digit 0x04 +#define ctype_xdigit 0x08 +#define ctype_word 0x10 /* alphameric or '_' */ +#define ctype_meta 0x80 /* regexp meta char or zero (end pattern) */ + +/* Offsets for the bitmap tables in pcre_cbits. Each table contains a set +of bits for a class map. Some classes are built by combining these tables. */ + +#define cbit_space 0 /* [:space:] or \s */ +#define cbit_xdigit 32 /* [:xdigit:] */ +#define cbit_digit 64 /* [:digit:] or \d */ +#define cbit_upper 96 /* [:upper:] */ +#define cbit_lower 128 /* [:lower:] */ +#define cbit_word 160 /* [:word:] or \w */ +#define cbit_graph 192 /* [:graph:] */ +#define cbit_print 224 /* [:print:] */ +#define cbit_punct 256 /* [:punct:] */ +#define cbit_cntrl 288 /* [:cntrl:] */ +#define cbit_length 320 /* Length of the cbits table */ + +/* Offsets of the various tables from the base tables pointer, and +total length. */ + +#define lcc_offset 0 +#define fcc_offset 256 +#define cbits_offset 512 +#define ctypes_offset (cbits_offset + cbit_length) +#define tables_length (ctypes_offset + 256) + +/* End of internal.h */ diff --git a/mk4/continuity/pcre/ltmain.sh b/mk4/continuity/pcre/ltmain.sh new file mode 100644 index 0000000..de848c6 --- /dev/null +++ b/mk4/continuity/pcre/ltmain.sh @@ -0,0 +1,5069 @@ +# ltmain.sh - Provide generalized library-building support services. +# NOTE: Changing this file will not affect anything until you rerun configure. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001 +# Free Software Foundation, Inc. +# Originally by Gordon Matzigkeit , 1996 +# +# 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. +# +# 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. + +# Check that we have a working $echo. +if test "X$1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X$1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then + # Yippee, $echo works! + : +else + # Restart under the correct shell, and then maybe $echo will work. + exec $SHELL "$0" --no-reexec ${1+"$@"} +fi + +if test "X$1" = X--fallback-echo; then + # used as fallback echo + shift + cat <&2 + echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit 1 +fi + +# Global variables. +mode=$default_mode +nonopt= +prev= +prevopt= +run= +show="$echo" +show_help= +execute_dlfiles= +lo2o="s/\\.lo\$/.${objext}/" +o2lo="s/\\.${objext}\$/.lo/" + +# Parse our command line options once, thoroughly. +while test $# -gt 0 +do + arg="$1" + shift + + case $arg in + -*=*) optarg=`$echo "X$arg" | $Xsed -e 's/[-_a-zA-Z0-9]*=//'` ;; + *) optarg= ;; + esac + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case $prev in + execute_dlfiles) + execute_dlfiles="$execute_dlfiles $arg" + ;; + *) + eval "$prev=\$arg" + ;; + esac + + prev= + prevopt= + continue + fi + + # Have we seen a non-optional argument yet? + case $arg in + --help) + show_help=yes + ;; + + --version) + echo "$PROGRAM (GNU $PACKAGE) $VERSION$TIMESTAMP" + exit 0 + ;; + + --config) + ${SED} -e '1,/^# ### BEGIN LIBTOOL CONFIG/d' -e '/^# ### END LIBTOOL CONFIG/,$d' $0 + exit 0 + ;; + + --debug) + echo "$progname: enabling shell trace mode" + set -x + ;; + + --dry-run | -n) + run=: + ;; + + --features) + echo "host: $host" + if test "$build_libtool_libs" = yes; then + echo "enable shared libraries" + else + echo "disable shared libraries" + fi + if test "$build_old_libs" = yes; then + echo "enable static libraries" + else + echo "disable static libraries" + fi + exit 0 + ;; + + --finish) mode="finish" ;; + + --mode) prevopt="--mode" prev=mode ;; + --mode=*) mode="$optarg" ;; + + --preserve-dup-deps) duplicate_deps="yes" ;; + + --quiet | --silent) + show=: + ;; + + -dlopen) + prevopt="-dlopen" + prev=execute_dlfiles + ;; + + -*) + $echo "$modename: unrecognized option \`$arg'" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; + + *) + nonopt="$arg" + break + ;; + esac +done + +if test -n "$prevopt"; then + $echo "$modename: option \`$prevopt' requires an argument" 1>&2 + $echo "$help" 1>&2 + exit 1 +fi + +# If this variable is set in any of the actions, the command in it +# will be execed at the end. This prevents here-documents from being +# left over by shells. +exec_cmd= + +if test -z "$show_help"; then + + # Infer the operation mode. + if test -z "$mode"; then + case $nonopt in + *cc | *++ | gcc* | *-gcc* | xlc*) + mode=link + for arg + do + case $arg in + -c) + mode=compile + break + ;; + esac + done + ;; + *db | *dbx | *strace | *truss) + mode=execute + ;; + *install*|cp|mv) + mode=install + ;; + *rm) + mode=uninstall + ;; + *) + # If we have no mode, but dlfiles were specified, then do execute mode. + test -n "$execute_dlfiles" && mode=execute + + # Just use the default operation mode. + if test -z "$mode"; then + if test -n "$nonopt"; then + $echo "$modename: warning: cannot infer operation mode from \`$nonopt'" 1>&2 + else + $echo "$modename: warning: cannot infer operation mode without MODE-ARGS" 1>&2 + fi + fi + ;; + esac + fi + + # Only execute mode is allowed to have -dlopen flags. + if test -n "$execute_dlfiles" && test "$mode" != execute; then + $echo "$modename: unrecognized option \`-dlopen'" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + # Change the help message to a mode-specific one. + generic_help="$help" + help="Try \`$modename --help --mode=$mode' for more information." + + # These modes are in order of execution frequency so that they run quickly. + case $mode in + # libtool compile mode + compile) + modename="$modename: compile" + # Get the compilation command and the source file. + base_compile= + prev= + lastarg= + srcfile="$nonopt" + suppress_output= + + user_target=no + for arg + do + case $prev in + "") ;; + xcompiler) + # Aesthetically quote the previous argument. + prev= + lastarg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + + case $arg in + # Double-quote args containing other shell metacharacters. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + + # Add the previous argument to base_compile. + if test -z "$base_compile"; then + base_compile="$lastarg" + else + base_compile="$base_compile $lastarg" + fi + continue + ;; + esac + + # Accept any command-line options. + case $arg in + -o) + if test "$user_target" != "no"; then + $echo "$modename: you cannot specify \`-o' more than once" 1>&2 + exit 1 + fi + user_target=next + ;; + + -static) + build_old_libs=yes + continue + ;; + + -prefer-pic) + pic_mode=yes + continue + ;; + + -prefer-non-pic) + pic_mode=no + continue + ;; + + -Xcompiler) + prev=xcompiler + continue + ;; + + -Wc,*) + args=`$echo "X$arg" | $Xsed -e "s/^-Wc,//"` + lastarg= + save_ifs="$IFS"; IFS=',' + for arg in $args; do + IFS="$save_ifs" + + # Double-quote args containing other shell metacharacters. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + lastarg="$lastarg $arg" + done + IFS="$save_ifs" + lastarg=`$echo "X$lastarg" | $Xsed -e "s/^ //"` + + # Add the arguments to base_compile. + if test -z "$base_compile"; then + base_compile="$lastarg" + else + base_compile="$base_compile $lastarg" + fi + continue + ;; + esac + + case $user_target in + next) + # The next one is the -o target name + user_target=yes + continue + ;; + yes) + # We got the output file + user_target=set + libobj="$arg" + continue + ;; + esac + + # Accept the current argument as the source file. + lastarg="$srcfile" + srcfile="$arg" + + # Aesthetically quote the previous argument. + + # Backslashify any backslashes, double quotes, and dollar signs. + # These are the only characters that are still specially + # interpreted inside of double-quoted scrings. + lastarg=`$echo "X$lastarg" | $Xsed -e "$sed_quote_subst"` + + # Double-quote args containing other shell metacharacters. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + case $lastarg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + lastarg="\"$lastarg\"" + ;; + esac + + # Add the previous argument to base_compile. + if test -z "$base_compile"; then + base_compile="$lastarg" + else + base_compile="$base_compile $lastarg" + fi + done + + case $user_target in + set) + ;; + no) + # Get the name of the library object. + libobj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%'` + ;; + *) + $echo "$modename: you must specify a target with \`-o'" 1>&2 + exit 1 + ;; + esac + + # Recognize several different file suffixes. + # If the user specifies -o file.o, it is replaced with file.lo + xform='[cCFSfmso]' + case $libobj in + *.ada) xform=ada ;; + *.adb) xform=adb ;; + *.ads) xform=ads ;; + *.asm) xform=asm ;; + *.c++) xform=c++ ;; + *.cc) xform=cc ;; + *.cpp) xform=cpp ;; + *.cxx) xform=cxx ;; + *.f90) xform=f90 ;; + *.for) xform=for ;; + esac + + libobj=`$echo "X$libobj" | $Xsed -e "s/\.$xform$/.lo/"` + + case $libobj in + *.lo) obj=`$echo "X$libobj" | $Xsed -e "$lo2o"` ;; + *) + $echo "$modename: cannot determine name of library object from \`$libobj'" 1>&2 + exit 1 + ;; + esac + + if test -z "$base_compile"; then + $echo "$modename: you must specify a compilation command" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + # Delete any leftover library objects. + if test "$build_old_libs" = yes; then + removelist="$obj $libobj" + else + removelist="$libobj" + fi + + $run $rm $removelist + trap "$run $rm $removelist; exit 1" 1 2 15 + + # On Cygwin there's no "real" PIC flag so we must build both object types + case $host_os in + cygwin* | mingw* | pw32* | os2*) + pic_mode=default + ;; + esac + if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then + # non-PIC code in shared libraries is not supported + pic_mode=default + fi + + # Calculate the filename of the output object if compiler does + # not support -o with -c + if test "$compiler_c_o" = no; then + output_obj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\.[^.]*$%%'`.${objext} + lockfile="$output_obj.lock" + removelist="$removelist $output_obj $lockfile" + trap "$run $rm $removelist; exit 1" 1 2 15 + else + need_locks=no + lockfile= + fi + + # Lock this critical section if it is needed + # We use this script file to make the link, it avoids creating a new file + if test "$need_locks" = yes; then + until $run ln "$0" "$lockfile" 2>/dev/null; do + $show "Waiting for $lockfile to be removed" + sleep 2 + done + elif test "$need_locks" = warn; then + if test -f "$lockfile"; then + echo "\ +*** ERROR, $lockfile exists and contains: +`cat $lockfile 2>/dev/null` + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $run $rm $removelist + exit 1 + fi + echo $srcfile > "$lockfile" + fi + + if test -n "$fix_srcfile_path"; then + eval srcfile=\"$fix_srcfile_path\" + fi + + # Only build a PIC object if we are building libtool libraries. + if test "$build_libtool_libs" = yes; then + # Without this assignment, base_compile gets emptied. + fbsd_hideous_sh_bug=$base_compile + + if test "$pic_mode" != no; then + # All platforms use -DPIC, to notify preprocessed assembler code. + command="$base_compile $srcfile $pic_flag -DPIC" + else + # Don't build PIC code + command="$base_compile $srcfile" + fi + if test "$build_old_libs" = yes; then + lo_libobj="$libobj" + dir=`$echo "X$libobj" | $Xsed -e 's%/[^/]*$%%'` + if test "X$dir" = "X$libobj"; then + dir="$objdir" + else + dir="$dir/$objdir" + fi + libobj="$dir/"`$echo "X$libobj" | $Xsed -e 's%^.*/%%'` + + if test -d "$dir"; then + $show "$rm $libobj" + $run $rm $libobj + else + $show "$mkdir $dir" + $run $mkdir $dir + status=$? + if test $status -ne 0 && test ! -d $dir; then + exit $status + fi + fi + fi + if test "$compiler_o_lo" = yes; then + output_obj="$libobj" + command="$command -o $output_obj" + elif test "$compiler_c_o" = yes; then + output_obj="$obj" + command="$command -o $output_obj" + fi + + $run $rm "$output_obj" + $show "$command" + if $run eval "$command"; then : + else + test -n "$output_obj" && $run $rm $removelist + exit 1 + fi + + if test "$need_locks" = warn && + test x"`cat $lockfile 2>/dev/null`" != x"$srcfile"; then + echo "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $run $rm $removelist + exit 1 + fi + + # Just move the object if needed, then go on to compile the next one + if test x"$output_obj" != x"$libobj"; then + $show "$mv $output_obj $libobj" + if $run $mv $output_obj $libobj; then : + else + error=$? + $run $rm $removelist + exit $error + fi + fi + + # If we have no pic_flag, then copy the object into place and finish. + if (test -z "$pic_flag" || test "$pic_mode" != default) && + test "$build_old_libs" = yes; then + # Rename the .lo from within objdir to obj + if test -f $obj; then + $show $rm $obj + $run $rm $obj + fi + + $show "$mv $libobj $obj" + if $run $mv $libobj $obj; then : + else + error=$? + $run $rm $removelist + exit $error + fi + + xdir=`$echo "X$obj" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$obj"; then + xdir="." + else + xdir="$xdir" + fi + baseobj=`$echo "X$obj" | $Xsed -e "s%.*/%%"` + libobj=`$echo "X$baseobj" | $Xsed -e "$o2lo"` + # Now arrange that obj and lo_libobj become the same file + $show "(cd $xdir && $LN_S $baseobj $libobj)" + if $run eval '(cd $xdir && $LN_S $baseobj $libobj)'; then + # Unlock the critical section if it was locked + if test "$need_locks" != no; then + $run $rm "$lockfile" + fi + exit 0 + else + error=$? + $run $rm $removelist + exit $error + fi + fi + + # Allow error messages only from the first compilation. + suppress_output=' >/dev/null 2>&1' + fi + + # Only build a position-dependent object if we build old libraries. + if test "$build_old_libs" = yes; then + if test "$pic_mode" != yes; then + # Don't build PIC code + command="$base_compile $srcfile" + else + # All platforms use -DPIC, to notify preprocessed assembler code. + command="$base_compile $srcfile $pic_flag -DPIC" + fi + if test "$compiler_c_o" = yes; then + command="$command -o $obj" + output_obj="$obj" + fi + + # Suppress compiler output if we already did a PIC compilation. + command="$command$suppress_output" + $run $rm "$output_obj" + $show "$command" + if $run eval "$command"; then : + else + $run $rm $removelist + exit 1 + fi + + if test "$need_locks" = warn && + test x"`cat $lockfile 2>/dev/null`" != x"$srcfile"; then + echo "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $run $rm $removelist + exit 1 + fi + + # Just move the object if needed + if test x"$output_obj" != x"$obj"; then + $show "$mv $output_obj $obj" + if $run $mv $output_obj $obj; then : + else + error=$? + $run $rm $removelist + exit $error + fi + fi + + # Create an invalid libtool object if no PIC, so that we do not + # accidentally link it into a program. + if test "$build_libtool_libs" != yes; then + $show "echo timestamp > $libobj" + $run eval "echo timestamp > \$libobj" || exit $? + else + # Move the .lo from within objdir + $show "$mv $libobj $lo_libobj" + if $run $mv $libobj $lo_libobj; then : + else + error=$? + $run $rm $removelist + exit $error + fi + fi + fi + + # Unlock the critical section if it was locked + if test "$need_locks" != no; then + $run $rm "$lockfile" + fi + + exit 0 + ;; + + # libtool link mode + link | relink) + modename="$modename: link" + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) + # It is impossible to link a dll without this setting, and + # we shouldn't force the makefile maintainer to figure out + # which system we are compiling for in order to pass an extra + # flag for every libtool invokation. + # allow_undefined=no + + # FIXME: Unfortunately, there are problems with the above when trying + # to make a dll which has undefined symbols, in which case not + # even a static library is built. For now, we need to specify + # -no-undefined on the libtool link line when we can be certain + # that all symbols are satisfied, otherwise we get a static library. + allow_undefined=yes + ;; + *) + allow_undefined=yes + ;; + esac + libtool_args="$nonopt" + compile_command="$nonopt" + finalize_command="$nonopt" + + compile_rpath= + finalize_rpath= + compile_shlibpath= + finalize_shlibpath= + convenience= + old_convenience= + deplibs= + old_deplibs= + compiler_flags= + linker_flags= + dllsearchpath= + lib_search_path=`pwd` + + avoid_version=no + dlfiles= + dlprefiles= + dlself=no + export_dynamic=no + export_symbols= + export_symbols_regex= + generated= + libobjs= + ltlibs= + module=no + no_install=no + objs= + prefer_static_libs=no + preload=no + prev= + prevarg= + release= + rpath= + xrpath= + perm_rpath= + temp_rpath= + thread_safe=no + vinfo= + + # We need to know -static, to get the right output filenames. + for arg + do + case $arg in + -all-static | -static) + if test "X$arg" = "X-all-static"; then + if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then + $echo "$modename: warning: complete static linking is impossible in this configuration" 1>&2 + fi + if test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + else + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + fi + build_libtool_libs=no + build_old_libs=yes + prefer_static_libs=yes + break + ;; + esac + done + + # See if our shared archives depend on static archives. + test -n "$old_archive_from_new_cmds" && build_old_libs=yes + + # Go through the arguments, transforming them on the way. + while test $# -gt 0; do + arg="$1" + shift + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + qarg=\"`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`\" ### testsuite: skip nested quoting test + ;; + *) qarg=$arg ;; + esac + libtool_args="$libtool_args $qarg" + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case $prev in + output) + compile_command="$compile_command @OUTPUT@" + finalize_command="$finalize_command @OUTPUT@" + ;; + esac + + case $prev in + dlfiles|dlprefiles) + if test "$preload" = no; then + # Add the symbol object into the linking commands. + compile_command="$compile_command @SYMFILE@" + finalize_command="$finalize_command @SYMFILE@" + preload=yes + fi + case $arg in + *.la | *.lo) ;; # We handle these cases below. + force) + if test "$dlself" = no; then + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + self) + if test "$prev" = dlprefiles; then + dlself=yes + elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then + dlself=yes + else + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + *) + if test "$prev" = dlfiles; then + dlfiles="$dlfiles $arg" + else + dlprefiles="$dlprefiles $arg" + fi + prev= + continue + ;; + esac + ;; + expsyms) + export_symbols="$arg" + if test ! -f "$arg"; then + $echo "$modename: symbol file \`$arg' does not exist" + exit 1 + fi + prev= + continue + ;; + expsyms_regex) + export_symbols_regex="$arg" + prev= + continue + ;; + release) + release="-$arg" + prev= + continue + ;; + rpath | xrpath) + # We need an absolute path. + case $arg in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + $echo "$modename: only absolute run-paths are allowed" 1>&2 + exit 1 + ;; + esac + if test "$prev" = rpath; then + case "$rpath " in + *" $arg "*) ;; + *) rpath="$rpath $arg" ;; + esac + else + case "$xrpath " in + *" $arg "*) ;; + *) xrpath="$xrpath $arg" ;; + esac + fi + prev= + continue + ;; + xcompiler) + compiler_flags="$compiler_flags $qarg" + prev= + compile_command="$compile_command $qarg" + finalize_command="$finalize_command $qarg" + continue + ;; + xlinker) + linker_flags="$linker_flags $qarg" + compiler_flags="$compiler_flags $wl$qarg" + prev= + compile_command="$compile_command $wl$qarg" + finalize_command="$finalize_command $wl$qarg" + continue + ;; + *) + eval "$prev=\"\$arg\"" + prev= + continue + ;; + esac + fi # test -n $prev + + prevarg="$arg" + + case $arg in + -all-static) + if test -n "$link_static_flag"; then + compile_command="$compile_command $link_static_flag" + finalize_command="$finalize_command $link_static_flag" + fi + continue + ;; + + -allow-undefined) + # FIXME: remove this flag sometime in the future. + $echo "$modename: \`-allow-undefined' is deprecated because it is the default" 1>&2 + continue + ;; + + -avoid-version) + avoid_version=yes + continue + ;; + + -dlopen) + prev=dlfiles + continue + ;; + + -dlpreopen) + prev=dlprefiles + continue + ;; + + -export-dynamic) + export_dynamic=yes + continue + ;; + + -export-symbols | -export-symbols-regex) + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + $echo "$modename: more than one -exported-symbols argument is not allowed" + exit 1 + fi + if test "X$arg" = "X-export-symbols"; then + prev=expsyms + else + prev=expsyms_regex + fi + continue + ;; + + # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* + # so, if we see these flags be careful not to treat them like -L + -L[A-Z][A-Z]*:*) + case $with_gcc/$host in + no/*-*-irix* | no/*-*-nonstopux*) + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + ;; + esac + continue + ;; + + -L*) + dir=`$echo "X$arg" | $Xsed -e 's/^-L//'` + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + $echo "$modename: cannot determine absolute directory name of \`$dir'" 1>&2 + exit 1 + fi + dir="$absdir" + ;; + esac + case "$deplibs " in + *" -L$dir "*) ;; + *) + deplibs="$deplibs -L$dir" + lib_search_path="$lib_search_path $dir" + ;; + esac + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) + case :$dllsearchpath: in + *":$dir:"*) ;; + *) dllsearchpath="$dllsearchpath:$dir";; + esac + ;; + esac + continue + ;; + + -l*) + if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then + case $host in + *-*-cygwin* | *-*-pw32* | *-*-beos*) + # These systems don't actually have a C or math library (as such) + continue + ;; + *-*-mingw* | *-*-os2*) + # These systems don't actually have a C library (as such) + test "X$arg" = "X-lc" && continue + ;; + *-*-openbsd* | *-*-freebsd*) + # Do not include libc due to us having libc/libc_r. + test "X$arg" = "X-lc" && continue + ;; + esac + elif test "X$arg" = "X-lc_r"; then + case $host in + *-*-openbsd* | *-*-freebsd*) + # Do not include libc_r directly, use -pthread flag. + continue + ;; + esac + fi + deplibs="$deplibs $arg" + continue + ;; + + -module) + module=yes + continue + ;; + + -no-fast-install) + fast_install=no + continue + ;; + + -no-install) + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) + # The PATH hackery in wrapper scripts is required on Windows + # in order for the loader to find any dlls it needs. + $echo "$modename: warning: \`-no-install' is ignored for $host" 1>&2 + $echo "$modename: warning: assuming \`-no-fast-install' instead" 1>&2 + fast_install=no + ;; + *) no_install=yes ;; + esac + continue + ;; + + -no-undefined) + allow_undefined=no + continue + ;; + + -o) prev=output ;; + + -release) + prev=release + continue + ;; + + -rpath) + prev=rpath + continue + ;; + + -R) + prev=xrpath + continue + ;; + + -R*) + dir=`$echo "X$arg" | $Xsed -e 's/^-R//'` + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + $echo "$modename: only absolute run-paths are allowed" 1>&2 + exit 1 + ;; + esac + case "$xrpath " in + *" $dir "*) ;; + *) xrpath="$xrpath $dir" ;; + esac + continue + ;; + + -static) + # The effects of -static are defined in a previous loop. + # We used to do the same as -all-static on platforms that + # didn't have a PIC flag, but the assumption that the effects + # would be equivalent was wrong. It would break on at least + # Digital Unix and AIX. + continue + ;; + + -thread-safe) + thread_safe=yes + continue + ;; + + -version-info) + prev=vinfo + continue + ;; + + -Wc,*) + args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wc,//'` + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + case $flag in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + flag="\"$flag\"" + ;; + esac + arg="$arg $wl$flag" + compiler_flags="$compiler_flags $flag" + done + IFS="$save_ifs" + arg=`$echo "X$arg" | $Xsed -e "s/^ //"` + ;; + + -Wl,*) + args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wl,//'` + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + case $flag in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + flag="\"$flag\"" + ;; + esac + arg="$arg $wl$flag" + compiler_flags="$compiler_flags $wl$flag" + linker_flags="$linker_flags $flag" + done + IFS="$save_ifs" + arg=`$echo "X$arg" | $Xsed -e "s/^ //"` + ;; + + -Xcompiler) + prev=xcompiler + continue + ;; + + -Xlinker) + prev=xlinker + continue + ;; + + # Some other compiler flag. + -* | +*) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + ;; + + *.lo | *.$objext) + # A library or standard object. + if test "$prev" = dlfiles; then + # This file was specified with -dlopen. + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + dlfiles="$dlfiles $arg" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + if test "$prev" = dlprefiles; then + # Preload the old-style object. + dlprefiles="$dlprefiles "`$echo "X$arg" | $Xsed -e "$lo2o"` + prev= + else + case $arg in + *.lo) libobjs="$libobjs $arg" ;; + *) objs="$objs $arg" ;; + esac + fi + ;; + + *.$libext) + # An archive. + deplibs="$deplibs $arg" + old_deplibs="$old_deplibs $arg" + continue + ;; + + *.la) + # A libtool-controlled library. + + if test "$prev" = dlfiles; then + # This library was specified with -dlopen. + dlfiles="$dlfiles $arg" + prev= + elif test "$prev" = dlprefiles; then + # The library was specified with -dlpreopen. + dlprefiles="$dlprefiles $arg" + prev= + else + deplibs="$deplibs $arg" + fi + continue + ;; + + # Some other compiler argument. + *) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + ;; + esac # arg + + # Now actually substitute the argument into the commands. + if test -n "$arg"; then + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + fi + done # argument parsing loop + + if test -n "$prev"; then + $echo "$modename: the \`$prevarg' option requires an argument" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then + eval arg=\"$export_dynamic_flag_spec\" + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + fi + + # calculate the name of the file, without its directory + outputname=`$echo "X$output" | $Xsed -e 's%^.*/%%'` + libobjs_save="$libobjs" + + if test -n "$shlibpath_var"; then + # get the directories listed in $shlibpath_var + eval shlib_search_path=\`\$echo \"X\${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\` + else + shlib_search_path= + fi + eval sys_lib_search_path=\"$sys_lib_search_path_spec\" + eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" + + output_objdir=`$echo "X$output" | $Xsed -e 's%/[^/]*$%%'` + if test "X$output_objdir" = "X$output"; then + output_objdir="$objdir" + else + output_objdir="$output_objdir/$objdir" + fi + # Create the object directory. + if test ! -d $output_objdir; then + $show "$mkdir $output_objdir" + $run $mkdir $output_objdir + status=$? + if test $status -ne 0 && test ! -d $output_objdir; then + exit $status + fi + fi + + # Determine the type of output + case $output in + "") + $echo "$modename: you must specify an output file" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; + *.$libext) linkmode=oldlib ;; + *.lo | *.$objext) linkmode=obj ;; + *.la) linkmode=lib ;; + *) linkmode=prog ;; # Anything else should be a program. + esac + + specialdeplibs= + libs= + # Find all interdependent deplibs by searching for libraries + # that are linked more than once (e.g. -la -lb -la) + for deplib in $deplibs; do + if test "X$duplicate_deps" = "Xyes" ; then + case "$libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + libs="$libs $deplib" + done + deplibs= + newdependency_libs= + newlib_search_path= + need_relink=no # whether we're linking any uninstalled libtool libraries + notinst_deplibs= # not-installed libtool libraries + notinst_path= # paths that contain not-installed libtool libraries + case $linkmode in + lib) + passes="conv link" + for file in $dlfiles $dlprefiles; do + case $file in + *.la) ;; + *) + $echo "$modename: libraries can \`-dlopen' only libtool libraries: $file" 1>&2 + exit 1 + ;; + esac + done + ;; + prog) + compile_deplibs= + finalize_deplibs= + alldeplibs=no + newdlfiles= + newdlprefiles= + passes="conv scan dlopen dlpreopen link" + ;; + *) passes="conv" + ;; + esac + for pass in $passes; do + if test $linkmode = prog; then + # Determine which files to process + case $pass in + dlopen) + libs="$dlfiles" + save_deplibs="$deplibs" # Collect dlpreopened libraries + deplibs= + ;; + dlpreopen) libs="$dlprefiles" ;; + link) libs="$deplibs %DEPLIBS% $dependency_libs" ;; + esac + fi + for deplib in $libs; do + lib= + found=no + case $deplib in + -l*) + if test $linkmode = oldlib && test $linkmode = obj; then + $echo "$modename: warning: \`-l' is ignored for archives/objects: $deplib" 1>&2 + continue + fi + if test $pass = conv; then + deplibs="$deplib $deplibs" + continue + fi + name=`$echo "X$deplib" | $Xsed -e 's/^-l//'` + for searchdir in $newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path; do + # Search the libtool library + lib="$searchdir/lib${name}.la" + if test -f "$lib"; then + found=yes + break + fi + done + if test "$found" != yes; then + # deplib doesn't seem to be a libtool library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test $linkmode = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + fi + ;; # -l + -L*) + case $linkmode in + lib) + deplibs="$deplib $deplibs" + test $pass = conv && continue + newdependency_libs="$deplib $newdependency_libs" + newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'` + ;; + prog) + if test $pass = conv; then + deplibs="$deplib $deplibs" + continue + fi + if test $pass = scan; then + deplibs="$deplib $deplibs" + newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'` + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + ;; + *) + $echo "$modename: warning: \`-L' is ignored for archives/objects: $deplib" 1>&2 + ;; + esac # linkmode + continue + ;; # -L + -R*) + if test $pass = link; then + dir=`$echo "X$deplib" | $Xsed -e 's/^-R//'` + # Make sure the xrpath contains only unique directories. + case "$xrpath " in + *" $dir "*) ;; + *) xrpath="$xrpath $dir" ;; + esac + fi + deplibs="$deplib $deplibs" + continue + ;; + *.la) lib="$deplib" ;; + *.$libext) + if test $pass = conv; then + deplibs="$deplib $deplibs" + continue + fi + case $linkmode in + lib) + if test "$deplibs_check_method" != pass_all; then + echo + echo "*** Warning: Trying to link with static lib archive $deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have" + echo "*** because the file extensions .$libext of this argument makes me believe" + echo "*** that it is just a static archive that I should not used here." + else + echo + echo "*** Warning: Linking the shared library $output against the" + echo "*** static library $deplib is not portable!" + deplibs="$deplib $deplibs" + fi + continue + ;; + prog) + if test $pass != link; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + continue + ;; + esac # linkmode + ;; # *.$libext + *.lo | *.$objext) + if test $pass = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then + # If there is no dlopen support or we're linking statically, + # we need to preload. + newdlprefiles="$newdlprefiles $deplib" + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + newdlfiles="$newdlfiles $deplib" + fi + continue + ;; + %DEPLIBS%) + alldeplibs=yes + continue + ;; + esac # case $deplib + if test $found = yes || test -f "$lib"; then : + else + $echo "$modename: cannot find the library \`$lib'" 1>&2 + exit 1 + fi + + # Check to see that this really is a libtool archive. + if (${SED} -e '2q' $lib | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : + else + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + exit 1 + fi + + ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'` + test "X$ladir" = "X$lib" && ladir="." + + dlname= + dlopen= + dlpreopen= + libdir= + library_names= + old_library= + # If the library was installed with an old release of libtool, + # it will not redefine variable installed. + installed=yes + + # Read the .la file + case $lib in + */* | *\\*) . $lib ;; + *) . ./$lib ;; + esac + + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan" || + { test $linkmode = oldlib && test $linkmode = obj; }; then + # Add dl[pre]opened files of deplib + test -n "$dlopen" && dlfiles="$dlfiles $dlopen" + test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen" + fi + + if test $pass = conv; then + # Only check for convenience libraries + deplibs="$lib $deplibs" + if test -z "$libdir"; then + if test -z "$old_library"; then + $echo "$modename: cannot find name of link library for \`$lib'" 1>&2 + exit 1 + fi + # It is a libtool convenience library, so add in its objects. + convenience="$convenience $ladir/$objdir/$old_library" + old_convenience="$old_convenience $ladir/$objdir/$old_library" + tmp_libs= + for deplib in $dependency_libs; do + deplibs="$deplib $deplibs" + if test "X$duplicate_deps" = "Xyes" ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done + elif test $linkmode != prog && test $linkmode != lib; then + $echo "$modename: \`$lib' is not a convenience library" 1>&2 + exit 1 + fi + continue + fi # $pass = conv + + # Get the name of the library we link against. + linklib= + for l in $old_library $library_names; do + linklib="$l" + done + if test -z "$linklib"; then + $echo "$modename: cannot find name of link library for \`$lib'" 1>&2 + exit 1 + fi + + # This library was specified with -dlopen. + if test $pass = dlopen; then + if test -z "$libdir"; then + $echo "$modename: cannot -dlopen a convenience library: \`$lib'" 1>&2 + exit 1 + fi + if test -z "$dlname" || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then + # If there is no dlname, no dlopen support or we're linking + # statically, we need to preload. + dlprefiles="$dlprefiles $lib" + else + newdlfiles="$newdlfiles $lib" + fi + continue + fi # $pass = dlopen + + # We need an absolute path. + case $ladir in + [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; + *) + abs_ladir=`cd "$ladir" && pwd` + if test -z "$abs_ladir"; then + $echo "$modename: warning: cannot determine absolute directory name of \`$ladir'" 1>&2 + $echo "$modename: passing it literally to the linker, although it might fail" 1>&2 + abs_ladir="$ladir" + fi + ;; + esac + laname=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` + + # Find the relevant object directory and library name. + if test "X$installed" = Xyes; then + if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then + $echo "$modename: warning: library \`$lib' was moved." 1>&2 + dir="$ladir" + absdir="$abs_ladir" + libdir="$abs_ladir" + else + dir="$libdir" + absdir="$libdir" + fi + else + dir="$ladir/$objdir" + absdir="$abs_ladir/$objdir" + # Remove this search path later + notinst_path="$notinst_path $abs_ladir" + fi # $installed = yes + name=`$echo "X$laname" | $Xsed -e 's/\.la$//' -e 's/^lib//'` + + # This library was specified with -dlpreopen. + if test $pass = dlpreopen; then + if test -z "$libdir"; then + $echo "$modename: cannot -dlpreopen a convenience library: \`$lib'" 1>&2 + exit 1 + fi + # Prefer using a static library (so that no silly _DYNAMIC symbols + # are required to link). + if test -n "$old_library"; then + newdlprefiles="$newdlprefiles $dir/$old_library" + # Otherwise, use the dlname, so that lt_dlopen finds it. + elif test -n "$dlname"; then + newdlprefiles="$newdlprefiles $dir/$dlname" + else + newdlprefiles="$newdlprefiles $dir/$linklib" + fi + fi # $pass = dlpreopen + + if test -z "$libdir"; then + # Link the convenience library + if test $linkmode = lib; then + deplibs="$dir/$old_library $deplibs" + elif test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$dir/$old_library $compile_deplibs" + finalize_deplibs="$dir/$old_library $finalize_deplibs" + else + deplibs="$lib $deplibs" + fi + continue + fi + + if test $linkmode = prog && test $pass != link; then + newlib_search_path="$newlib_search_path $ladir" + deplibs="$lib $deplibs" + + linkalldeplibs=no + if test "$link_all_deplibs" != no || test -z "$library_names" || + test "$build_libtool_libs" = no; then + linkalldeplibs=yes + fi + + tmp_libs= + for deplib in $dependency_libs; do + case $deplib in + -L*) newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`;; ### testsuite: skip nested quoting test + esac + # Need to link against all dependency_libs? + if test $linkalldeplibs = yes; then + deplibs="$deplib $deplibs" + else + # Need to hardcode shared library paths + # or/and link against static libraries + newdependency_libs="$deplib $newdependency_libs" + fi + if test "X$duplicate_deps" = "Xyes" ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done # for deplib + continue + fi # $linkmode = prog... + + link_static=no # Whether the deplib will be linked statically + if test -n "$library_names" && + { test "$prefer_static_libs" = no || test -z "$old_library"; }; then + # Link against this shared library + + if test "$linkmode,$pass" = "prog,link" || + { test $linkmode = lib && test $hardcode_into_libs = yes; }; then + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) compile_rpath="$compile_rpath $absdir" + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" + esac + ;; + esac + if test $linkmode = prog; then + # We need to hardcode the library path + if test -n "$shlibpath_var"; then + # Make sure the rpath contains only unique directories. + case "$temp_rpath " in + *" $dir "*) ;; + *" $absdir "*) ;; + *) temp_rpath="$temp_rpath $dir" ;; + esac + fi + fi + fi # $linkmode,$pass = prog,link... + + if test "$alldeplibs" = yes && + { test "$deplibs_check_method" = pass_all || + { test "$build_libtool_libs" = yes && + test -n "$library_names"; }; }; then + # We only need to search for static libraries + continue + fi + + if test "$installed" = no; then + notinst_deplibs="$notinst_deplibs $lib" + need_relink=yes + fi + + if test -n "$old_archive_from_expsyms_cmds"; then + # figure out the soname + set dummy $library_names + realname="$2" + shift; shift + libname=`eval \\$echo \"$libname_spec\"` + # use dlname if we got it. it's perfectly good, no? + if test -n "$dlname"; then + soname="$dlname" + elif test -n "$soname_spec"; then + # bleh windows + case $host in + *cygwin*) + major=`expr $current - $age` + versuffix="-$major" + ;; + esac + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + + # Make a new name for the extract_expsyms_cmds to use + soroot="$soname" + soname=`echo $soroot | ${SED} -e 's/^.*\///'` + newlib="libimp-`echo $soname | ${SED} 's/^lib//;s/\.dll$//'`.a" + + # If the library has no export list, then create one now + if test -f "$output_objdir/$soname-def"; then : + else + $show "extracting exported symbol list from \`$soname'" + save_ifs="$IFS"; IFS='~' + eval cmds=\"$extract_expsyms_cmds\" + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + + # Create $newlib + if test -f "$output_objdir/$newlib"; then :; else + $show "generating import library for \`$soname'" + save_ifs="$IFS"; IFS='~' + eval cmds=\"$old_archive_from_expsyms_cmds\" + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + # make sure the library variables are pointing to the new library + dir=$output_objdir + linklib=$newlib + fi # test -n $old_archive_from_expsyms_cmds + + if test $linkmode = prog || test "$mode" != relink; then + add_shlibpath= + add_dir= + add= + lib_linked=yes + case $hardcode_action in + immediate | unsupported) + if test "$hardcode_direct" = no; then + add="$dir/$linklib" + elif test "$hardcode_minus_L" = no; then + case $host in + *-*-sunos*) add_shlibpath="$dir" ;; + esac + add_dir="-L$dir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = no; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + relink) + if test "$hardcode_direct" = yes; then + add="$dir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$dir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + *) lib_linked=no ;; + esac + + if test "$lib_linked" != yes; then + $echo "$modename: configuration error: unsupported hardcode properties" + exit 1 + fi + + if test -n "$add_shlibpath"; then + case :$compile_shlibpath: in + *":$add_shlibpath:"*) ;; + *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;; + esac + fi + if test $linkmode = prog; then + test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" + test -n "$add" && compile_deplibs="$add $compile_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + if test "$hardcode_direct" != yes && \ + test "$hardcode_minus_L" != yes && \ + test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; + esac + fi + fi + fi + + if test $linkmode = prog || test "$mode" = relink; then + add_shlibpath= + add_dir= + add= + # Finalize command for both is simple: just hardcode it. + if test "$hardcode_direct" = yes; then + add="$libdir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$libdir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; + esac + add="-l$name" + else + # We cannot seem to hardcode it, guess we'll fake it. + add_dir="-L$libdir" + add="-l$name" + fi + + if test $linkmode = prog; then + test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" + test -n "$add" && finalize_deplibs="$add $finalize_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + fi + fi + elif test $linkmode = prog; then + if test "$alldeplibs" = yes && + { test "$deplibs_check_method" = pass_all || + { test "$build_libtool_libs" = yes && + test -n "$library_names"; }; }; then + # We only need to search for static libraries + continue + fi + + # Try to link the static library + # Here we assume that one of hardcode_direct or hardcode_minus_L + # is not unsupported. This is valid on all known static and + # shared platforms. + if test "$hardcode_direct" != unsupported; then + test -n "$old_library" && linklib="$old_library" + compile_deplibs="$dir/$linklib $compile_deplibs" + finalize_deplibs="$dir/$linklib $finalize_deplibs" + else + compile_deplibs="-l$name -L$dir $compile_deplibs" + finalize_deplibs="-l$name -L$dir $finalize_deplibs" + fi + elif test "$build_libtool_libs" = yes; then + # Not a shared library + if test "$deplibs_check_method" != pass_all; then + # We're trying link a shared library against a static one + # but the system doesn't support it. + + # Just print a warning and add the library to dependency_libs so + # that the program can be linked against the static library. + echo + echo "*** Warning: This system can not link to static lib archive $lib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have." + if test "$module" = yes; then + echo "*** But as you try to build a module library, libtool will still create " + echo "*** a static module, that should work as long as the dlopening application" + echo "*** is linked with the -dlopen flag to resolve symbols at runtime." + if test -z "$global_symbol_pipe"; then + echo + echo "*** However, this would only work if libtool was able to extract symbol" + echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + echo "*** not find such a program. So, this module is probably useless." + echo "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + else + convenience="$convenience $dir/$old_library" + old_convenience="$old_convenience $dir/$old_library" + deplibs="$dir/$old_library $deplibs" + link_static=yes + fi + fi # link shared/static library? + + if test $linkmode = lib; then + if test -n "$dependency_libs" && + { test $hardcode_into_libs != yes || test $build_old_libs = yes || + test $link_static = yes; }; then + # Extract -R from dependency_libs + temp_deplibs= + for libdir in $dependency_libs; do + case $libdir in + -R*) temp_xrpath=`$echo "X$libdir" | $Xsed -e 's/^-R//'` + case " $xrpath " in + *" $temp_xrpath "*) ;; + *) xrpath="$xrpath $temp_xrpath";; + esac;; + *) temp_deplibs="$temp_deplibs $libdir";; + esac + done + dependency_libs="$temp_deplibs" + fi + + newlib_search_path="$newlib_search_path $absdir" + # Link against this library + test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" + # ... and its dependency_libs + tmp_libs= + for deplib in $dependency_libs; do + newdependency_libs="$deplib $newdependency_libs" + if test "X$duplicate_deps" = "Xyes" ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done + + if test $link_all_deplibs != no; then + # Add the search paths of all dependency libraries + for deplib in $dependency_libs; do + case $deplib in + -L*) path="$deplib" ;; + *.la) + dir=`$echo "X$deplib" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$deplib" && dir="." + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + $echo "$modename: warning: cannot determine absolute directory name of \`$dir'" 1>&2 + absdir="$dir" + fi + ;; + esac + if grep "^installed=no" $deplib > /dev/null; then + path="-L$absdir/$objdir" + else + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + if test -z "$libdir"; then + $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2 + exit 1 + fi + if test "$absdir" != "$libdir"; then + $echo "$modename: warning: \`$deplib' seems to be moved" 1>&2 + fi + path="-L$absdir" + fi + ;; + *) continue ;; + esac + case " $deplibs " in + *" $path "*) ;; + *) deplibs="$deplibs $path" ;; + esac + done + fi # link_all_deplibs != no + fi # linkmode = lib + done # for deplib in $libs + if test $pass = dlpreopen; then + # Link the dlpreopened libraries before other libraries + for deplib in $save_deplibs; do + deplibs="$deplib $deplibs" + done + fi + if test $pass != dlopen; then + test $pass != scan && dependency_libs="$newdependency_libs" + if test $pass != conv; then + # Make sure lib_search_path contains only unique directories. + lib_search_path= + for dir in $newlib_search_path; do + case "$lib_search_path " in + *" $dir "*) ;; + *) lib_search_path="$lib_search_path $dir" ;; + esac + done + newlib_search_path= + fi + + if test "$linkmode,$pass" != "prog,link"; then + vars="deplibs" + else + vars="compile_deplibs finalize_deplibs" + fi + for var in $vars dependency_libs; do + # Add libraries to $var in reverse order + eval tmp_libs=\"\$$var\" + new_libs= + for deplib in $tmp_libs; do + case $deplib in + -L*) new_libs="$deplib $new_libs" ;; + *) + case " $specialdeplibs " in + *" $deplib "*) new_libs="$deplib $new_libs" ;; + *) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$deplib $new_libs" ;; + esac + ;; + esac + ;; + esac + done + tmp_libs= + for deplib in $new_libs; do + case $deplib in + -L*) + case " $tmp_libs " in + *" $deplib "*) ;; + *) tmp_libs="$tmp_libs $deplib" ;; + esac + ;; + *) tmp_libs="$tmp_libs $deplib" ;; + esac + done + eval $var=\"$tmp_libs\" + done # for var + fi + if test "$pass" = "conv" && + { test "$linkmode" = "lib" || test "$linkmode" = "prog"; }; then + libs="$deplibs" # reset libs + deplibs= + fi + done # for pass + if test $linkmode = prog; then + dlfiles="$newdlfiles" + dlprefiles="$newdlprefiles" + fi + + case $linkmode in + oldlib) + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + $echo "$modename: warning: \`-dlopen' is ignored for archives" 1>&2 + fi + + if test -n "$rpath"; then + $echo "$modename: warning: \`-rpath' is ignored for archives" 1>&2 + fi + + if test -n "$xrpath"; then + $echo "$modename: warning: \`-R' is ignored for archives" 1>&2 + fi + + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info' is ignored for archives" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for archives" 1>&2 + fi + + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + $echo "$modename: warning: \`-export-symbols' is ignored for archives" 1>&2 + fi + + # Now set the variables for building old libraries. + build_libtool_libs=no + oldlibs="$output" + objs="$objs$old_deplibs" + ;; + + lib) + # Make sure we only generate libraries of the form `libNAME.la'. + case $outputname in + lib*) + name=`$echo "X$outputname" | $Xsed -e 's/\.la$//' -e 's/^lib//'` + eval libname=\"$libname_spec\" + ;; + *) + if test "$module" = no; then + $echo "$modename: libtool library \`$output' must begin with \`lib'" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + if test "$need_lib_prefix" != no; then + # Add the "lib" prefix for modules if required + name=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` + eval libname=\"$libname_spec\" + else + libname=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` + fi + ;; + esac + + if test -n "$objs"; then + if test "$deplibs_check_method" != pass_all; then + $echo "$modename: cannot build libtool library \`$output' from non-libtool objects on this host:$objs" 2>&1 + exit 1 + else + echo + echo "*** Warning: Linking the shared library $output against the non-libtool" + echo "*** objects $objs is not portable!" + libobjs="$libobjs $objs" + fi + fi + + if test "$dlself" != no; then + $echo "$modename: warning: \`-dlopen self' is ignored for libtool libraries" 1>&2 + fi + + set dummy $rpath + if test $# -gt 2; then + $echo "$modename: warning: ignoring multiple \`-rpath's for a libtool library" 1>&2 + fi + install_libdir="$2" + + oldlibs= + if test -z "$rpath"; then + if test "$build_libtool_libs" = yes; then + # Building a libtool convenience library. + libext=al + oldlibs="$output_objdir/$libname.$libext $oldlibs" + build_libtool_libs=convenience + build_old_libs=yes + fi + + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info' is ignored for convenience libraries" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for convenience libraries" 1>&2 + fi + else + + # Parse the version information argument. + save_ifs="$IFS"; IFS=':' + set dummy $vinfo 0 0 0 + IFS="$save_ifs" + + if test -n "$8"; then + $echo "$modename: too many parameters to \`-version-info'" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + current="$2" + revision="$3" + age="$4" + + # Check that each of the things are valid numbers. + case $current in + 0 | [1-9] | [1-9][0-9] | [1-9][0-9][0-9]) ;; + *) + $echo "$modename: CURRENT \`$current' is not a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit 1 + ;; + esac + + case $revision in + 0 | [1-9] | [1-9][0-9] | [1-9][0-9][0-9]) ;; + *) + $echo "$modename: REVISION \`$revision' is not a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit 1 + ;; + esac + + case $age in + 0 | [1-9] | [1-9][0-9] | [1-9][0-9][0-9]) ;; + *) + $echo "$modename: AGE \`$age' is not a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit 1 + ;; + esac + + if test $age -gt $current; then + $echo "$modename: AGE \`$age' is greater than the current interface number \`$current'" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit 1 + fi + + # Calculate the version variables. + major= + versuffix= + verstring= + case $version_type in + none) ;; + + darwin) + # Like Linux, but with the current version available in + # verstring for coding it into the library header + major=.`expr $current - $age` + versuffix="$major.$age.$revision" + # Darwin ld doesn't like 0 for these options... + minor_current=`expr $current + 1` + verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" + ;; + + freebsd-aout) + major=".$current" + versuffix=".$current.$revision"; + ;; + + freebsd-elf) + major=".$current" + versuffix=".$current"; + ;; + + irix | nonstopux) + major=`expr $current - $age + 1` + + case $version_type in + nonstopux) verstring_prefix=nonstopux ;; + *) verstring_prefix=sgi ;; + esac + verstring="$verstring_prefix$major.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$revision + while test $loop != 0; do + iface=`expr $revision - $loop` + loop=`expr $loop - 1` + verstring="$verstring_prefix$major.$iface:$verstring" + done + + # Before this point, $major must not contain `.'. + major=.$major + versuffix="$major.$revision" + ;; + + linux) + major=.`expr $current - $age` + versuffix="$major.$age.$revision" + ;; + + osf) + major=.`expr $current - $age` + versuffix=".$current.$age.$revision" + verstring="$current.$age.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$age + while test $loop != 0; do + iface=`expr $current - $loop` + loop=`expr $loop - 1` + verstring="$verstring:${iface}.0" + done + + # Make executables depend on our current version. + verstring="$verstring:${current}.0" + ;; + + sunos) + major=".$current" + versuffix=".$current.$revision" + ;; + + windows) + # Use '-' rather than '.', since we only want one + # extension on DOS 8.3 filesystems. + major=`expr $current - $age` + versuffix="-$major" + ;; + + *) + $echo "$modename: unknown library version type \`$version_type'" 1>&2 + echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit 1 + ;; + esac + + # Clear the version info if we defaulted, and they specified a release. + if test -z "$vinfo" && test -n "$release"; then + major= + verstring="0.0" + case $version_type in + darwin) + # we can't check for "0.0" in archive_cmds due to quoting + # problems, so we reset it completely + verstring="" + ;; + *) + verstring="0.0" + ;; + esac + if test "$need_version" = no; then + versuffix= + else + versuffix=".0.0" + fi + fi + + # Remove version info from name if versioning should be avoided + if test "$avoid_version" = yes && test "$need_version" = no; then + major= + versuffix= + verstring="" + fi + + # Check to see if the archive will have undefined symbols. + if test "$allow_undefined" = yes; then + if test "$allow_undefined_flag" = unsupported; then + $echo "$modename: warning: undefined symbols not allowed in $host shared libraries" 1>&2 + build_libtool_libs=no + build_old_libs=yes + fi + else + # Don't allow undefined symbols. + allow_undefined_flag="$no_undefined_flag" + fi + fi + + if test "$mode" != relink; then + # Remove our outputs. + $show "${rm}r $output_objdir/$outputname $output_objdir/$libname.* $output_objdir/${libname}${release}.*" + $run ${rm}r $output_objdir/$outputname $output_objdir/$libname.* $output_objdir/${libname}${release}.* + fi + + # Now set the variables for building old libraries. + if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then + oldlibs="$oldlibs $output_objdir/$libname.$libext" + + # Transform .lo files to .o files. + oldobjs="$objs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP` + fi + + # Eliminate all temporary directories. + for path in $notinst_path; do + lib_search_path=`echo "$lib_search_path " | ${SED} -e 's% $path % %g'` + deplibs=`echo "$deplibs " | ${SED} -e 's% -L$path % %g'` + dependency_libs=`echo "$dependency_libs " | ${SED} -e 's% -L$path % %g'` + done + + if test -n "$xrpath"; then + # If the user specified any rpath flags, then add them. + temp_xrpath= + for libdir in $xrpath; do + temp_xrpath="$temp_xrpath -R$libdir" + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" ;; + esac + done + if test $hardcode_into_libs != yes || test $build_old_libs = yes; then + dependency_libs="$temp_xrpath $dependency_libs" + fi + fi + + # Make sure dlfiles contains only unique files that won't be dlpreopened + old_dlfiles="$dlfiles" + dlfiles= + for lib in $old_dlfiles; do + case " $dlprefiles $dlfiles " in + *" $lib "*) ;; + *) dlfiles="$dlfiles $lib" ;; + esac + done + + # Make sure dlprefiles contains only unique files + old_dlprefiles="$dlprefiles" + dlprefiles= + for lib in $old_dlprefiles; do + case "$dlprefiles " in + *" $lib "*) ;; + *) dlprefiles="$dlprefiles $lib" ;; + esac + done + + if test "$build_libtool_libs" = yes; then + if test -n "$rpath"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos*) + # these systems don't actually have a c library (as such)! + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C library is in the System framework + deplibs="$deplibs -framework System" + ;; + *-*-netbsd*) + # Don't link with libc until the a.out ld.so is fixed. + ;; + *-*-openbsd* | *-*-freebsd*) + # Do not include libc due to us having libc/libc_r. + ;; + *) + # Add libc to deplibs on all other systems if necessary. + if test $build_libtool_need_lc = "yes"; then + deplibs="$deplibs -lc" + fi + ;; + esac + fi + + # Transform deplibs into only deplibs that can be linked in shared. + name_save=$name + libname_save=$libname + release_save=$release + versuffix_save=$versuffix + major_save=$major + # I'm not sure if I'm treating the release correctly. I think + # release should show up in the -l (ie -lgmp5) so we don't want to + # add it in twice. Is that correct? + release="" + versuffix="" + major="" + newdeplibs= + droppeddeps=no + case $deplibs_check_method in + pass_all) + # Don't check for shared/static. Everything works. + # This might be a little naive. We might want to check + # whether the library exists or not. But this is on + # osf3 & osf4 and I'm not really sure... Just + # implementing what was already the behaviour. + newdeplibs=$deplibs + ;; + test_compile) + # This code stresses the "libraries are programs" paradigm to its + # limits. Maybe even breaks it. We compile a program, linking it + # against the deplibs as a proxy for the library. Then we can check + # whether they linked in statically or dynamically with ldd. + $rm conftest.c + cat > conftest.c </dev/null` + for potent_lib in $potential_libs; do + # Follow soft links. + if ls -lLd "$potent_lib" 2>/dev/null \ + | grep " -> " >/dev/null; then + continue + fi + # The statement above tries to avoid entering an + # endless loop below, in case of cyclic links. + # We might still enter an endless loop, since a link + # loop can be closed while we follow links, + # but so what? + potlib="$potent_lib" + while test -h "$potlib" 2>/dev/null; do + potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` + case $potliblink in + [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; + *) potlib=`$echo "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";; + esac + done + if eval $file_magic_cmd \"\$potlib\" 2>/dev/null \ + | ${SED} 10q \ + | egrep "$file_magic_regex" > /dev/null; then + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + break 2 + fi + done + done + if test -n "$a_deplib" ; then + droppeddeps=yes + echo + echo "*** Warning: linker path does not have real file for library $a_deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have" + echo "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + echo "*** with $libname but no candidates were found. (...for file magic test)" + else + echo "*** with $libname and none of the candidates passed a file format test" + echo "*** using a file magic. Last file checked: $potlib" + fi + fi + else + # Add a -L argument. + newdeplibs="$newdeplibs $a_deplib" + fi + done # Gone through all deplibs. + ;; + match_pattern*) + set dummy $deplibs_check_method + match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"` + for a_deplib in $deplibs; do + name="`expr $a_deplib : '-l\(.*\)'`" + # If $name is empty we are operating on a -L argument. + if test -n "$name" && test "$name" != "0"; then + libname=`eval \\$echo \"$libname_spec\"` + for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do + potential_libs=`ls $i/$libname[.-]* 2>/dev/null` + for potent_lib in $potential_libs; do + potlib="$potent_lib" # see symlink-check below in file_magic test + if eval echo \"$potent_lib\" 2>/dev/null \ + | ${SED} 10q \ + | egrep "$match_pattern_regex" > /dev/null; then + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + break 2 + fi + done + done + if test -n "$a_deplib" ; then + droppeddeps=yes + echo + echo "*** Warning: linker path does not have real file for library $a_deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have" + echo "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + echo "*** with $libname but no candidates were found. (...for regex pattern test)" + else + echo "*** with $libname and none of the candidates passed a file format test" + echo "*** using a regex pattern. Last file checked: $potlib" + fi + fi + else + # Add a -L argument. + newdeplibs="$newdeplibs $a_deplib" + fi + done # Gone through all deplibs. + ;; + none | unknown | *) + newdeplibs="" + if $echo "X $deplibs" | $Xsed -e 's/ -lc$//' \ + -e 's/ -[LR][^ ]*//g' -e 's/[ ]//g' | + grep . >/dev/null; then + echo + if test "X$deplibs_check_method" = "Xnone"; then + echo "*** Warning: inter-library dependencies are not supported in this platform." + else + echo "*** Warning: inter-library dependencies are not known to be supported." + fi + echo "*** All declared inter-library dependencies are being dropped." + droppeddeps=yes + fi + ;; + esac + versuffix=$versuffix_save + major=$major_save + release=$release_save + libname=$libname_save + name=$name_save + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library is the System framework + newdeplibs=`$echo "X $newdeplibs" | $Xsed -e 's/ -lc / -framework System /'` + ;; + esac + + if test "$droppeddeps" = yes; then + if test "$module" = yes; then + echo + echo "*** Warning: libtool could not satisfy all declared inter-library" + echo "*** dependencies of module $libname. Therefore, libtool will create" + echo "*** a static module, that should work as long as the dlopening" + echo "*** application is linked with the -dlopen flag." + if test -z "$global_symbol_pipe"; then + echo + echo "*** However, this would only work if libtool was able to extract symbol" + echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + echo "*** not find such a program. So, this module is probably useless." + echo "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + else + echo "*** The inter-library dependencies that have been dropped here will be" + echo "*** automatically added whenever a program is linked with this library" + echo "*** or is declared to -dlopen it." + + if test $allow_undefined = no; then + echo + echo "*** Since this library must not contain undefined symbols," + echo "*** because either the platform does not support them or" + echo "*** it was explicitly requested with -no-undefined," + echo "*** libtool will only create a static version of it." + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + fi + fi + # Done checking deplibs! + deplibs=$newdeplibs + fi + + # All the library-specific variables (install_libdir is set above). + library_names= + old_library= + dlname= + + # Test again, we may have decided not to build it any more + if test "$build_libtool_libs" = yes; then + if test $hardcode_into_libs = yes; then + # Hardcode the library paths + hardcode_libdirs= + dep_rpath= + rpath="$finalize_rpath" + test "$mode" != relink && rpath="$compile_rpath$rpath" + for libdir in $rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + dep_rpath="$dep_rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval dep_rpath=\"$hardcode_libdir_flag_spec\" + fi + if test -n "$runpath_var" && test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" + fi + test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" + fi + + shlibpath="$finalize_shlibpath" + test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath" + if test -n "$shlibpath"; then + eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" + fi + + # Get the real and link names of the library. + eval library_names=\"$library_names_spec\" + set dummy $library_names + realname="$2" + shift; shift + + if test -n "$soname_spec"; then + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + test -z "$dlname" && dlname=$soname + + lib="$output_objdir/$realname" + for link + do + linknames="$linknames $link" + done + + # Ensure that we have .o objects for linkers which dislike .lo + # (e.g. aix) in case we are running --disable-static + for obj in $libobjs; do + xdir=`$echo "X$obj" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$obj"; then + xdir="." + else + xdir="$xdir" + fi + baseobj=`$echo "X$obj" | $Xsed -e 's%^.*/%%'` + oldobj=`$echo "X$baseobj" | $Xsed -e "$lo2o"` + if test ! -f $xdir/$oldobj; then + $show "(cd $xdir && ${LN_S} $baseobj $oldobj)" + $run eval '(cd $xdir && ${LN_S} $baseobj $oldobj)' || exit $? + fi + done + + # Use standard objects if they are pic + test -z "$pic_flag" && libobjs=`$echo "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then + $show "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $run $rm $export_symbols + eval cmds=\"$export_symbols_cmds\" + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + if test -n "$export_symbols_regex"; then + $show "egrep -e \"$export_symbols_regex\" \"$export_symbols\" > \"${export_symbols}T\"" + $run eval 'egrep -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + $show "$mv \"${export_symbols}T\" \"$export_symbols\"" + $run eval '$mv "${export_symbols}T" "$export_symbols"' + fi + fi + fi + + if test -n "$export_symbols" && test -n "$include_expsyms"; then + $run eval '$echo "X$include_expsyms" | $SP2NL >> "$export_symbols"' + fi + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + else + gentop="$output_objdir/${outputname}x" + $show "${rm}r $gentop" + $run ${rm}r "$gentop" + $show "mkdir $gentop" + $run mkdir "$gentop" + status=$? + if test $status -ne 0 && test ! -d "$gentop"; then + exit $status + fi + generated="$generated $gentop" + + for xlib in $convenience; do + # Extract the objects. + case $xlib in + [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;; + *) xabs=`pwd`"/$xlib" ;; + esac + xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'` + xdir="$gentop/$xlib" + + $show "${rm}r $xdir" + $run ${rm}r "$xdir" + $show "mkdir $xdir" + $run mkdir "$xdir" + status=$? + if test $status -ne 0 && test ! -d "$xdir"; then + exit $status + fi + $show "(cd $xdir && $AR x $xabs)" + $run eval "(cd \$xdir && $AR x \$xabs)" || exit $? + + libobjs="$libobjs "`find $xdir -name \*.o -print -o -name \*.lo -print | $NL2SP` + done + fi + fi + + if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then + eval flag=\"$thread_safe_flag_spec\" + linker_flags="$linker_flags $flag" + fi + + # Make a backup of the uninstalled library when relinking + if test "$mode" = relink; then + $run eval '(cd $output_objdir && $rm ${realname}U && $mv $realname ${realname}U)' || exit $? + fi + + # Do each of the archive commands. + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + eval cmds=\"$archive_expsym_cmds\" + else + save_deplibs="$deplibs" + for conv in $convenience; do + tmp_deplibs= + for test_deplib in $deplibs; do + if test "$test_deplib" != "$conv"; then + tmp_deplibs="$tmp_deplibs $test_deplib" + fi + done + deplibs="$tmp_deplibs" + done + eval cmds=\"$archive_cmds\" + deplibs="$save_deplibs" + fi + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + $run eval '(cd $output_objdir && $rm ${realname}T && $mv $realname ${realname}T && $mv "$realname"U $realname)' || exit $? + exit 0 + fi + + # Create links to the real library. + for linkname in $linknames; do + if test "$realname" != "$linkname"; then + $show "(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)" + $run eval '(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)' || exit $? + fi + done + + # If -module or -export-dynamic was specified, set the dlname. + if test "$module" = yes || test "$export_dynamic" = yes; then + # On all known operating systems, these are identical. + dlname="$soname" + fi + fi + ;; + + obj) + if test -n "$deplibs"; then + $echo "$modename: warning: \`-l' and \`-L' are ignored for objects" 1>&2 + fi + + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + $echo "$modename: warning: \`-dlopen' is ignored for objects" 1>&2 + fi + + if test -n "$rpath"; then + $echo "$modename: warning: \`-rpath' is ignored for objects" 1>&2 + fi + + if test -n "$xrpath"; then + $echo "$modename: warning: \`-R' is ignored for objects" 1>&2 + fi + + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info' is ignored for objects" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for objects" 1>&2 + fi + + case $output in + *.lo) + if test -n "$objs$old_deplibs"; then + $echo "$modename: cannot build library object \`$output' from non-libtool objects" 1>&2 + exit 1 + fi + libobj="$output" + obj=`$echo "X$output" | $Xsed -e "$lo2o"` + ;; + *) + libobj= + obj="$output" + ;; + esac + + # Delete the old objects. + $run $rm $obj $libobj + + # Objects from convenience libraries. This assumes + # single-version convenience libraries. Whenever we create + # different ones for PIC/non-PIC, this we'll have to duplicate + # the extraction. + reload_conv_objs= + gentop= + # reload_cmds runs $LD directly, so let us get rid of + # -Wl from whole_archive_flag_spec + wl= + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + eval reload_conv_objs=\"\$reload_objs $whole_archive_flag_spec\" + else + gentop="$output_objdir/${obj}x" + $show "${rm}r $gentop" + $run ${rm}r "$gentop" + $show "mkdir $gentop" + $run mkdir "$gentop" + status=$? + if test $status -ne 0 && test ! -d "$gentop"; then + exit $status + fi + generated="$generated $gentop" + + for xlib in $convenience; do + # Extract the objects. + case $xlib in + [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;; + *) xabs=`pwd`"/$xlib" ;; + esac + xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'` + xdir="$gentop/$xlib" + + $show "${rm}r $xdir" + $run ${rm}r "$xdir" + $show "mkdir $xdir" + $run mkdir "$xdir" + status=$? + if test $status -ne 0 && test ! -d "$xdir"; then + exit $status + fi + $show "(cd $xdir && $AR x $xabs)" + $run eval "(cd \$xdir && $AR x \$xabs)" || exit $? + + reload_conv_objs="$reload_objs "`find $xdir -name \*.o -print -o -name \*.lo -print | $NL2SP` + done + fi + fi + + # Create the old-style object. + reload_objs="$objs$old_deplibs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test + + output="$obj" + eval cmds=\"$reload_cmds\" + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + + # Exit if we aren't doing a library object file. + if test -z "$libobj"; then + if test -n "$gentop"; then + $show "${rm}r $gentop" + $run ${rm}r $gentop + fi + + exit 0 + fi + + if test "$build_libtool_libs" != yes; then + if test -n "$gentop"; then + $show "${rm}r $gentop" + $run ${rm}r $gentop + fi + + # Create an invalid libtool object if no PIC, so that we don't + # accidentally link it into a program. + $show "echo timestamp > $libobj" + $run eval "echo timestamp > $libobj" || exit $? + exit 0 + fi + + if test -n "$pic_flag" || test "$pic_mode" != default; then + # Only do commands if we really have different PIC objects. + reload_objs="$libobjs $reload_conv_objs" + output="$libobj" + eval cmds=\"$reload_cmds\" + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + else + # Just create a symlink. + $show $rm $libobj + $run $rm $libobj + xdir=`$echo "X$libobj" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$libobj"; then + xdir="." + else + xdir="$xdir" + fi + baseobj=`$echo "X$libobj" | $Xsed -e 's%^.*/%%'` + oldobj=`$echo "X$baseobj" | $Xsed -e "$lo2o"` + $show "(cd $xdir && $LN_S $oldobj $baseobj)" + $run eval '(cd $xdir && $LN_S $oldobj $baseobj)' || exit $? + fi + + if test -n "$gentop"; then + $show "${rm}r $gentop" + $run ${rm}r $gentop + fi + + exit 0 + ;; + + prog) + case $host in + *cygwin*) output=`echo $output | ${SED} -e 's,.exe$,,;s,$,.exe,'` ;; + esac + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info' is ignored for programs" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for programs" 1>&2 + fi + + if test "$preload" = yes; then + if test "$dlopen_support" = unknown && test "$dlopen_self" = unknown && + test "$dlopen_self_static" = unknown; then + $echo "$modename: warning: \`AC_LIBTOOL_DLOPEN' not used. Assuming no dlopen support." + fi + fi + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library is the System framework + compile_deplibs=`$echo "X $compile_deplibs" | $Xsed -e 's/ -lc / -framework System /'` + finalize_deplibs=`$echo "X $finalize_deplibs" | $Xsed -e 's/ -lc / -framework System /'` + case $host in + *darwin*) + # Don't allow lazy linking, it breaks C++ global constructors + compile_command="$compile_command ${wl}-bind_at_load" + finalize_command="$finalize_command ${wl}-bind_at_load" + ;; + esac + ;; + esac + + compile_command="$compile_command $compile_deplibs" + finalize_command="$finalize_command $finalize_deplibs" + + if test -n "$rpath$xrpath"; then + # If the user specified any rpath flags, then add them. + for libdir in $rpath $xrpath; do + # This is the magic to use -rpath. + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" ;; + esac + done + fi + + # Now hardcode the library paths + rpath= + hardcode_libdirs= + for libdir in $compile_rpath $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + rpath="$rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) + case :$dllsearchpath: in + *":$libdir:"*) ;; + *) dllsearchpath="$dllsearchpath:$libdir";; + esac + ;; + esac + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + compile_rpath="$rpath" + + rpath= + hardcode_libdirs= + for libdir in $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + rpath="$rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$finalize_perm_rpath " in + *" $libdir "*) ;; + *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + finalize_rpath="$rpath" + + if test -n "$libobjs" && test "$build_old_libs" = yes; then + # Transform all the library objects into standard objects. + compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + fi + + dlsyms= + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + if test -n "$NM" && test -n "$global_symbol_pipe"; then + dlsyms="${outputname}S.c" + else + $echo "$modename: not configured to extract global symbols from dlpreopened files" 1>&2 + fi + fi + + if test -n "$dlsyms"; then + case $dlsyms in + "") ;; + *.c) + # Discover the nlist of each of the dlfiles. + nlist="$output_objdir/${outputname}.nm" + + $show "$rm $nlist ${nlist}S ${nlist}T" + $run $rm "$nlist" "${nlist}S" "${nlist}T" + + # Parse the name list into a source file. + $show "creating $output_objdir/$dlsyms" + + test -z "$run" && $echo > "$output_objdir/$dlsyms" "\ +/* $dlsyms - symbol resolution table for \`$outputname' dlsym emulation. */ +/* Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP */ + +#ifdef __cplusplus +extern \"C\" { +#endif + +/* Prevent the only kind of declaration conflicts we can make. */ +#define lt_preloaded_symbols some_other_symbol + +/* External symbol declarations for the compiler. */\ +" + + if test "$dlself" = yes; then + $show "generating symbol list for \`$output'" + + test -z "$run" && $echo ': @PROGRAM@ ' > "$nlist" + + # Add our own program objects to the symbol list. + progfiles=`$echo "X$objs$old_deplibs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + for arg in $progfiles; do + $show "extracting global C symbols from \`$arg'" + $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" + done + + if test -n "$exclude_expsyms"; then + $run eval 'egrep -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' + $run eval '$mv "$nlist"T "$nlist"' + fi + + if test -n "$export_symbols_regex"; then + $run eval 'egrep -e "$export_symbols_regex" "$nlist" > "$nlist"T' + $run eval '$mv "$nlist"T "$nlist"' + fi + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + export_symbols="$output_objdir/$output.exp" + $run $rm $export_symbols + $run eval "${SED} -n -e '/^: @PROGRAM@$/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' + else + $run eval "${SED} -e 's/\([][.*^$]\)/\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$output.exp"' + $run eval 'grep -f "$output_objdir/$output.exp" < "$nlist" > "$nlist"T' + $run eval 'mv "$nlist"T "$nlist"' + fi + fi + + for arg in $dlprefiles; do + $show "extracting global C symbols from \`$arg'" + name=`echo "$arg" | ${SED} -e 's%^.*/%%'` + $run eval 'echo ": $name " >> "$nlist"' + $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" + done + + if test -z "$run"; then + # Make sure we have at least an empty file. + test -f "$nlist" || : > "$nlist" + + if test -n "$exclude_expsyms"; then + egrep -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T + $mv "$nlist"T "$nlist" + fi + + # Try sorting and uniquifying the output. + if grep -v "^: " < "$nlist" | + if sort -k 3 /dev/null 2>&1; then + sort -k 3 + else + sort +2 + fi | + uniq > "$nlist"S; then + : + else + grep -v "^: " < "$nlist" > "$nlist"S + fi + + if test -f "$nlist"S; then + eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$dlsyms"' + else + echo '/* NONE */' >> "$output_objdir/$dlsyms" + fi + + $echo >> "$output_objdir/$dlsyms" "\ + +#undef lt_preloaded_symbols + +#if defined (__STDC__) && __STDC__ +# define lt_ptr void * +#else +# define lt_ptr char * +# define const +#endif + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + lt_ptr address; +} +lt_preloaded_symbols[] = +{\ +" + + eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$dlsyms" + + $echo >> "$output_objdir/$dlsyms" "\ + {0, (lt_ptr) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif\ +" + fi + + pic_flag_for_symtable= + case $host in + # compiling the symbol table file with pic_flag works around + # a FreeBSD bug that causes programs to crash when -lm is + # linked before any other PIC object. But we must not use + # pic_flag when linking with -static. The problem exists in + # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. + *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) + case "$compile_command " in + *" -static "*) ;; + *) pic_flag_for_symtable=" $pic_flag -DPIC -DFREEBSD_WORKAROUND";; + esac;; + *-*-hpux*) + case "$compile_command " in + *" -static "*) ;; + *) pic_flag_for_symtable=" $pic_flag -DPIC";; + esac + esac + + # Now compile the dynamic symbol file. + $show "(cd $output_objdir && $CC -c$no_builtin_flag$pic_flag_for_symtable \"$dlsyms\")" + $run eval '(cd $output_objdir && $CC -c$no_builtin_flag$pic_flag_for_symtable "$dlsyms")' || exit $? + + # Clean up the generated files. + $show "$rm $output_objdir/$dlsyms $nlist ${nlist}S ${nlist}T" + $run $rm "$output_objdir/$dlsyms" "$nlist" "${nlist}S" "${nlist}T" + + # Transform the symbol file into the correct name. + compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"` + finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"` + ;; + *) + $echo "$modename: unknown suffix for \`$dlsyms'" 1>&2 + exit 1 + ;; + esac + else + # We keep going just in case the user didn't refer to + # lt_preloaded_symbols. The linker will fail if global_symbol_pipe + # really was required. + + # Nullify the symbol file. + compile_command=`$echo "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"` + finalize_command=`$echo "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"` + fi + + if test $need_relink = no || test "$build_libtool_libs" != yes; then + # Replace the output file specification. + compile_command=`$echo "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` + link_command="$compile_command$compile_rpath" + + # We have no uninstalled library dependencies, so finalize right now. + $show "$link_command" + $run eval "$link_command" + status=$? + + # Delete the generated files. + if test -n "$dlsyms"; then + $show "$rm $output_objdir/${outputname}S.${objext}" + $run $rm "$output_objdir/${outputname}S.${objext}" + fi + + exit $status + fi + + if test -n "$shlibpath_var"; then + # We should set the shlibpath_var + rpath= + for dir in $temp_rpath; do + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) + # Absolute path. + rpath="$rpath$dir:" + ;; + *) + # Relative path: add a thisdir entry. + rpath="$rpath\$thisdir/$dir:" + ;; + esac + done + temp_rpath="$rpath" + fi + + if test -n "$compile_shlibpath$finalize_shlibpath"; then + compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" + fi + if test -n "$finalize_shlibpath"; then + finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" + fi + + compile_var= + finalize_var= + if test -n "$runpath_var"; then + if test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + compile_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + if test -n "$finalize_perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $finalize_perm_rpath; do + rpath="$rpath$dir:" + done + finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + fi + + if test "$no_install" = yes; then + # We don't need to create a wrapper script. + link_command="$compile_var$compile_command$compile_rpath" + # Replace the output file specification. + link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` + # Delete the old output file. + $run $rm $output + # Link the executable and exit + $show "$link_command" + $run eval "$link_command" || exit $? + exit 0 + fi + + if test "$hardcode_action" = relink; then + # Fast installation is not supported + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + + $echo "$modename: warning: this platform does not like uninstalled shared libraries" 1>&2 + $echo "$modename: \`$output' will be relinked during installation" 1>&2 + else + if test "$fast_install" != no; then + link_command="$finalize_var$compile_command$finalize_rpath" + if test "$fast_install" = yes; then + relink_command=`$echo "X$compile_var$compile_command$compile_rpath" | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g'` + else + # fast_install is set to needless + relink_command= + fi + else + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + fi + fi + + # Replace the output file specification. + link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` + + # Delete the old output files. + $run $rm $output $output_objdir/$outputname $output_objdir/lt-$outputname + + $show "$link_command" + $run eval "$link_command" || exit $? + + # Now create the wrapper script. + $show "creating $output" + + # Quote the relink command for shipping. + if test -n "$relink_command"; then + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"` + relink_command="$var=\"$var_value\"; export $var; $relink_command" + fi + done + relink_command="(cd `pwd`; $relink_command)" + relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"` + fi + + # Quote $echo for shipping. + if test "X$echo" = "X$SHELL $0 --fallback-echo"; then + case $0 in + [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $0 --fallback-echo";; + *) qecho="$SHELL `pwd`/$0 --fallback-echo";; + esac + qecho=`$echo "X$qecho" | $Xsed -e "$sed_quote_subst"` + else + qecho=`$echo "X$echo" | $Xsed -e "$sed_quote_subst"` + fi + + # Only actually do things if our run command is non-null. + if test -z "$run"; then + # win32 will think the script is a binary if it has + # a .exe suffix, so we strip it off here. + case $output in + *.exe) output=`echo $output|${SED} 's,.exe$,,'` ;; + esac + # test for cygwin because mv fails w/o .exe extensions + case $host in + *cygwin*) exeext=.exe ;; + *) exeext= ;; + esac + $rm $output + trap "$rm $output; exit 1" 1 2 15 + + $echo > $output "\ +#! $SHELL + +# $output - temporary wrapper script for $objdir/$outputname +# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP +# +# The $output program cannot be directly executed until all the libtool +# libraries that it depends on are installed. +# +# This wrapper script should never be moved out of the build directory. +# If it is, it will not operate correctly. + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed="${SED}"' -e 1s/^X//' +sed_quote_subst='$sed_quote_subst' + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +if test \"\${CDPATH+set}\" = set; then CDPATH=:; export CDPATH; fi + +relink_command=\"$relink_command\" + +# This environment variable determines our operation mode. +if test \"\$libtool_install_magic\" = \"$magic\"; then + # install mode needs the following variable: + notinst_deplibs='$notinst_deplibs' +else + # When we are sourced in execute mode, \$file and \$echo are already set. + if test \"\$libtool_execute_magic\" != \"$magic\"; then + echo=\"$qecho\" + file=\"\$0\" + # Make sure echo works. + if test \"X\$1\" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift + elif test \"X\`(\$echo '\t') 2>/dev/null\`\" = 'X\t'; then + # Yippee, \$echo works! + : + else + # Restart under the correct shell, and then maybe \$echo will work. + exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"} + fi + fi\ +" + $echo >> $output "\ + + # Find the directory that this script lives in. + thisdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\` + test \"x\$thisdir\" = \"x\$file\" && thisdir=. + + # Follow symbolic links until we get to the real thisdir. + file=\`ls -ld \"\$file\" | ${SED} -n 's/.*-> //p'\` + while test -n \"\$file\"; do + destdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\` + + # If there was a directory component, then change thisdir. + if test \"x\$destdir\" != \"x\$file\"; then + case \"\$destdir\" in + [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; + *) thisdir=\"\$thisdir/\$destdir\" ;; + esac + fi + + file=\`\$echo \"X\$file\" | \$Xsed -e 's%^.*/%%'\` + file=\`ls -ld \"\$thisdir/\$file\" | ${SED} -n 's/.*-> //p'\` + done + + # Try to get the absolute directory name. + absdir=\`cd \"\$thisdir\" && pwd\` + test -n \"\$absdir\" && thisdir=\"\$absdir\" +" + + if test "$fast_install" = yes; then + echo >> $output "\ + program=lt-'$outputname'$exeext + progdir=\"\$thisdir/$objdir\" + + if test ! -f \"\$progdir/\$program\" || \\ + { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ + test \"X\$file\" != \"X\$progdir/\$program\"; }; then + + file=\"\$\$-\$program\" + + if test ! -d \"\$progdir\"; then + $mkdir \"\$progdir\" + else + $rm \"\$progdir/\$file\" + fi" + + echo >> $output "\ + + # relink executable if necessary + if test -n \"\$relink_command\"; then + if relink_command_output=\`eval \$relink_command 2>&1\`; then : + else + $echo \"\$relink_command_output\" >&2 + $rm \"\$progdir/\$file\" + exit 1 + fi + fi + + $mv \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || + { $rm \"\$progdir/\$program\"; + $mv \"\$progdir/\$file\" \"\$progdir/\$program\"; } + $rm \"\$progdir/\$file\" + fi" + else + echo >> $output "\ + program='$outputname' + progdir=\"\$thisdir/$objdir\" +" + fi + + echo >> $output "\ + + if test -f \"\$progdir/\$program\"; then" + + # Export our shlibpath_var if we have one. + if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then + $echo >> $output "\ + # Add our own library path to $shlibpath_var + $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" + + # Some systems cannot cope with colon-terminated $shlibpath_var + # The second colon is a workaround for a bug in BeOS R4 ${SED} + $shlibpath_var=\`\$echo \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\` + + export $shlibpath_var +" + fi + + # fixup the dll searchpath if we need to. + if test -n "$dllsearchpath"; then + $echo >> $output "\ + # Add the dll search path components to the executable PATH + PATH=$dllsearchpath:\$PATH +" + fi + + $echo >> $output "\ + if test \"\$libtool_execute_magic\" != \"$magic\"; then + # Run the actual program with our arguments. +" + case $host in + # win32 systems need to use the prog path for dll + # lookup to work + *-*-cygwin* | *-*-pw32*) + $echo >> $output "\ + exec \$progdir/\$program \${1+\"\$@\"} +" + ;; + + # Backslashes separate directories on plain windows + *-*-mingw | *-*-os2*) + $echo >> $output "\ + exec \$progdir\\\\\$program \${1+\"\$@\"} +" + ;; + + *) + $echo >> $output "\ + # Export the path to the program. + PATH=\"\$progdir:\$PATH\" + export PATH + + exec \$program \${1+\"\$@\"} +" + ;; + esac + $echo >> $output "\ + \$echo \"\$0: cannot exec \$program \${1+\"\$@\"}\" + exit 1 + fi + else + # The program doesn't exist. + \$echo \"\$0: error: \$progdir/\$program does not exist\" 1>&2 + \$echo \"This script is just a wrapper for \$program.\" 1>&2 + echo \"See the $PACKAGE documentation for more information.\" 1>&2 + exit 1 + fi +fi\ +" + chmod +x $output + fi + exit 0 + ;; + esac + + # See if we need to build an old-fashioned archive. + for oldlib in $oldlibs; do + + if test "$build_libtool_libs" = convenience; then + oldobjs="$libobjs_save" + addlibs="$convenience" + build_libtool_libs=no + else + if test "$build_libtool_libs" = module; then + oldobjs="$libobjs_save" + build_libtool_libs=no + else + oldobjs="$objs$old_deplibs "`$echo "X$libobjs_save" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP` + fi + addlibs="$old_convenience" + fi + + if test -n "$addlibs"; then + gentop="$output_objdir/${outputname}x" + $show "${rm}r $gentop" + $run ${rm}r "$gentop" + $show "mkdir $gentop" + $run mkdir "$gentop" + status=$? + if test $status -ne 0 && test ! -d "$gentop"; then + exit $status + fi + generated="$generated $gentop" + + # Add in members from convenience archives. + for xlib in $addlibs; do + # Extract the objects. + case $xlib in + [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;; + *) xabs=`pwd`"/$xlib" ;; + esac + xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'` + xdir="$gentop/$xlib" + + $show "${rm}r $xdir" + $run ${rm}r "$xdir" + $show "mkdir $xdir" + $run mkdir "$xdir" + status=$? + if test $status -ne 0 && test ! -d "$xdir"; then + exit $status + fi + $show "(cd $xdir && $AR x $xabs)" + $run eval "(cd \$xdir && $AR x \$xabs)" || exit $? + + oldobjs="$oldobjs "`find $xdir -name \*.${objext} -print -o -name \*.lo -print | $NL2SP` + done + fi + + # Do each command in the archive commands. + if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then + eval cmds=\"$old_archive_from_new_cmds\" + else + # Ensure that we have .o objects in place in case we decided + # not to build a shared library, and have fallen back to building + # static libs even though --disable-static was passed! + for oldobj in $oldobjs; do + if test ! -f $oldobj; then + xdir=`$echo "X$oldobj" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$oldobj"; then + xdir="." + else + xdir="$xdir" + fi + baseobj=`$echo "X$oldobj" | $Xsed -e 's%^.*/%%'` + obj=`$echo "X$baseobj" | $Xsed -e "$o2lo"` + $show "(cd $xdir && ${LN_S} $obj $baseobj)" + $run eval '(cd $xdir && ${LN_S} $obj $baseobj)' || exit $? + fi + done + + eval cmds=\"$old_archive_cmds\" + fi + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + done + + if test -n "$generated"; then + $show "${rm}r$generated" + $run ${rm}r$generated + fi + + # Now create the libtool archive. + case $output in + *.la) + old_library= + test "$build_old_libs" = yes && old_library="$libname.$libext" + $show "creating $output" + + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"` + relink_command="$var=\"$var_value\"; export $var; $relink_command" + fi + done + # Quote the link command for shipping. + relink_command="(cd `pwd`; $SHELL $0 --mode=relink $libtool_args)" + relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"` + + # Only create the output if not a dry run. + if test -z "$run"; then + for installed in no yes; do + if test "$installed" = yes; then + if test -z "$install_libdir"; then + break + fi + output="$output_objdir/$outputname"i + # Replace all uninstalled libtool libraries with the installed ones + newdependency_libs= + for deplib in $dependency_libs; do + case $deplib in + *.la) + name=`$echo "X$deplib" | $Xsed -e 's%^.*/%%'` + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + if test -z "$libdir"; then + $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2 + exit 1 + fi + newdependency_libs="$newdependency_libs $libdir/$name" + ;; + *) newdependency_libs="$newdependency_libs $deplib" ;; + esac + done + dependency_libs="$newdependency_libs" + newdlfiles= + for lib in $dlfiles; do + name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + if test -z "$libdir"; then + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + exit 1 + fi + newdlfiles="$newdlfiles $libdir/$name" + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + if test -z "$libdir"; then + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + exit 1 + fi + newdlprefiles="$newdlprefiles $libdir/$name" + done + dlprefiles="$newdlprefiles" + fi + $rm $output + # place dlname in correct position for cygwin + tdlname=$dlname + case $host,$output,$installed,$module,$dlname in + *cygwin*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;; + esac + $echo > $output "\ +# $outputname - a libtool library file +# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='$tdlname' + +# Names of this library. +library_names='$library_names' + +# The name of the static archive. +old_library='$old_library' + +# Libraries that this one depends upon. +dependency_libs='$dependency_libs' + +# Version information for $libname. +current=$current +age=$age +revision=$revision + +# Is this an already installed library? +installed=$installed + +# Files to dlopen/dlpreopen +dlopen='$dlfiles' +dlpreopen='$dlprefiles' + +# Directory that this library needs to be installed in: +libdir='$install_libdir'" + if test "$installed" = no && test $need_relink = yes; then + $echo >> $output "\ +relink_command=\"$relink_command\"" + fi + done + fi + + # Do a symbolic link so that the libtool archive can be found in + # LD_LIBRARY_PATH before the program is installed. + $show "(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)" + $run eval '(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)' || exit $? + ;; + esac + exit 0 + ;; + + # libtool install mode + install) + modename="$modename: install" + + # There may be an optional sh(1) argument at the beginning of + # install_prog (especially on Windows NT). + if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || + # Allow the use of GNU shtool's install command. + $echo "X$nonopt" | $Xsed | grep shtool > /dev/null; then + # Aesthetically quote it. + arg=`$echo "X$nonopt" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + install_prog="$arg " + arg="$1" + shift + else + install_prog= + arg="$nonopt" + fi + + # The real first argument should be the name of the installation program. + # Aesthetically quote it. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + install_prog="$install_prog$arg" + + # We need to accept at least all the BSD install flags. + dest= + files= + opts= + prev= + install_type= + isdir=no + stripme= + for arg + do + if test -n "$dest"; then + files="$files $dest" + dest="$arg" + continue + fi + + case $arg in + -d) isdir=yes ;; + -f) prev="-f" ;; + -g) prev="-g" ;; + -m) prev="-m" ;; + -o) prev="-o" ;; + -s) + stripme=" -s" + continue + ;; + -*) ;; + + *) + # If the previous option needed an argument, then skip it. + if test -n "$prev"; then + prev= + else + dest="$arg" + continue + fi + ;; + esac + + # Aesthetically quote the argument. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + install_prog="$install_prog $arg" + done + + if test -z "$install_prog"; then + $echo "$modename: you must specify an install program" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + if test -n "$prev"; then + $echo "$modename: the \`$prev' option requires an argument" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + if test -z "$files"; then + if test -z "$dest"; then + $echo "$modename: no file or destination specified" 1>&2 + else + $echo "$modename: you must specify a destination" 1>&2 + fi + $echo "$help" 1>&2 + exit 1 + fi + + # Strip any trailing slash from the destination. + dest=`$echo "X$dest" | $Xsed -e 's%/$%%'` + + # Check to see that the destination is a directory. + test -d "$dest" && isdir=yes + if test "$isdir" = yes; then + destdir="$dest" + destname= + else + destdir=`$echo "X$dest" | $Xsed -e 's%/[^/]*$%%'` + test "X$destdir" = "X$dest" && destdir=. + destname=`$echo "X$dest" | $Xsed -e 's%^.*/%%'` + + # Not a directory, so check to see that there is only one file specified. + set dummy $files + if test $# -gt 2; then + $echo "$modename: \`$dest' is not a directory" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + fi + case $destdir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + for file in $files; do + case $file in + *.lo) ;; + *) + $echo "$modename: \`$destdir' must be an absolute directory name" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; + esac + done + ;; + esac + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + staticlibs= + future_libdirs= + current_libdirs= + for file in $files; do + + # Do each installation. + case $file in + *.$libext) + # Do the static libraries later. + staticlibs="$staticlibs $file" + ;; + + *.la) + # Check to see that this really is a libtool archive. + if (${SED} -e '2q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : + else + $echo "$modename: \`$file' is not a valid libtool archive" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + library_names= + old_library= + relink_command= + # If there is no directory component, then add one. + case $file in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Add the libdir to current_libdirs if it is the destination. + if test "X$destdir" = "X$libdir"; then + case "$current_libdirs " in + *" $libdir "*) ;; + *) current_libdirs="$current_libdirs $libdir" ;; + esac + else + # Note the libdir as a future libdir. + case "$future_libdirs " in + *" $libdir "*) ;; + *) future_libdirs="$future_libdirs $libdir" ;; + esac + fi + + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`/ + test "X$dir" = "X$file/" && dir= + dir="$dir$objdir" + + if test -n "$relink_command"; then + $echo "$modename: warning: relinking \`$file'" 1>&2 + $show "$relink_command" + if $run eval "$relink_command"; then : + else + $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2 + continue + fi + fi + + # See the names of the shared library. + set dummy $library_names + if test -n "$2"; then + realname="$2" + shift + shift + + srcname="$realname" + test -n "$relink_command" && srcname="$realname"T + + # Install the shared library and build the symlinks. + $show "$install_prog $dir/$srcname $destdir/$realname" + $run eval "$install_prog $dir/$srcname $destdir/$realname" || exit $? + if test -n "$stripme" && test -n "$striplib"; then + $show "$striplib $destdir/$realname" + $run eval "$striplib $destdir/$realname" || exit $? + fi + + if test $# -gt 0; then + # Delete the old symlinks, and create new ones. + for linkname + do + if test "$linkname" != "$realname"; then + $show "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)" + $run eval "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)" + fi + done + fi + + # Do each command in the postinstall commands. + lib="$destdir/$realname" + eval cmds=\"$postinstall_cmds\" + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + + # Install the pseudo-library for information purposes. + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + instname="$dir/$name"i + $show "$install_prog $instname $destdir/$name" + $run eval "$install_prog $instname $destdir/$name" || exit $? + + # Maybe install the static library, too. + test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library" + ;; + + *.lo) + # Install (i.e. copy) a libtool object. + + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + destfile="$destdir/$destfile" + fi + + # Deduce the name of the destination old-style object file. + case $destfile in + *.lo) + staticdest=`$echo "X$destfile" | $Xsed -e "$lo2o"` + ;; + *.$objext) + staticdest="$destfile" + destfile= + ;; + *) + $echo "$modename: cannot copy a libtool object to \`$destfile'" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; + esac + + # Install the libtool object if requested. + if test -n "$destfile"; then + $show "$install_prog $file $destfile" + $run eval "$install_prog $file $destfile" || exit $? + fi + + # Install the old object if enabled. + if test "$build_old_libs" = yes; then + # Deduce the name of the old-style object file. + staticobj=`$echo "X$file" | $Xsed -e "$lo2o"` + + $show "$install_prog $staticobj $staticdest" + $run eval "$install_prog \$staticobj \$staticdest" || exit $? + fi + exit 0 + ;; + + *) + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + destfile="$destdir/$destfile" + fi + + # Do a test to see if this is really a libtool program. + case $host in + *cygwin*|*mingw*) + wrapper=`echo $file | ${SED} -e 's,.exe$,,'` + ;; + *) + wrapper=$file + ;; + esac + if (${SED} -e '4q' $wrapper | egrep "^# Generated by .*$PACKAGE")>/dev/null 2>&1; then + notinst_deplibs= + relink_command= + + # If there is no directory component, then add one. + case $file in + */* | *\\*) . $wrapper ;; + *) . ./$wrapper ;; + esac + + # Check the variables that should have been set. + if test -z "$notinst_deplibs"; then + $echo "$modename: invalid libtool wrapper script \`$wrapper'" 1>&2 + exit 1 + fi + + finalize=yes + for lib in $notinst_deplibs; do + # Check to see that each library is installed. + libdir= + if test -f "$lib"; then + # If there is no directory component, then add one. + case $lib in + */* | *\\*) . $lib ;; + *) . ./$lib ;; + esac + fi + libfile="$libdir/"`$echo "X$lib" | $Xsed -e 's%^.*/%%g'` ### testsuite: skip nested quoting test + if test -n "$libdir" && test ! -f "$libfile"; then + $echo "$modename: warning: \`$lib' has not been installed in \`$libdir'" 1>&2 + finalize=no + fi + done + + relink_command= + # If there is no directory component, then add one. + case $file in + */* | *\\*) . $wrapper ;; + *) . ./$wrapper ;; + esac + + outputname= + if test "$fast_install" = no && test -n "$relink_command"; then + if test "$finalize" = yes && test -z "$run"; then + tmpdir="/tmp" + test -n "$TMPDIR" && tmpdir="$TMPDIR" + tmpdir="$tmpdir/libtool-$$" + if $mkdir -p "$tmpdir" && chmod 700 "$tmpdir"; then : + else + $echo "$modename: error: cannot create temporary directory \`$tmpdir'" 1>&2 + continue + fi + file=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + outputname="$tmpdir/$file" + # Replace the output file specification. + relink_command=`$echo "X$relink_command" | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g'` + + $show "$relink_command" + if $run eval "$relink_command"; then : + else + $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2 + ${rm}r "$tmpdir" + continue + fi + file="$outputname" + else + $echo "$modename: warning: cannot relink \`$file'" 1>&2 + fi + else + # Install the binary that we compiled earlier. + file=`$echo "X$file" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"` + fi + fi + + # remove .exe since cygwin /usr/bin/install will append another + # one anyways + case $install_prog,$host in + /usr/bin/install*,*cygwin*) + case $file:$destfile in + *.exe:*.exe) + # this is ok + ;; + *.exe:*) + destfile=$destfile.exe + ;; + *:*.exe) + destfile=`echo $destfile | ${SED} -e 's,.exe$,,'` + ;; + esac + ;; + esac + $show "$install_prog$stripme $file $destfile" + $run eval "$install_prog\$stripme \$file \$destfile" || exit $? + test -n "$outputname" && ${rm}r "$tmpdir" + ;; + esac + done + + for file in $staticlibs; do + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + + # Set up the ranlib parameters. + oldlib="$destdir/$name" + + $show "$install_prog $file $oldlib" + $run eval "$install_prog \$file \$oldlib" || exit $? + + if test -n "$stripme" && test -n "$striplib"; then + $show "$old_striplib $oldlib" + $run eval "$old_striplib $oldlib" || exit $? + fi + + # Do each command in the postinstall commands. + eval cmds=\"$old_postinstall_cmds\" + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + done + + if test -n "$future_libdirs"; then + $echo "$modename: warning: remember to run \`$progname --finish$future_libdirs'" 1>&2 + fi + + if test -n "$current_libdirs"; then + # Maybe just do a dry run. + test -n "$run" && current_libdirs=" -n$current_libdirs" + exec_cmd='$SHELL $0 --finish$current_libdirs' + else + exit 0 + fi + ;; + + # libtool finish mode + finish) + modename="$modename: finish" + libdirs="$nonopt" + admincmds= + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + for dir + do + libdirs="$libdirs $dir" + done + + for libdir in $libdirs; do + if test -n "$finish_cmds"; then + # Do each command in the finish commands. + eval cmds=\"$finish_cmds\" + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || admincmds="$admincmds + $cmd" + done + IFS="$save_ifs" + fi + if test -n "$finish_eval"; then + # Do the single finish_eval. + eval cmds=\"$finish_eval\" + $run eval "$cmds" || admincmds="$admincmds + $cmds" + fi + done + fi + + # Exit here if they wanted silent mode. + test "$show" = ":" && exit 0 + + echo "----------------------------------------------------------------------" + echo "Libraries have been installed in:" + for libdir in $libdirs; do + echo " $libdir" + done + echo + echo "If you ever happen to want to link against installed libraries" + echo "in a given directory, LIBDIR, you must either use libtool, and" + echo "specify the full pathname of the library, or use the \`-LLIBDIR'" + echo "flag during linking and do at least one of the following:" + if test -n "$shlibpath_var"; then + echo " - add LIBDIR to the \`$shlibpath_var' environment variable" + echo " during execution" + fi + if test -n "$runpath_var"; then + echo " - add LIBDIR to the \`$runpath_var' environment variable" + echo " during linking" + fi + if test -n "$hardcode_libdir_flag_spec"; then + libdir=LIBDIR + eval flag=\"$hardcode_libdir_flag_spec\" + + echo " - use the \`$flag' linker flag" + fi + if test -n "$admincmds"; then + echo " - have your system administrator run these commands:$admincmds" + fi + if test -f /etc/ld.so.conf; then + echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" + fi + echo + echo "See any operating system documentation about shared libraries for" + echo "more information, such as the ld(1) and ld.so(8) manual pages." + echo "----------------------------------------------------------------------" + exit 0 + ;; + + # libtool execute mode + execute) + modename="$modename: execute" + + # The first argument is the command name. + cmd="$nonopt" + if test -z "$cmd"; then + $echo "$modename: you must specify a COMMAND" 1>&2 + $echo "$help" + exit 1 + fi + + # Handle -dlopen flags immediately. + for file in $execute_dlfiles; do + if test ! -f "$file"; then + $echo "$modename: \`$file' is not a file" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + dir= + case $file in + *.la) + # Check to see that this really is a libtool archive. + if (${SED} -e '2q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : + else + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + # Read the libtool library. + dlname= + library_names= + + # If there is no directory component, then add one. + case $file in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Skip this library if it cannot be dlopened. + if test -z "$dlname"; then + # Warn if it was a shared library. + test -n "$library_names" && $echo "$modename: warning: \`$file' was not linked with \`-export-dynamic'" + continue + fi + + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$file" && dir=. + + if test -f "$dir/$objdir/$dlname"; then + dir="$dir/$objdir" + else + $echo "$modename: cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" 1>&2 + exit 1 + fi + ;; + + *.lo) + # Just add the directory containing the .lo file. + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$file" && dir=. + ;; + + *) + $echo "$modename: warning \`-dlopen' is ignored for non-libtool libraries and objects" 1>&2 + continue + ;; + esac + + # Get the absolute pathname. + absdir=`cd "$dir" && pwd` + test -n "$absdir" && dir="$absdir" + + # Now add the directory to shlibpath_var. + if eval "test -z \"\$$shlibpath_var\""; then + eval "$shlibpath_var=\"\$dir\"" + else + eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" + fi + done + + # This variable tells wrapper scripts just to set shlibpath_var + # rather than running their programs. + libtool_execute_magic="$magic" + + # Check if any of the arguments is a wrapper script. + args= + for file + do + case $file in + -*) ;; + *) + # Do a test to see if this is really a libtool program. + if (${SED} -e '4q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + # If there is no directory component, then add one. + case $file in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Transform arg to wrapped name. + file="$progdir/$program" + fi + ;; + esac + # Quote arguments (to preserve shell metacharacters). + file=`$echo "X$file" | $Xsed -e "$sed_quote_subst"` + args="$args \"$file\"" + done + + if test -z "$run"; then + if test -n "$shlibpath_var"; then + # Export the shlibpath_var. + eval "export $shlibpath_var" + fi + + # Restore saved enviroment variables + if test "${save_LC_ALL+set}" = set; then + LC_ALL="$save_LC_ALL"; export LC_ALL + fi + if test "${save_LANG+set}" = set; then + LANG="$save_LANG"; export LANG + fi + + # Now prepare to actually exec the command. + exec_cmd="\$cmd$args" + else + # Display what would be done. + if test -n "$shlibpath_var"; then + eval "\$echo \"\$shlibpath_var=\$$shlibpath_var\"" + $echo "export $shlibpath_var" + fi + $echo "$cmd$args" + exit 0 + fi + ;; + + # libtool clean and uninstall mode + clean | uninstall) + modename="$modename: $mode" + rm="$nonopt" + files= + rmforce= + exit_status=0 + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + for arg + do + case $arg in + -f) rm="$rm $arg"; rmforce=yes ;; + -*) rm="$rm $arg" ;; + *) files="$files $arg" ;; + esac + done + + if test -z "$rm"; then + $echo "$modename: you must specify an RM program" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + rmdirs= + + for file in $files; do + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + if test "X$dir" = "X$file"; then + dir=. + objdir="$objdir" + else + objdir="$dir/$objdir" + fi + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + test $mode = uninstall && objdir="$dir" + + # Remember objdir for removal later, being careful to avoid duplicates + if test $mode = clean; then + case " $rmdirs " in + *" $objdir "*) ;; + *) rmdirs="$rmdirs $objdir" ;; + esac + fi + + # Don't error if the file doesn't exist and rm -f was used. + if (test -L "$file") >/dev/null 2>&1 \ + || (test -h "$file") >/dev/null 2>&1 \ + || test -f "$file"; then + : + elif test -d "$file"; then + exit_status=1 + continue + elif test "$rmforce" = yes; then + continue + fi + + rmfiles="$file" + + case $name in + *.la) + # Possibly a libtool archive, so verify it. + if (${SED} -e '2q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + . $dir/$name + + # Delete the libtool libraries and symlinks. + for n in $library_names; do + rmfiles="$rmfiles $objdir/$n" + done + test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library" + test $mode = clean && rmfiles="$rmfiles $objdir/$name $objdir/${name}i" + + if test $mode = uninstall; then + if test -n "$library_names"; then + # Do each command in the postuninstall commands. + eval cmds=\"$postuninstall_cmds\" + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" + if test $? != 0 && test "$rmforce" != yes; then + exit_status=1 + fi + done + IFS="$save_ifs" + fi + + if test -n "$old_library"; then + # Do each command in the old_postuninstall commands. + eval cmds=\"$old_postuninstall_cmds\" + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" + if test $? != 0 && test "$rmforce" != yes; then + exit_status=1 + fi + done + IFS="$save_ifs" + fi + # FIXME: should reinstall the best remaining shared library. + fi + fi + ;; + + *.lo) + if test "$build_old_libs" = yes; then + oldobj=`$echo "X$name" | $Xsed -e "$lo2o"` + rmfiles="$rmfiles $dir/$oldobj" + fi + ;; + + *) + # Do a test to see if this is a libtool program. + if test $mode = clean && + (${SED} -e '4q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + relink_command= + . $dir/$file + + rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}" + if test "$fast_install" = yes && test -n "$relink_command"; then + rmfiles="$rmfiles $objdir/lt-$name" + fi + fi + ;; + esac + $show "$rm $rmfiles" + $run $rm $rmfiles || exit_status=1 + done + + # Try to remove the ${objdir}s in the directories where we deleted files + for dir in $rmdirs; do + if test -d "$dir"; then + $show "rmdir $dir" + $run rmdir $dir >/dev/null 2>&1 + fi + done + + exit $exit_status + ;; + + "") + $echo "$modename: you must specify a MODE" 1>&2 + $echo "$generic_help" 1>&2 + exit 1 + ;; + esac + + if test -z "$exec_cmd"; then + $echo "$modename: invalid operation mode \`$mode'" 1>&2 + $echo "$generic_help" 1>&2 + exit 1 + fi +fi # test -z "$show_help" + +if test -n "$exec_cmd"; then + eval exec $exec_cmd + exit 1 +fi + +# We need to display help for each of the modes. +case $mode in +"") $echo \ +"Usage: $modename [OPTION]... [MODE-ARG]... + +Provide generalized library-building support services. + + --config show all configuration variables + --debug enable verbose shell tracing +-n, --dry-run display commands without modifying any files + --features display basic configuration information and exit + --finish same as \`--mode=finish' + --help display this help message and exit + --mode=MODE use operation mode MODE [default=inferred from MODE-ARGS] + --quiet same as \`--silent' + --silent don't print informational messages + --version print version information + +MODE must be one of the following: + + clean remove files from the build directory + compile compile a source file into a libtool object + execute automatically set library path, then run a program + finish complete the installation of libtool libraries + install install libraries or executables + link create a library or an executable + uninstall remove libraries from an installed directory + +MODE-ARGS vary depending on the MODE. Try \`$modename --help --mode=MODE' for +a more detailed description of MODE." + exit 0 + ;; + +clean) + $echo \ +"Usage: $modename [OPTION]... --mode=clean RM [RM-OPTION]... FILE... + +Remove files from the build directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, object or program, all the files associated +with it are deleted. Otherwise, only FILE itself is deleted using RM." + ;; + +compile) + $echo \ +"Usage: $modename [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE + +Compile a source file into a libtool library object. + +This mode accepts the following additional options: + + -o OUTPUT-FILE set the output file name to OUTPUT-FILE + -prefer-pic try to building PIC objects only + -prefer-non-pic try to building non-PIC objects only + -static always build a \`.o' file suitable for static linking + +COMPILE-COMMAND is a command to be used in creating a \`standard' object file +from the given SOURCEFILE. + +The output file name is determined by removing the directory component from +SOURCEFILE, then substituting the C source code suffix \`.c' with the +library object suffix, \`.lo'." + ;; + +execute) + $echo \ +"Usage: $modename [OPTION]... --mode=execute COMMAND [ARGS]... + +Automatically set library path, then run a program. + +This mode accepts the following additional options: + + -dlopen FILE add the directory containing FILE to the library path + +This mode sets the library path environment variable according to \`-dlopen' +flags. + +If any of the ARGS are libtool executable wrappers, then they are translated +into their corresponding uninstalled binary, and any of their required library +directories are added to the library path. + +Then, COMMAND is executed, with ARGS as arguments." + ;; + +finish) + $echo \ +"Usage: $modename [OPTION]... --mode=finish [LIBDIR]... + +Complete the installation of libtool libraries. + +Each LIBDIR is a directory that contains libtool libraries. + +The commands that this mode executes may require superuser privileges. Use +the \`--dry-run' option if you just want to see what would be executed." + ;; + +install) + $echo \ +"Usage: $modename [OPTION]... --mode=install INSTALL-COMMAND... + +Install executables or libraries. + +INSTALL-COMMAND is the installation command. The first component should be +either the \`install' or \`cp' program. + +The rest of the components are interpreted as arguments to that command (only +BSD-compatible install options are recognized)." + ;; + +link) + $echo \ +"Usage: $modename [OPTION]... --mode=link LINK-COMMAND... + +Link object files or libraries together to form another library, or to +create an executable program. + +LINK-COMMAND is a command using the C compiler that you would use to create +a program from several object files. + +The following components of LINK-COMMAND are treated specially: + + -all-static do not do any dynamic linking at all + -avoid-version do not add a version suffix if possible + -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime + -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols + -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) + -export-symbols SYMFILE + try to export only the symbols listed in SYMFILE + -export-symbols-regex REGEX + try to export only the symbols matching REGEX + -LLIBDIR search LIBDIR for required installed libraries + -lNAME OUTPUT-FILE requires the installed library libNAME + -module build a library that can dlopened + -no-fast-install disable the fast-install mode + -no-install link a not-installable executable + -no-undefined declare that a library does not refer to external symbols + -o OUTPUT-FILE create OUTPUT-FILE from the specified objects + -release RELEASE specify package release information + -rpath LIBDIR the created library will eventually be installed in LIBDIR + -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries + -static do not do any dynamic linking of libtool libraries + -version-info CURRENT[:REVISION[:AGE]] + specify library version info [each variable defaults to 0] + +All other options (arguments beginning with \`-') are ignored. + +Every other argument is treated as a filename. Files ending in \`.la' are +treated as uninstalled libtool libraries, other files are standard or library +object files. + +If the OUTPUT-FILE ends in \`.la', then a libtool library is created, +only library objects (\`.lo' files) may be specified, and \`-rpath' is +required, except when creating a convenience library. + +If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created +using \`ar' and \`ranlib', or on Windows using \`lib'. + +If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file +is created, otherwise an executable program is created." + ;; + +uninstall) + $echo \ +"Usage: $modename [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... + +Remove libraries from an installation directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, all the files associated with it are deleted. +Otherwise, only FILE itself is deleted using RM." + ;; + +*) + $echo "$modename: invalid operation mode \`$mode'" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; +esac + +echo +$echo "Try \`$modename --help' for more information about other modes." + +exit 0 + +# Local Variables: +# mode:shell-script +# sh-indentation:2 +# End: diff --git a/mk4/continuity/pcre/maketables.c b/mk4/continuity/pcre/maketables.c new file mode 100644 index 0000000..257fe89 --- /dev/null +++ b/mk4/continuity/pcre/maketables.c @@ -0,0 +1,136 @@ +/************************************************* +* Perl-Compatible Regular Expressions * +*************************************************/ + +/* +PCRE is a library of functions to support regular expressions whose syntax +and semantics are as close as possible to those of the Perl 5 language. + +Written by: Philip Hazel + + Copyright (c) 1997-2003 University of Cambridge + +----------------------------------------------------------------------------- +Permission is granted to anyone to use this software for any purpose on any +computer system, and to redistribute it freely, subject to the following +restrictions: + +1. This software 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. + +2. The origin of this software must not be misrepresented, either by + explicit claim or by omission. + +3. Altered versions must be plainly marked as such, and must not be + misrepresented as being the original software. + +4. If PCRE is embedded in any software that is released under the GNU + General Purpose Licence (GPL), then the terms of that licence shall + supersede any condition above with which it is incompatible. +----------------------------------------------------------------------------- + +See the file Tech.Notes for some information on the internals. +*/ + + +/* This file is compiled on its own as part of the PCRE library. However, +it is also included in the compilation of dftables.c, in which case the macro +DFTABLES is defined. */ + +#ifndef DFTABLES +#include "internal.h" +#endif + + + +/************************************************* +* Create PCRE character tables * +*************************************************/ + +/* This function builds a set of character tables for use by PCRE and returns +a pointer to them. They are build using the ctype functions, and consequently +their contents will depend upon the current locale setting. When compiled as +part of the library, the store is obtained via pcre_malloc(), but when compiled +inside dftables, use malloc(). + +Arguments: none +Returns: pointer to the contiguous block of data +*/ + +const unsigned char * +pcre_maketables(void) +{ +unsigned char *yield, *p; +int i; + +#ifndef DFTABLES +yield = (unsigned char*)(pcre_malloc)(tables_length); +#else +yield = (unsigned char*)malloc(tables_length); +#endif + +if (yield == NULL) return NULL; +p = yield; + +/* First comes the lower casing table */ + +for (i = 0; i < 256; i++) *p++ = tolower(i); + +/* Next the case-flipping table */ + +for (i = 0; i < 256; i++) *p++ = islower(i)? toupper(i) : tolower(i); + +/* Then the character class tables. Don't try to be clever and save effort +on exclusive ones - in some locales things may be different. Note that the +table for "space" includes everything "isspace" gives, including VT in the +default locale. This makes it work for the POSIX class [:space:]. */ + +memset(p, 0, cbit_length); +for (i = 0; i < 256; i++) + { + if (isdigit(i)) + { + p[cbit_digit + i/8] |= 1 << (i&7); + p[cbit_word + i/8] |= 1 << (i&7); + } + if (isupper(i)) + { + p[cbit_upper + i/8] |= 1 << (i&7); + p[cbit_word + i/8] |= 1 << (i&7); + } + if (islower(i)) + { + p[cbit_lower + i/8] |= 1 << (i&7); + p[cbit_word + i/8] |= 1 << (i&7); + } + if (i == '_') p[cbit_word + i/8] |= 1 << (i&7); + if (isspace(i)) p[cbit_space + i/8] |= 1 << (i&7); + if (isxdigit(i))p[cbit_xdigit + i/8] |= 1 << (i&7); + if (isgraph(i)) p[cbit_graph + i/8] |= 1 << (i&7); + if (isprint(i)) p[cbit_print + i/8] |= 1 << (i&7); + if (ispunct(i)) p[cbit_punct + i/8] |= 1 << (i&7); + if (iscntrl(i)) p[cbit_cntrl + i/8] |= 1 << (i&7); + } +p += cbit_length; + +/* Finally, the character type table. In this, we exclude VT from the white +space chars, because Perl doesn't recognize it as such for \s and for comments +within regexes. */ + +for (i = 0; i < 256; i++) + { + int x = 0; + if (i != 0x0b && isspace(i)) x += ctype_space; + if (isalpha(i)) x += ctype_letter; + if (isdigit(i)) x += ctype_digit; + if (isxdigit(i)) x += ctype_xdigit; + if (isalnum(i) || i == '_') x += ctype_word; + if (strchr("*+?{^.$|()[", i) != 0) x += ctype_meta; + *p++ = x; + } + +return yield; +} + +/* End of maketables.c */ diff --git a/mk4/continuity/pcre/makevp.bat b/mk4/continuity/pcre/makevp.bat new file mode 100644 index 0000000..10bd248 --- /dev/null +++ b/mk4/continuity/pcre/makevp.bat @@ -0,0 +1,25 @@ +@echo off + +REM This file was contributed by Alexander Tokarev for building PCRE for use +REM with Virtual Pascal. It has not been tested with the latest PCRE release. + +REM CHANGE THIS FOR YOUR BORLAND C++ COMPILER PATH + +SET BORLAND=c:\usr\apps\bcc55 + +sh configure + +bcc32 -DDFTABLES -DSTATIC -DVPCOMPAT -I%BORLAND%\include -L%BORLAND%\lib dftables.c + +dftables > chartables.c + +bcc32 -c -RT- -y- -v- -u- -P- -O2 -5 -DSTATIC -DVPCOMPAT -UDFTABLES -I%BORLAND%\include get.c maketables.c pcre.c study.c + +tlib %BORLAND%\lib\cw32.lib *calloc *del *strncmp *memcpy *memmove *memset +tlib pcre.lib +get.obj +maketables.obj +pcre.obj +study.obj +calloc.obj +del.obj +strncmp.obj +memcpy.obj +memmove.obj +memset.obj + +del *.obj *.exe *.tds *.bak >nul 2>nul + +echo --- +echo Now the library should be complete. Please check all messages above. +echo Don't care for warnings, it's OK. diff --git a/mk4/continuity/pcre/mkinstalldirs b/mk4/continuity/pcre/mkinstalldirs new file mode 100644 index 0000000..82a287b --- /dev/null +++ b/mk4/continuity/pcre/mkinstalldirs @@ -0,0 +1,40 @@ +#! /bin/sh +# mkinstalldirs --- make directory hierarchy +# Author: Noah Friedman +# Created: 1993-05-16 +# Public domain + +# $Id: mkinstalldirs,v 1.1 2003/11/07 14:48:15 aleigh Exp $ + +errstatus=0 + +for file +do + set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` + shift + + pathcomp= + for d + do + pathcomp="$pathcomp$d" + case "$pathcomp" in + -* ) pathcomp=./$pathcomp ;; + esac + + if test ! -d "$pathcomp"; then + echo "mkdir $pathcomp" + + mkdir "$pathcomp" || lasterr=$? + + if test ! -d "$pathcomp"; then + errstatus=$lasterr + fi + fi + + pathcomp="$pathcomp/" + done +done + +exit $errstatus + +# mkinstalldirs ends here diff --git a/mk4/continuity/pcre/pcre-config.in b/mk4/continuity/pcre/pcre-config.in new file mode 100644 index 0000000..8daded9 --- /dev/null +++ b/mk4/continuity/pcre/pcre-config.in @@ -0,0 +1,59 @@ +#!/bin/sh + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +exec_prefix_set=no + +usage="\ +Usage: pcre-config [--prefix] [--exec-prefix] [--version] [--libs] [--libs-posix] [--cflags] [--cflags-posix]" + +if test $# -eq 0; then + echo "${usage}" 1>&2 + exit 1 +fi + +while test $# -gt 0; do + case "$1" in + -*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) optarg= ;; + esac + + case $1 in + --prefix=*) + prefix=$optarg + if test $exec_prefix_set = no ; then + exec_prefix=$optarg + fi + ;; + --prefix) + echo $prefix + ;; + --exec-prefix=*) + exec_prefix=$optarg + exec_prefix_set=yes + ;; + --exec-prefix) + echo $exec_prefix + ;; + --version) + echo @PCRE_VERSION@ + ;; + --cflags | --cflags-posix) + if test @includedir@ != /usr/include ; then + includes=-I@includedir@ + fi + echo $includes + ;; + --libs-posix) + echo -L@libdir@ -lpcreposix -lpcre + ;; + --libs) + echo -L@libdir@ -lpcre + ;; + *) + echo "${usage}" 1>&2 + exit 1 + ;; + esac + shift +done diff --git a/mk4/continuity/pcre/pcre.c b/mk4/continuity/pcre/pcre.c new file mode 100644 index 0000000..5da0f76 --- /dev/null +++ b/mk4/continuity/pcre/pcre.c @@ -0,0 +1,7596 @@ +/************************************************* +* Perl-Compatible Regular Expressions * +*************************************************/ + +/* +This is a library of functions to support regular expressions whose syntax +and semantics are as close as possible to those of the Perl 5 language. See +the file Tech.Notes for some information on the internals. + +Written by: Philip Hazel + + Copyright (c) 1997-2003 University of Cambridge + +----------------------------------------------------------------------------- +Permission is granted to anyone to use this software for any purpose on any +computer system, and to redistribute it freely, subject to the following +restrictions: + +1. This software 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. + +2. The origin of this software must not be misrepresented, either by + explicit claim or by omission. + +3. Altered versions must be plainly marked as such, and must not be + misrepresented as being the original software. + +4. If PCRE is embedded in any software that is released under the GNU + General Purpose Licence (GPL), then the terms of that licence shall + supersede any condition above with which it is incompatible. +----------------------------------------------------------------------------- +*/ + +/* Define DEBUG to get debugging output on stdout. */ + +/* #define DEBUG */ + +/* Use a macro for debugging printing, 'cause that eliminates the use of #ifdef +inline, and there are *still* stupid compilers about that don't like indented +pre-processor statements. I suppose it's only been 10 years... */ + +#ifdef DEBUG +#define DPRINTF(p) printf p +#else +#define DPRINTF(p) /*nothing*/ +#endif + +/* Include the internals header, which itself includes Standard C headers plus +the external pcre header. */ + +#include "internal.h" + + +/* Allow compilation as C++ source code, should anybody want to do that. */ + +#ifdef __cplusplus +#define class pcre_class +#endif + + +/* Maximum number of items on the nested bracket stacks at compile time. This +applies to the nesting of all kinds of parentheses. It does not limit +un-nested, non-capturing parentheses. This number can be made bigger if +necessary - it is used to dimension one int and one unsigned char vector at +compile time. */ + +#define BRASTACK_SIZE 200 + + +/* Maximum number of ints of offset to save on the stack for recursive calls. +If the offset vector is bigger, malloc is used. This should be a multiple of 3, +because the offset vector is always a multiple of 3 long. */ + +#define REC_STACK_SAVE_MAX 30 + + +/* The number of bytes in a literal character string above which we can't add +any more is set at 250 in order to allow for UTF-8 characters. (In theory it +could be 255 when UTF-8 support is excluded, but that means that some of the +test output would be different, which just complicates things.) */ + +#define MAXLIT 250 + + +/* The maximum remaining length of subject we are prepared to search for a +req_byte match. */ + +#define REQ_BYTE_MAX 1000 + + +/* Table of sizes for the fixed-length opcodes. It's defined in a macro so that +the definition is next to the definition of the opcodes in internal.h. */ + +static uschar OP_lengths[] = { OP_LENGTHS }; + +/* Min and max values for the common repeats; for the maxima, 0 => infinity */ + +static const char rep_min[] = { 0, 0, 1, 1, 0, 0 }; +static const char rep_max[] = { 0, 0, 0, 0, 1, 1 }; + +/* Table for handling escaped characters in the range '0'-'z'. Positive returns +are simple data values; negative values are for special things like \d and so +on. Zero means further processing is needed (for things like \x), or the escape +is invalid. */ + +static const short int escapes[] = { + 0, 0, 0, 0, 0, 0, 0, 0, /* 0 - 7 */ + 0, 0, ':', ';', '<', '=', '>', '?', /* 8 - ? */ + '@', -ESC_A, -ESC_B, -ESC_C, -ESC_D, -ESC_E, 0, -ESC_G, /* @ - G */ + 0, 0, 0, 0, 0, 0, 0, 0, /* H - O */ + 0, -ESC_Q, 0, -ESC_S, 0, 0, 0, -ESC_W, /* P - W */ + 0, 0, -ESC_Z, '[', '\\', ']', '^', '_', /* X - _ */ + '`', 7, -ESC_b, 0, -ESC_d, ESC_e, ESC_f, 0, /* ` - g */ + 0, 0, 0, 0, 0, 0, ESC_n, 0, /* h - o */ + 0, 0, ESC_r, -ESC_s, ESC_tee, 0, 0, -ESC_w, /* p - w */ + 0, 0, -ESC_z /* x - z */ +}; + +/* Tables of names of POSIX character classes and their lengths. The list is +terminated by a zero length entry. The first three must be alpha, upper, lower, +as this is assumed for handling case independence. */ + +static const char *posix_names[] = { + "alpha", "lower", "upper", + "alnum", "ascii", "blank", "cntrl", "digit", "graph", + "print", "punct", "space", "word", "xdigit" }; + +static const uschar posix_name_lengths[] = { + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 6, 0 }; + +/* Table of class bit maps for each POSIX class; up to three may be combined +to form the class. The table for [:blank:] is dynamically modified to remove +the vertical space characters. */ + +static const int posix_class_maps[] = { + cbit_lower, cbit_upper, -1, /* alpha */ + cbit_lower, -1, -1, /* lower */ + cbit_upper, -1, -1, /* upper */ + cbit_digit, cbit_lower, cbit_upper, /* alnum */ + cbit_print, cbit_cntrl, -1, /* ascii */ + cbit_space, -1, -1, /* blank - a GNU extension */ + cbit_cntrl, -1, -1, /* cntrl */ + cbit_digit, -1, -1, /* digit */ + cbit_graph, -1, -1, /* graph */ + cbit_print, -1, -1, /* print */ + cbit_punct, -1, -1, /* punct */ + cbit_space, -1, -1, /* space */ + cbit_word, -1, -1, /* word - a Perl extension */ + cbit_xdigit,-1, -1 /* xdigit */ +}; + +/* Table to identify ASCII digits and hex digits. This is used when compiling +patterns. Note that the tables in chartables are dependent on the locale, and +may mark arbitrary characters as digits - but the PCRE compiling code expects +to handle only 0-9, a-z, and A-Z as digits when compiling. That is why we have +a private table here. It costs 256 bytes, but it is a lot faster than doing +character value tests (at least in some simple cases I timed), and in some +applications one wants PCRE to compile efficiently as well as match +efficiently. + +For convenience, we use the same bit definitions as in chartables: + + 0x04 decimal digit + 0x08 hexadecimal digit + +Then we can use ctype_digit and ctype_xdigit in the code. */ + +static const unsigned char digitab[] = + { + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0- 7 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 8- 15 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 16- 23 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 24- 31 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* - ' */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* ( - / */ + 0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c, /* 0 - 7 */ + 0x0c,0x0c,0x00,0x00,0x00,0x00,0x00,0x00, /* 8 - ? */ + 0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x00, /* @ - G */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* H - O */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* P - W */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* X - _ */ + 0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x00, /* ` - g */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* h - o */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* p - w */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* x -127 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 128-135 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 136-143 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 144-151 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 152-159 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 160-167 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 168-175 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 176-183 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 184-191 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 192-199 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 200-207 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 208-215 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 216-223 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 224-231 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 232-239 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 240-247 */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};/* 248-255 */ + +/* Definition to allow mutual recursion */ + +static BOOL + compile_regex(int, int, int *, uschar **, const uschar **, const char **, + BOOL, int, int *, int *, branch_chain *, compile_data *); + +/* Structure for building a chain of data that actually lives on the +stack, for holding the values of the subject pointer at the start of each +subpattern, so as to detect when an empty string has been matched by a +subpattern - to break infinite loops. */ + +typedef struct eptrblock { + struct eptrblock *prev; + const uschar *saved_eptr; +} eptrblock; + +/* Flag bits for the match() function */ + +#define match_condassert 0x01 /* Called to check a condition assertion */ +#define match_isgroup 0x02 /* Set if start of bracketed group */ + +/* Non-error returns from the match() function. Error returns are externally +defined PCRE_ERROR_xxx codes, which are all negative. */ + +#define MATCH_MATCH 1 +#define MATCH_NOMATCH 0 + + + +/************************************************* +* Global variables * +*************************************************/ + +/* PCRE is thread-clean and doesn't use any global variables in the normal +sense. However, it calls memory allocation and free functions via the two +indirections below, and it can optionally do callouts. These values can be +changed by the caller, but are shared between all threads. However, when +compiling for Virtual Pascal, things are done differently (see pcre.in). */ + +#ifndef VPCOMPAT +void *(*pcre_malloc)(size_t) = malloc; +void (*pcre_free)(void *) = free; +int (*pcre_callout)(pcre_callout_block *) = NULL; +#endif + + +/************************************************* +* Macros and tables for character handling * +*************************************************/ + +/* When UTF-8 encoding is being used, a character is no longer just a single +byte. The macros for character handling generate simple sequences when used in +byte-mode, and more complicated ones for UTF-8 characters. */ + +#ifndef SUPPORT_UTF8 +#define GETCHAR(c, eptr) c = *eptr; +#define GETCHARINC(c, eptr) c = *eptr++; +#define GETCHARINCTEST(c, eptr) c = *eptr++; +#define GETCHARLEN(c, eptr, len) c = *eptr; +#define BACKCHAR(eptr) + +#else /* SUPPORT_UTF8 */ + +/* Get the next UTF-8 character, not advancing the pointer. This is called when +we know we are in UTF-8 mode. */ + +#define GETCHAR(c, eptr) \ + c = *eptr; \ + if ((c & 0xc0) == 0xc0) \ + { \ + int gcii; \ + int gcaa = utf8_table4[c & 0x3f]; /* Number of additional bytes */ \ + int gcss = 6*gcaa; \ + c = (c & utf8_table3[gcaa]) << gcss; \ + for (gcii = 1; gcii <= gcaa; gcii++) \ + { \ + gcss -= 6; \ + c |= (eptr[gcii] & 0x3f) << gcss; \ + } \ + } + +/* Get the next UTF-8 character, advancing the pointer. This is called when we +know we are in UTF-8 mode. */ + +#define GETCHARINC(c, eptr) \ + c = *eptr++; \ + if ((c & 0xc0) == 0xc0) \ + { \ + int gcaa = utf8_table4[c & 0x3f]; /* Number of additional bytes */ \ + int gcss = 6*gcaa; \ + c = (c & utf8_table3[gcaa]) << gcss; \ + while (gcaa-- > 0) \ + { \ + gcss -= 6; \ + c |= (*eptr++ & 0x3f) << gcss; \ + } \ + } + +/* Get the next character, testing for UTF-8 mode, and advancing the pointer */ + +#define GETCHARINCTEST(c, eptr) \ + c = *eptr++; \ + if (md->utf8 && (c & 0xc0) == 0xc0) \ + { \ + int gcaa = utf8_table4[c & 0x3f]; /* Number of additional bytes */ \ + int gcss = 6*gcaa; \ + c = (c & utf8_table3[gcaa]) << gcss; \ + while (gcaa-- > 0) \ + { \ + gcss -= 6; \ + c |= (*eptr++ & 0x3f) << gcss; \ + } \ + } + +/* Get the next UTF-8 character, not advancing the pointer, incrementing length +if there are extra bytes. This is called when we know we are in UTF-8 mode. */ + +#define GETCHARLEN(c, eptr, len) \ + c = *eptr; \ + if ((c & 0xc0) == 0xc0) \ + { \ + int gcii; \ + int gcaa = utf8_table4[c & 0x3f]; /* Number of additional bytes */ \ + int gcss = 6*gcaa; \ + c = (c & utf8_table3[gcaa]) << gcss; \ + for (gcii = 1; gcii <= gcaa; gcii++) \ + { \ + gcss -= 6; \ + c |= (eptr[gcii] & 0x3f) << gcss; \ + } \ + len += gcaa; \ + } + +/* If the pointer is not at the start of a character, move it back until +it is. Called only in UTF-8 mode. */ + +#define BACKCHAR(eptr) while((*eptr & 0xc0) == 0x80) eptr--; + +#endif + + + +/************************************************* +* Default character tables * +*************************************************/ + +/* A default set of character tables is included in the PCRE binary. Its source +is built by the maketables auxiliary program, which uses the default C ctypes +functions, and put in the file chartables.c. These tables are used by PCRE +whenever the caller of pcre_compile() does not provide an alternate set of +tables. */ + +#include "chartables.c" + + + +#ifdef SUPPORT_UTF8 +/************************************************* +* Tables for UTF-8 support * +*************************************************/ + +/* These are the breakpoints for different numbers of bytes in a UTF-8 +character. */ + +static const int utf8_table1[] = + { 0x7f, 0x7ff, 0xffff, 0x1fffff, 0x3ffffff, 0x7fffffff}; + +/* These are the indicator bits and the mask for the data bits to set in the +first byte of a character, indexed by the number of additional bytes. */ + +static const int utf8_table2[] = { 0, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc}; +static const int utf8_table3[] = { 0xff, 0x1f, 0x0f, 0x07, 0x03, 0x01}; + +/* Table of the number of extra characters, indexed by the first character +masked with 0x3f. The highest number for a valid UTF-8 character is in fact +0x3d. */ + +static const uschar utf8_table4[] = { + 1,1,1,1,1,1,1,1,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,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 }; + + +/************************************************* +* Convert character value to UTF-8 * +*************************************************/ + +/* This function takes an integer value in the range 0 - 0x7fffffff +and encodes it as a UTF-8 character in 0 to 6 bytes. + +Arguments: + cvalue the character value + buffer pointer to buffer for result - at least 6 bytes long + +Returns: number of characters placed in the buffer +*/ + +static int +ord2utf8(int cvalue, uschar *buffer) +{ +register int i, j; +for (i = 0; i < sizeof(utf8_table1)/sizeof(int); i++) + if (cvalue <= utf8_table1[i]) break; +buffer += i; +for (j = i; j > 0; j--) + { + *buffer-- = 0x80 | (cvalue & 0x3f); + cvalue >>= 6; + } +*buffer = utf8_table2[i] | cvalue; +return i + 1; +} +#endif + + + +/************************************************* +* Print compiled regex * +*************************************************/ + +/* The code for doing this is held in a separate file that is also included in +pcretest.c. It defines a function called print_internals(). */ + +#ifdef DEBUG +#include "printint.c" +#endif + + + +/************************************************* +* Return version string * +*************************************************/ + +#define STRING(a) # a +#define XSTRING(s) STRING(s) + +const char * +pcre_version(void) +{ +return XSTRING(PCRE_MAJOR) "." XSTRING(PCRE_MINOR) " " XSTRING(PCRE_DATE); +} + + + + +/************************************************* +* (Obsolete) Return info about compiled pattern * +*************************************************/ + +/* This is the original "info" function. It picks potentially useful data out +of the private structure, but its interface was too rigid. It remains for +backwards compatibility. The public options are passed back in an int - though +the re->options field has been expanded to a long int, all the public options +at the low end of it, and so even on 16-bit systems this will still be OK. +Therefore, I haven't changed the API for pcre_info(). + +Arguments: + external_re points to compiled code + optptr where to pass back the options + first_byte where to pass back the first character, + or -1 if multiline and all branches start ^, + or -2 otherwise + +Returns: number of capturing subpatterns + or negative values on error +*/ + +int +pcre_info(const pcre *external_re, int *optptr, int *first_byte) +{ +const real_pcre *re = (const real_pcre *)external_re; +if (re == NULL) return PCRE_ERROR_NULL; +if (re->magic_number != MAGIC_NUMBER) return PCRE_ERROR_BADMAGIC; +if (optptr != NULL) *optptr = (int)(re->options & PUBLIC_OPTIONS); +if (first_byte != NULL) + *first_byte = ((re->options & PCRE_FIRSTSET) != 0)? re->first_byte : + ((re->options & PCRE_STARTLINE) != 0)? -1 : -2; +return re->top_bracket; +} + + + +/************************************************* +* Return info about compiled pattern * +*************************************************/ + +/* This is a newer "info" function which has an extensible interface so +that additional items can be added compatibly. + +Arguments: + external_re points to compiled code + extra_data points extra data, or NULL + what what information is required + where where to put the information + +Returns: 0 if data returned, negative on error +*/ + +int +pcre_fullinfo(const pcre *external_re, const pcre_extra *extra_data, int what, + void *where) +{ +const real_pcre *re = (const real_pcre *)external_re; +const pcre_study_data *study = NULL; + +if (re == NULL || where == NULL) return PCRE_ERROR_NULL; +if (re->magic_number != MAGIC_NUMBER) return PCRE_ERROR_BADMAGIC; + +if (extra_data != NULL && (extra_data->flags & PCRE_EXTRA_STUDY_DATA) != 0) + study = extra_data->study_data; + +switch (what) + { + case PCRE_INFO_OPTIONS: + *((unsigned long int *)where) = re->options & PUBLIC_OPTIONS; + break; + + case PCRE_INFO_SIZE: + *((size_t *)where) = re->size; + break; + + case PCRE_INFO_STUDYSIZE: + *((size_t *)where) = (study == NULL)? 0 : study->size; + break; + + case PCRE_INFO_CAPTURECOUNT: + *((int *)where) = re->top_bracket; + break; + + case PCRE_INFO_BACKREFMAX: + *((int *)where) = re->top_backref; + break; + + case PCRE_INFO_FIRSTBYTE: + *((int *)where) = + ((re->options & PCRE_FIRSTSET) != 0)? re->first_byte : + ((re->options & PCRE_STARTLINE) != 0)? -1 : -2; + break; + + case PCRE_INFO_FIRSTTABLE: + *((const uschar **)where) = + (study != NULL && (study->options & PCRE_STUDY_MAPPED) != 0)? + study->start_bits : NULL; + break; + + case PCRE_INFO_LASTLITERAL: + *((int *)where) = + ((re->options & PCRE_REQCHSET) != 0)? re->req_byte : -1; + break; + + case PCRE_INFO_NAMEENTRYSIZE: + *((int *)where) = re->name_entry_size; + break; + + case PCRE_INFO_NAMECOUNT: + *((int *)where) = re->name_count; + break; + + case PCRE_INFO_NAMETABLE: + *((const uschar **)where) = (const uschar *)re + sizeof(real_pcre); + break; + + default: return PCRE_ERROR_BADOPTION; + } + +return 0; +} + + + +/************************************************* +* Return info about what features are configured * +*************************************************/ + +/* This is function which has an extensible interface so that additional items +can be added compatibly. + +Arguments: + what what information is required + where where to put the information + +Returns: 0 if data returned, negative on error +*/ + +int +pcre_config(int what, void *where) +{ +switch (what) + { + case PCRE_CONFIG_UTF8: + #ifdef SUPPORT_UTF8 + *((int *)where) = 1; + #else + *((int *)where) = 0; + #endif + break; + + case PCRE_CONFIG_NEWLINE: + *((int *)where) = NEWLINE; + break; + + case PCRE_CONFIG_LINK_SIZE: + *((int *)where) = LINK_SIZE; + break; + + case PCRE_CONFIG_POSIX_MALLOC_THRESHOLD: + *((int *)where) = POSIX_MALLOC_THRESHOLD; + break; + + case PCRE_CONFIG_MATCH_LIMIT: + *((unsigned int *)where) = MATCH_LIMIT; + break; + + default: return PCRE_ERROR_BADOPTION; + } + +return 0; +} + + + +#ifdef DEBUG +/************************************************* +* Debugging function to print chars * +*************************************************/ + +/* Print a sequence of chars in printable format, stopping at the end of the +subject if the requested. + +Arguments: + p points to characters + length number to print + is_subject TRUE if printing from within md->start_subject + md pointer to matching data block, if is_subject is TRUE + +Returns: nothing +*/ + +static void +pchars(const uschar *p, int length, BOOL is_subject, match_data *md) +{ +int c; +if (is_subject && length > md->end_subject - p) length = md->end_subject - p; +while (length-- > 0) + if (isprint(c = *(p++))) printf("%c", c); else printf("\\x%02x", c); +} +#endif + + + + +/************************************************* +* Handle escapes * +*************************************************/ + +/* This function is called when a \ has been encountered. It either returns a +positive value for a simple escape such as \n, or a negative value which +encodes one of the more complicated things such as \d. When UTF-8 is enabled, +a positive value greater than 255 may be returned. On entry, ptr is pointing at +the \. On exit, it is on the final character of the escape sequence. + +Arguments: + ptrptr points to the pattern position pointer + errorptr points to the pointer to the error message + bracount number of previous extracting brackets + options the options bits + isclass TRUE if inside a character class + cd pointer to char tables block + +Returns: zero or positive => a data character + negative => a special escape sequence + on error, errorptr is set +*/ + +static int +check_escape(const uschar **ptrptr, const char **errorptr, int bracount, + int options, BOOL isclass, compile_data *cd) +{ +const uschar *ptr = *ptrptr; +int c, i; + +/* If backslash is at the end of the pattern, it's an error. */ + +c = *(++ptr); +if (c == 0) *errorptr = ERR1; + +/* Digits or letters may have special meaning; all others are literals. */ + +else if (c < '0' || c > 'z') {} + +/* Do an initial lookup in a table. A non-zero result is something that can be +returned immediately. Otherwise further processing may be required. */ + +else if ((i = escapes[c - '0']) != 0) c = i; + +/* Escapes that need further processing, or are illegal. */ + +else + { + const uschar *oldptr; + switch (c) + { + /* A number of Perl escapes are not handled by PCRE. We give an explicit + error. */ + + case 'l': + case 'L': + case 'N': + case 'p': + case 'P': + case 'u': + case 'U': + case 'X': + *errorptr = ERR37; + break; + + /* The handling of escape sequences consisting of a string of digits + starting with one that is not zero is not straightforward. By experiment, + the way Perl works seems to be as follows: + + Outside a character class, the digits are read as a decimal number. If the + number is less than 10, or if there are that many previous extracting + left brackets, then it is a back reference. Otherwise, up to three octal + digits are read to form an escaped byte. Thus \123 is likely to be octal + 123 (cf \0123, which is octal 012 followed by the literal 3). If the octal + value is greater than 377, the least significant 8 bits are taken. Inside a + character class, \ followed by a digit is always an octal number. */ + + case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '8': case '9': + + if (!isclass) + { + oldptr = ptr; + c -= '0'; + while ((digitab[ptr[1]] & ctype_digit) != 0) + c = c * 10 + *(++ptr) - '0'; + if (c < 10 || c <= bracount) + { + c = -(ESC_REF + c); + break; + } + ptr = oldptr; /* Put the pointer back and fall through */ + } + + /* Handle an octal number following \. If the first digit is 8 or 9, Perl + generates a binary zero byte and treats the digit as a following literal. + Thus we have to pull back the pointer by one. */ + + if ((c = *ptr) >= '8') + { + ptr--; + c = 0; + break; + } + + /* \0 always starts an octal number, but we may drop through to here with a + larger first octal digit. */ + + case '0': + c -= '0'; + while(i++ < 2 && ptr[1] >= '0' && ptr[1] <= '7') + c = c * 8 + *(++ptr) - '0'; + c &= 255; /* Take least significant 8 bits */ + break; + + /* \x is complicated when UTF-8 is enabled. \x{ddd} is a character number + which can be greater than 0xff, but only if the ddd are hex digits. */ + + case 'x': +#ifdef SUPPORT_UTF8 + if (ptr[1] == '{' && (options & PCRE_UTF8) != 0) + { + const uschar *pt = ptr + 2; + register int count = 0; + c = 0; + while ((digitab[*pt] & ctype_xdigit) != 0) + { + int cc = *pt++; + if (cc >= 'a') cc -= 32; /* Convert to upper case */ + count++; + c = c * 16 + cc - ((cc < 'A')? '0' : ('A' - 10)); + } + if (*pt == '}') + { + if (c < 0 || count > 8) *errorptr = ERR34; + ptr = pt; + break; + } + /* If the sequence of hex digits does not end with '}', then we don't + recognize this construct; fall through to the normal \x handling. */ + } +#endif + + /* Read just a single hex char */ + + c = 0; + while (i++ < 2 && (digitab[ptr[1]] & ctype_xdigit) != 0) + { + int cc = *(++ptr); + if (cc >= 'a') cc -= 32; /* Convert to upper case */ + c = c * 16 + cc - ((cc < 'A')? '0' : ('A' - 10)); + } + break; + + /* Other special escapes not starting with a digit are straightforward */ + + case 'c': + c = *(++ptr); + if (c == 0) + { + *errorptr = ERR2; + return 0; + } + + /* A letter is upper-cased; then the 0x40 bit is flipped. This coding + is ASCII-specific, but then the whole concept of \cx is ASCII-specific. */ + + if (c >= 'a' && c <= 'z') c -= 32; + c ^= 0x40; + break; + + /* PCRE_EXTRA enables extensions to Perl in the matter of escapes. Any + other alphameric following \ is an error if PCRE_EXTRA was set; otherwise, + for Perl compatibility, it is a literal. This code looks a bit odd, but + there used to be some cases other than the default, and there may be again + in future, so I haven't "optimized" it. */ + + default: + if ((options & PCRE_EXTRA) != 0) switch(c) + { + default: + *errorptr = ERR3; + break; + } + break; + } + } + +*ptrptr = ptr; +return c; +} + + + +/************************************************* +* Check for counted repeat * +*************************************************/ + +/* This function is called when a '{' is encountered in a place where it might +start a quantifier. It looks ahead to see if it really is a quantifier or not. +It is only a quantifier if it is one of the forms {ddd} {ddd,} or {ddd,ddd} +where the ddds are digits. + +Arguments: + p pointer to the first char after '{' + cd pointer to char tables block + +Returns: TRUE or FALSE +*/ + +static BOOL +is_counted_repeat(const uschar *p, compile_data *cd) +{ +if ((digitab[*p++] && ctype_digit) == 0) return FALSE; +while ((digitab[*p] & ctype_digit) != 0) p++; +if (*p == '}') return TRUE; + +if (*p++ != ',') return FALSE; +if (*p == '}') return TRUE; + +if ((digitab[*p++] && ctype_digit) == 0) return FALSE; +while ((digitab[*p] & ctype_digit) != 0) p++; + +return (*p == '}'); +} + + + +/************************************************* +* Read repeat counts * +*************************************************/ + +/* Read an item of the form {n,m} and return the values. This is called only +after is_counted_repeat() has confirmed that a repeat-count quantifier exists, +so the syntax is guaranteed to be correct, but we need to check the values. + +Arguments: + p pointer to first char after '{' + minp pointer to int for min + maxp pointer to int for max + returned as -1 if no max + errorptr points to pointer to error message + cd pointer to character tables clock + +Returns: pointer to '}' on success; + current ptr on error, with errorptr set +*/ + +static const uschar * +read_repeat_counts(const uschar *p, int *minp, int *maxp, + const char **errorptr, compile_data *cd) +{ +int min = 0; +int max = -1; + +while ((digitab[*p] & ctype_digit) != 0) min = min * 10 + *p++ - '0'; + +if (*p == '}') max = min; else + { + if (*(++p) != '}') + { + max = 0; + while((digitab[*p] & ctype_digit) != 0) max = max * 10 + *p++ - '0'; + if (max < min) + { + *errorptr = ERR4; + return p; + } + } + } + +/* Do paranoid checks, then fill in the required variables, and pass back the +pointer to the terminating '}'. */ + +if (min > 65535 || max > 65535) + *errorptr = ERR5; +else + { + *minp = min; + *maxp = max; + } +return p; +} + + + +/************************************************* +* Find first significant op code * +*************************************************/ + +/* This is called by several functions that scan a compiled expression looking +for a fixed first character, or an anchoring op code etc. It skips over things +that do not influence this. For some calls, a change of option is important. + +Arguments: + code pointer to the start of the group + options pointer to external options + optbit the option bit whose changing is significant, or + zero if none are + +Returns: pointer to the first significant opcode +*/ + +static const uschar* +first_significant_code(const uschar *code, int *options, int optbit) +{ +for (;;) + { + switch ((int)*code) + { + case OP_OPT: + if (optbit > 0 && ((int)code[1] & optbit) != (*options & optbit)) + *options = (int)code[1]; + code += 2; + break; + + case OP_ASSERT_NOT: + case OP_ASSERTBACK: + case OP_ASSERTBACK_NOT: + do code += GET(code, 1); while (*code == OP_ALT); + /* Fall through */ + + case OP_CALLOUT: + case OP_CREF: + case OP_BRANUMBER: + case OP_WORD_BOUNDARY: + case OP_NOT_WORD_BOUNDARY: + code += OP_lengths[*code]; + break; + + default: + return code; + } + } +/* Control never reaches here */ +} + + + + +/************************************************* +* Find the fixed length of a pattern * +*************************************************/ + +/* Scan a pattern and compute the fixed length of subject that will match it, +if the length is fixed. This is needed for dealing with backward assertions. +In UTF8 mode, the result is in characters rather than bytes. + +Arguments: + code points to the start of the pattern (the bracket) + options the compiling options + +Returns: the fixed length, or -1 if there is no fixed length, + or -2 if \C was encountered +*/ + +static int +find_fixedlength(uschar *code, int options) +{ +int length = -1; + +register int branchlength = 0; +register uschar *cc = code + 1 + LINK_SIZE; + +/* Scan along the opcodes for this branch. If we get to the end of the +branch, check the length against that of the other branches. */ + +for (;;) + { + int d; + register int op = *cc; + if (op >= OP_BRA) op = OP_BRA; + + switch (op) + { + case OP_BRA: + case OP_ONCE: + case OP_COND: + d = find_fixedlength(cc, options); + if (d < 0) return d; + branchlength += d; + do cc += GET(cc, 1); while (*cc == OP_ALT); + cc += 1 + LINK_SIZE; + break; + + /* Reached end of a branch; if it's a ket it is the end of a nested + call. If it's ALT it is an alternation in a nested call. If it is + END it's the end of the outer call. All can be handled by the same code. */ + + case OP_ALT: + case OP_KET: + case OP_KETRMAX: + case OP_KETRMIN: + case OP_END: + if (length < 0) length = branchlength; + else if (length != branchlength) return -1; + if (*cc != OP_ALT) return length; + cc += 1 + LINK_SIZE; + branchlength = 0; + break; + + /* Skip over assertive subpatterns */ + + case OP_ASSERT: + case OP_ASSERT_NOT: + case OP_ASSERTBACK: + case OP_ASSERTBACK_NOT: + do cc += GET(cc, 1); while (*cc == OP_ALT); + /* Fall through */ + + /* Skip over things that don't match chars */ + + case OP_REVERSE: + case OP_BRANUMBER: + case OP_CREF: + case OP_OPT: + case OP_CALLOUT: + case OP_SOD: + case OP_SOM: + case OP_EOD: + case OP_EODN: + case OP_CIRC: + case OP_DOLL: + case OP_NOT_WORD_BOUNDARY: + case OP_WORD_BOUNDARY: + cc += OP_lengths[*cc]; + break; + + /* Handle char strings. In UTF-8 mode we must count characters, not bytes. + This requires a scan of the string, unfortunately. We assume valid UTF-8 + strings, so all we do is reduce the length by one for every byte whose bits + are 10xxxxxx. */ + + case OP_CHARS: + branchlength += *(++cc); +#ifdef SUPPORT_UTF8 + if ((options & PCRE_UTF8) != 0) + for (d = 1; d <= *cc; d++) + if ((cc[d] & 0xc0) == 0x80) branchlength--; +#endif + cc += *cc + 1; + break; + + /* Handle exact repetitions. The count is already in characters, but we + need to skip over a multibyte character in UTF8 mode. */ + + case OP_EXACT: + branchlength += GET2(cc,1); + cc += 4; +#ifdef SUPPORT_UTF8 + if ((options & PCRE_UTF8) != 0) + { + while((*cc & 0x80) == 0x80) cc++; + } +#endif + break; + + case OP_TYPEEXACT: + branchlength += GET2(cc,1); + cc += 4; + break; + + /* Handle single-char matchers */ + + case OP_NOT_DIGIT: + case OP_DIGIT: + case OP_NOT_WHITESPACE: + case OP_WHITESPACE: + case OP_NOT_WORDCHAR: + case OP_WORDCHAR: + case OP_ANY: + branchlength++; + cc++; + break; + + /* The single-byte matcher isn't allowed */ + + case OP_ANYBYTE: + return -2; + + /* Check a class for variable quantification */ + +#ifdef SUPPORT_UTF8 + case OP_XCLASS: + cc += GET(cc, 1) - 33; + /* Fall through */ +#endif + + case OP_CLASS: + case OP_NCLASS: + cc += 33; + + switch (*cc) + { + case OP_CRSTAR: + case OP_CRMINSTAR: + case OP_CRQUERY: + case OP_CRMINQUERY: + return -1; + + case OP_CRRANGE: + case OP_CRMINRANGE: + if (GET2(cc,1) != GET2(cc,3)) return -1; + branchlength += GET2(cc,1); + cc += 5; + break; + + default: + branchlength++; + } + break; + + /* Anything else is variable length */ + + default: + return -1; + } + } +/* Control never gets here */ +} + + + + +/************************************************* +* Scan compiled regex for numbered bracket * +*************************************************/ + +/* This little function scans through a compiled pattern until it finds a +capturing bracket with the given number. + +Arguments: + code points to start of expression + utf8 TRUE in UTF-8 mode + number the required bracket number + +Returns: pointer to the opcode for the bracket, or NULL if not found +*/ + +static const uschar * +find_bracket(const uschar *code, BOOL utf8, int number) +{ +#ifndef SUPPORT_UTF8 +utf8 = utf8; /* Stop pedantic compilers complaining */ +#endif + +for (;;) + { + register int c = *code; + if (c == OP_END) return NULL; + else if (c == OP_CHARS) code += code[1] + OP_lengths[c]; + else if (c > OP_BRA) + { + int n = c - OP_BRA; + if (n > EXTRACT_BASIC_MAX) n = GET2(code, 2+LINK_SIZE); + if (n == number) return (uschar *)code; + code += OP_lengths[OP_BRA]; + } + else + { + code += OP_lengths[c]; + + /* In UTF-8 mode, opcodes that are followed by a character may be followed + by a multi-byte character. The length in the table is a minimum, so we have + to scan along to skip the extra characters. All opcodes are less than 128, + so we can use relatively efficient code. */ + +#ifdef SUPPORT_UTF8 + if (utf8) switch(c) + { + case OP_EXACT: + case OP_UPTO: + case OP_MINUPTO: + case OP_STAR: + case OP_MINSTAR: + case OP_PLUS: + case OP_MINPLUS: + case OP_QUERY: + case OP_MINQUERY: + while ((*code & 0xc0) == 0x80) code++; + break; + } +#endif + } + } +} + + + +/************************************************* +* Scan compiled branch for non-emptiness * +*************************************************/ + +/* This function scans through a branch of a compiled pattern to see whether it +can match the empty string or not. It is called only from could_be_empty() +below. Note that first_significant_code() skips over assertions. If we hit an +unclosed bracket, we return "empty" - this means we've struck an inner bracket +whose current branch will already have been scanned. + +Arguments: + code points to start of search + endcode points to where to stop + utf8 TRUE if in UTF8 mode + +Returns: TRUE if what is matched could be empty +*/ + +static BOOL +could_be_empty_branch(const uschar *code, const uschar *endcode, BOOL utf8) +{ +register int c; +for (code = first_significant_code(code + 1 + LINK_SIZE, NULL, 0); + code < endcode; + code = first_significant_code(code + OP_lengths[c], NULL, 0)) + { + const uschar *ccode; + + c = *code; + + if (c >= OP_BRA) + { + BOOL empty_branch; + if (GET(code, 1) == 0) return TRUE; /* Hit unclosed bracket */ + + /* Scan a closed bracket */ + + empty_branch = FALSE; + do + { + if (!empty_branch && could_be_empty_branch(code, endcode, utf8)) + empty_branch = TRUE; + code += GET(code, 1); + } + while (*code == OP_ALT); + if (!empty_branch) return FALSE; /* All branches are non-empty */ + code += 1 + LINK_SIZE; + c = *code; + } + + else switch (c) + { + /* Check for quantifiers after a class */ + +#ifdef SUPPORT_UTF8 + case OP_XCLASS: + ccode = code + GET(code, 1); + goto CHECK_CLASS_REPEAT; +#endif + + case OP_CLASS: + case OP_NCLASS: + ccode = code + 33; + +#ifdef SUPPORT_UTF8 + CHECK_CLASS_REPEAT: +#endif + + switch (*ccode) + { + case OP_CRSTAR: /* These could be empty; continue */ + case OP_CRMINSTAR: + case OP_CRQUERY: + case OP_CRMINQUERY: + break; + + default: /* Non-repeat => class must match */ + case OP_CRPLUS: /* These repeats aren't empty */ + case OP_CRMINPLUS: + return FALSE; + + case OP_CRRANGE: + case OP_CRMINRANGE: + if (GET2(ccode, 1) > 0) return FALSE; /* Minimum > 0 */ + break; + } + break; + + /* Opcodes that must match a character */ + + case OP_NOT_DIGIT: + case OP_DIGIT: + case OP_NOT_WHITESPACE: + case OP_WHITESPACE: + case OP_NOT_WORDCHAR: + case OP_WORDCHAR: + case OP_ANY: + case OP_ANYBYTE: + case OP_CHARS: + case OP_NOT: + case OP_PLUS: + case OP_MINPLUS: + case OP_EXACT: + case OP_NOTPLUS: + case OP_NOTMINPLUS: + case OP_NOTEXACT: + case OP_TYPEPLUS: + case OP_TYPEMINPLUS: + case OP_TYPEEXACT: + return FALSE; + + /* End of branch */ + + case OP_KET: + case OP_KETRMAX: + case OP_KETRMIN: + case OP_ALT: + return TRUE; + + /* In UTF-8 mode, STAR, MINSTAR, QUERY, MINQUERY, UPTO, and MINUPTO may be + followed by a multibyte character */ + +#ifdef SUPPORT_UTF8 + case OP_STAR: + case OP_MINSTAR: + case OP_QUERY: + case OP_MINQUERY: + case OP_UPTO: + case OP_MINUPTO: + if (utf8) while ((code[2] & 0xc0) == 0x80) code++; + break; +#endif + } + } + +return TRUE; +} + + + +/************************************************* +* Scan compiled regex for non-emptiness * +*************************************************/ + +/* This function is called to check for left recursive calls. We want to check +the current branch of the current pattern to see if it could match the empty +string. If it could, we must look outwards for branches at other levels, +stopping when we pass beyond the bracket which is the subject of the recursion. + +Arguments: + code points to start of the recursion + endcode points to where to stop (current RECURSE item) + bcptr points to the chain of current (unclosed) branch starts + utf8 TRUE if in UTF-8 mode + +Returns: TRUE if what is matched could be empty +*/ + +static BOOL +could_be_empty(const uschar *code, const uschar *endcode, branch_chain *bcptr, + BOOL utf8) +{ +while (bcptr != NULL && bcptr->current >= code) + { + if (!could_be_empty_branch(bcptr->current, endcode, utf8)) return FALSE; + bcptr = bcptr->outer; + } +return TRUE; +} + + + +/************************************************* +* Check for POSIX class syntax * +*************************************************/ + +/* This function is called when the sequence "[:" or "[." or "[=" is +encountered in a character class. It checks whether this is followed by an +optional ^ and then a sequence of letters, terminated by a matching ":]" or +".]" or "=]". + +Argument: + ptr pointer to the initial [ + endptr where to return the end pointer + cd pointer to compile data + +Returns: TRUE or FALSE +*/ + +static BOOL +check_posix_syntax(const uschar *ptr, const uschar **endptr, compile_data *cd) +{ +int terminator; /* Don't combine these lines; the Solaris cc */ +terminator = *(++ptr); /* compiler warns about "non-constant" initializer. */ +if (*(++ptr) == '^') ptr++; +while ((cd->ctypes[*ptr] & ctype_letter) != 0) ptr++; +if (*ptr == terminator && ptr[1] == ']') + { + *endptr = ptr; + return TRUE; + } +return FALSE; +} + + + + +/************************************************* +* Check POSIX class name * +*************************************************/ + +/* This function is called to check the name given in a POSIX-style class entry +such as [:alnum:]. + +Arguments: + ptr points to the first letter + len the length of the name + +Returns: a value representing the name, or -1 if unknown +*/ + +static int +check_posix_name(const uschar *ptr, int len) +{ +register int yield = 0; +while (posix_name_lengths[yield] != 0) + { + if (len == posix_name_lengths[yield] && + strncmp((const char *)ptr, posix_names[yield], len) == 0) return yield; + yield++; + } +return -1; +} + + + + +/************************************************* +* Compile one branch * +*************************************************/ + +/* Scan the pattern, compiling it into the code vector. If the options are +changed during the branch, the pointer is used to change the external options +bits. + +Arguments: + optionsptr pointer to the option bits + brackets points to number of extracting brackets used + code points to the pointer to the current code point + ptrptr points to the current pattern pointer + errorptr points to pointer to error message + firstbyteptr set to initial literal character, or < 0 (REQ_UNSET, REQ_NONE) + reqbyteptr set to the last literal character required, else < 0 + bcptr points to current branch chain + cd contains pointers to tables etc. + +Returns: TRUE on success + FALSE, with *errorptr set on error +*/ + +static BOOL +compile_branch(int *optionsptr, int *brackets, uschar **codeptr, + const uschar **ptrptr, const char **errorptr, int *firstbyteptr, + int *reqbyteptr, branch_chain *bcptr, compile_data *cd) +{ +int repeat_type, op_type; +int repeat_min = 0, repeat_max = 0; /* To please picky compilers */ +int bravalue = 0; +int length; +int greedy_default, greedy_non_default; +int firstbyte, reqbyte; +int zeroreqbyte, zerofirstbyte; +int req_caseopt, reqvary, tempreqvary; +int condcount = 0; +int options = *optionsptr; +register int c; +register uschar *code = *codeptr; +uschar *tempcode; +BOOL inescq = FALSE; +BOOL groupsetfirstbyte = FALSE; +const uschar *ptr = *ptrptr; +const uschar *tempptr; +uschar *previous = NULL; +uschar class[32]; + +#ifdef SUPPORT_UTF8 +BOOL class_utf8; +BOOL utf8 = (options & PCRE_UTF8) != 0; +uschar *class_utf8data; +uschar utf8_char[6]; +#else +BOOL utf8 = FALSE; +#endif + +/* Set up the default and non-default settings for greediness */ + +greedy_default = ((options & PCRE_UNGREEDY) != 0); +greedy_non_default = greedy_default ^ 1; + +/* Initialize no first char, no required char. REQ_UNSET means "no char +matching encountered yet". It gets changed to REQ_NONE if we hit something that +matches a non-fixed char first char; reqbyte just remains unset if we never +find one. + +When we hit a repeat whose minimum is zero, we may have to adjust these values +to take the zero repeat into account. This is implemented by setting them to +zerofirstbyte and zeroreqbyte when such a repeat is encountered. The individual +item types that can be repeated set these backoff variables appropriately. */ + +firstbyte = reqbyte = zerofirstbyte = zeroreqbyte = REQ_UNSET; + +/* The variable req_caseopt contains either the REQ_CASELESS value or zero, +according to the current setting of the caseless flag. REQ_CASELESS is a bit +value > 255. It is added into the firstbyte or reqbyte variables to record the +case status of the value. */ + +req_caseopt = ((options & PCRE_CASELESS) != 0)? REQ_CASELESS : 0; + +/* Switch on next character until the end of the branch */ + +for (;; ptr++) + { + BOOL negate_class; + BOOL possessive_quantifier; + int class_charcount; + int class_lastchar; + int newoptions; + int recno; + int skipbytes; + int subreqbyte; + int subfirstbyte; + + c = *ptr; + if (inescq && c != 0) goto NORMAL_CHAR; + + if ((options & PCRE_EXTENDED) != 0) + { + if ((cd->ctypes[c] & ctype_space) != 0) continue; + if (c == '#') + { + /* The space before the ; is to avoid a warning on a silly compiler + on the Macintosh. */ + while ((c = *(++ptr)) != 0 && c != NEWLINE) ; + if (c != 0) continue; /* Else fall through to handle end of string */ + } + } + + switch(c) + { + /* The branch terminates at end of string, |, or ). */ + + case 0: + case '|': + case ')': + *firstbyteptr = firstbyte; + *reqbyteptr = reqbyte; + *codeptr = code; + *ptrptr = ptr; + return TRUE; + + /* Handle single-character metacharacters. In multiline mode, ^ disables + the setting of any following char as a first character. */ + + case '^': + if ((options & PCRE_MULTILINE) != 0) + { + if (firstbyte == REQ_UNSET) firstbyte = REQ_NONE; + } + previous = NULL; + *code++ = OP_CIRC; + break; + + case '$': + previous = NULL; + *code++ = OP_DOLL; + break; + + /* There can never be a first char if '.' is first, whatever happens about + repeats. The value of reqbyte doesn't change either. */ + + case '.': + if (firstbyte == REQ_UNSET) firstbyte = REQ_NONE; + zerofirstbyte = firstbyte; + zeroreqbyte = reqbyte; + previous = code; + *code++ = OP_ANY; + break; + + /* Character classes. If the included characters are all < 255 in value, we + build a 32-byte bitmap of the permitted characters, except in the special + case where there is only one such character. For negated classes, we build + the map as usual, then invert it at the end. However, we use a different + opcode so that data characters > 255 can be handled correctly. + + If the class contains characters outside the 0-255 range, a different + opcode is compiled. It may optionally have a bit map for characters < 256, + but those above are are explicitly listed afterwards. A flag byte tells + whether the bitmap is present, and whether this is a negated class or not. + */ + + case '[': + previous = code; + + /* PCRE supports POSIX class stuff inside a class. Perl gives an error if + they are encountered at the top level, so we'll do that too. */ + + if ((ptr[1] == ':' || ptr[1] == '.' || ptr[1] == '=') && + check_posix_syntax(ptr, &tempptr, cd)) + { + *errorptr = (ptr[1] == ':')? ERR13 : ERR31; + goto FAILED; + } + + /* If the first character is '^', set the negation flag and skip it. */ + + if ((c = *(++ptr)) == '^') + { + negate_class = TRUE; + c = *(++ptr); + } + else + { + negate_class = FALSE; + } + + /* Keep a count of chars with values < 256 so that we can optimize the case + of just a single character (as long as it's < 256). For higher valued UTF-8 + characters, we don't yet do any optimization. */ + + class_charcount = 0; + class_lastchar = -1; + +#ifdef SUPPORT_UTF8 + class_utf8 = FALSE; /* No chars >= 256 */ + class_utf8data = code + LINK_SIZE + 34; /* For UTF-8 items */ +#endif + + /* Initialize the 32-char bit map to all zeros. We have to build the + map in a temporary bit of store, in case the class contains only 1 + character (< 256), because in that case the compiled code doesn't use the + bit map. */ + + memset(class, 0, 32 * sizeof(uschar)); + + /* Process characters until ] is reached. By writing this as a "do" it + means that an initial ] is taken as a data character. The first pass + through the regex checked the overall syntax, so we don't need to be very + strict here. At the start of the loop, c contains the first byte of the + character. */ + + do + { +#ifdef SUPPORT_UTF8 + if (utf8 && c > 127) + { /* Braces are required because the */ + GETCHARLEN(c, ptr, ptr); /* macro generates multiple statements */ + } +#endif + + /* Inside \Q...\E everything is literal except \E */ + + if (inescq) + { + if (c == '\\' && ptr[1] == 'E') + { + inescq = FALSE; + ptr++; + continue; + } + else goto LONE_SINGLE_CHARACTER; + } + + /* Handle POSIX class names. Perl allows a negation extension of the + form [:^name:]. A square bracket that doesn't match the syntax is + treated as a literal. We also recognize the POSIX constructions + [.ch.] and [=ch=] ("collating elements") and fault them, as Perl + 5.6 and 5.8 do. */ + + if (c == '[' && + (ptr[1] == ':' || ptr[1] == '.' || ptr[1] == '=') && + check_posix_syntax(ptr, &tempptr, cd)) + { + BOOL local_negate = FALSE; + int posix_class, i; + register const uschar *cbits = cd->cbits; + + if (ptr[1] != ':') + { + *errorptr = ERR31; + goto FAILED; + } + + ptr += 2; + if (*ptr == '^') + { + local_negate = TRUE; + ptr++; + } + + posix_class = check_posix_name(ptr, tempptr - ptr); + if (posix_class < 0) + { + *errorptr = ERR30; + goto FAILED; + } + + /* If matching is caseless, upper and lower are converted to + alpha. This relies on the fact that the class table starts with + alpha, lower, upper as the first 3 entries. */ + + if ((options & PCRE_CASELESS) != 0 && posix_class <= 2) + posix_class = 0; + + /* Or into the map we are building up to 3 of the static class + tables, or their negations. The [:blank:] class sets up the same + chars as the [:space:] class (all white space). We remove the vertical + white space chars afterwards. */ + + posix_class *= 3; + for (i = 0; i < 3; i++) + { + BOOL isblank = strncmp((char *)ptr, "blank", 5) == 0; + int taboffset = posix_class_maps[posix_class + i]; + if (taboffset < 0) break; + if (local_negate) + { + for (c = 0; c < 32; c++) class[c] |= ~cbits[c+taboffset]; + if (isblank) class[1] |= 0x3c; + } + else + { + for (c = 0; c < 32; c++) class[c] |= cbits[c+taboffset]; + if (isblank) class[1] &= ~0x3c; + } + } + + ptr = tempptr + 1; + class_charcount = 10; /* Set > 1; assumes more than 1 per class */ + continue; /* End of POSIX syntax handling */ + } + + /* Backslash may introduce a single character, or it may introduce one + of the specials, which just set a flag. Escaped items are checked for + validity in the pre-compiling pass. The sequence \b is a special case. + Inside a class (and only there) it is treated as backspace. Elsewhere + it marks a word boundary. Other escapes have preset maps ready to + or into the one we are building. We assume they have more than one + character in them, so set class_charcount bigger than one. */ + + if (c == '\\') + { + c = check_escape(&ptr, errorptr, *brackets, options, TRUE, cd); + if (-c == ESC_b) c = '\b'; /* \b is backslash in a class */ + + if (-c == ESC_Q) /* Handle start of quoted string */ + { + if (ptr[1] == '\\' && ptr[2] == 'E') + { + ptr += 2; /* avoid empty string */ + } + else inescq = TRUE; + continue; + } + + else if (c < 0) + { + register const uschar *cbits = cd->cbits; + class_charcount = 10; /* Greater than 1 is what matters */ + switch (-c) + { + case ESC_d: + for (c = 0; c < 32; c++) class[c] |= cbits[c+cbit_digit]; + continue; + + case ESC_D: + for (c = 0; c < 32; c++) class[c] |= ~cbits[c+cbit_digit]; + continue; + + case ESC_w: + for (c = 0; c < 32; c++) class[c] |= cbits[c+cbit_word]; + continue; + + case ESC_W: + for (c = 0; c < 32; c++) class[c] |= ~cbits[c+cbit_word]; + continue; + + case ESC_s: + for (c = 0; c < 32; c++) class[c] |= cbits[c+cbit_space]; + class[1] &= ~0x08; /* Perl 5.004 onwards omits VT from \s */ + continue; + + case ESC_S: + for (c = 0; c < 32; c++) class[c] |= ~cbits[c+cbit_space]; + class[1] |= 0x08; /* Perl 5.004 onwards omits VT from \s */ + continue; + + /* Unrecognized escapes are faulted if PCRE is running in its + strict mode. By default, for compatibility with Perl, they are + treated as literals. */ + + default: + if ((options & PCRE_EXTRA) != 0) + { + *errorptr = ERR7; + goto FAILED; + } + c = *ptr; /* The final character */ + } + } + + /* Fall through if we have a single character (c >= 0). This may be + > 256 in UTF-8 mode. */ + + } /* End of backslash handling */ + + /* A single character may be followed by '-' to form a range. However, + Perl does not permit ']' to be the end of the range. A '-' character + here is treated as a literal. */ + + if (ptr[1] == '-' && ptr[2] != ']') + { + int d; + ptr += 2; + +#ifdef SUPPORT_UTF8 + if (utf8) + { /* Braces are required because the */ + GETCHARLEN(d, ptr, ptr); /* macro generates multiple statements */ + } + else +#endif + d = *ptr; + + /* The second part of a range can be a single-character escape, but + not any of the other escapes. Perl 5.6 treats a hyphen as a literal + in such circumstances. */ + + if (d == '\\') + { + const uschar *oldptr = ptr; + d = check_escape(&ptr, errorptr, *brackets, options, TRUE, cd); + + /* \b is backslash; any other special means the '-' was literal */ + + if (d < 0) + { + if (d == -ESC_b) d = '\b'; else + { + ptr = oldptr - 2; + goto LONE_SINGLE_CHARACTER; /* A few lines below */ + } + } + } + + /* Check that the two values are in the correct order */ + + if (d < c) + { + *errorptr = ERR8; + goto FAILED; + } + + /* If d is greater than 255, we can't just use the bit map, so set up + for the UTF-8 supporting class type. If we are not caseless, we can + just set up a single range. If we are caseless, the characters < 256 + are handled with a bitmap, in order to get the case-insensitive + handling. */ + +#ifdef SUPPORT_UTF8 + if (d > 255) + { + class_utf8 = TRUE; + *class_utf8data++ = XCL_RANGE; + if ((options & PCRE_CASELESS) == 0) + { + class_utf8data += ord2utf8(c, class_utf8data); + class_utf8data += ord2utf8(d, class_utf8data); + continue; /* Go get the next char in the class */ + } + class_utf8data += ord2utf8(256, class_utf8data); + class_utf8data += ord2utf8(d, class_utf8data); + d = 255; + /* Fall through */ + } +#endif + /* We use the bit map if the range is entirely < 255, or if part of it + is < 255 and matching is caseless. */ + + for (; c <= d; c++) + { + class[c/8] |= (1 << (c&7)); + if ((options & PCRE_CASELESS) != 0) + { + int uc = cd->fcc[c]; /* flip case */ + class[uc/8] |= (1 << (uc&7)); + } + class_charcount++; /* in case a one-char range */ + class_lastchar = c; + } + + continue; /* Go get the next char in the class */ + } + + /* Handle a lone single character - we can get here for a normal + non-escape char, or after \ that introduces a single character. */ + + LONE_SINGLE_CHARACTER: + + /* Handle a multibyte character */ + +#ifdef SUPPORT_UTF8 + if (utf8 && c > 255) + { + class_utf8 = TRUE; + *class_utf8data++ = XCL_SINGLE; + class_utf8data += ord2utf8(c, class_utf8data); + } + else +#endif + /* Handle a single-byte character */ + { + class [c/8] |= (1 << (c&7)); + if ((options & PCRE_CASELESS) != 0) + { + c = cd->fcc[c]; /* flip case */ + class[c/8] |= (1 << (c&7)); + } + class_charcount++; + class_lastchar = c; + } + } + + /* Loop until ']' reached; the check for end of string happens inside the + loop. This "while" is the end of the "do" above. */ + + while ((c = *(++ptr)) != ']' || inescq); + + /* If class_charcount is 1, we saw precisely one character with a value < + 256. In UTF-8 mode, we can optimize if there were no characters >= 256 and + the one character is < 128. In non-UTF-8 mode we can always optimize. + + The optimization throws away the bit map. We turn the item into a + 1-character OP_CHARS if it's positive, or OP_NOT if it's negative. Note + that OP_NOT does not support multibyte characters. In the positive case, it + can cause firstbyte to be set. Otherwise, there can be no first char if + this item is first, whatever repeat count may follow. In the case of + reqbyte, save the previous value for reinstating. */ + +#ifdef SUPPORT_UTF8 + if (class_charcount == 1 && + (!utf8 || + (!class_utf8 && class_lastchar < 128))) +#else + if (class_charcount == 1) +#endif + { + zeroreqbyte = reqbyte; + if (negate_class) + { + if (firstbyte == REQ_UNSET) firstbyte = REQ_NONE; + zerofirstbyte = firstbyte; + *code++ = OP_NOT; + } + else + { + if (firstbyte == REQ_UNSET) + { + zerofirstbyte = REQ_NONE; + firstbyte = class_lastchar | req_caseopt; + } + else + { + zerofirstbyte = firstbyte; + reqbyte = class_lastchar | req_caseopt | cd->req_varyopt; + } + *code++ = OP_CHARS; + *code++ = 1; + } + *code++ = class_lastchar; + break; /* End of class handling */ + } /* End of 1-byte optimization */ + + /* Otherwise, if this is the first thing in the branch, there can be no + first char setting, whatever the repeat count. Any reqbyte setting must + remain unchanged after any kind of repeat. */ + + if (firstbyte == REQ_UNSET) firstbyte = REQ_NONE; + zerofirstbyte = firstbyte; + zeroreqbyte = reqbyte; + + /* If there are characters with values > 255, we have to compile an + extended class, with its own opcode. If there are no characters < 256, + we can omit the bitmap. */ + +#ifdef SUPPORT_UTF8 + if (class_utf8) + { + *class_utf8data++ = XCL_END; /* Marks the end of extra data */ + *code++ = OP_XCLASS; + code += LINK_SIZE; + *code = negate_class? XCL_NOT : 0; + + /* If the map is required, install it, and move on to the end of + the extra data */ + + if (class_charcount > 0) + { + *code++ |= XCL_MAP; + memcpy(code, class, 32); + code = class_utf8data; + } + + /* If the map is not required, slide down the extra data. */ + + else + { + int len = class_utf8data - (code + 33); + memmove(code + 1, code + 33, len); + code += len + 1; + } + + /* Now fill in the complete length of the item */ + + PUT(previous, 1, code - previous); + break; /* End of class handling */ + } +#endif + + /* If there are no characters > 255, negate the 32-byte map if necessary, + and copy it into the code vector. If this is the first thing in the branch, + there can be no first char setting, whatever the repeat count. Any reqbyte + setting must remain unchanged after any kind of repeat. */ + + if (negate_class) + { + *code++ = OP_NCLASS; + for (c = 0; c < 32; c++) code[c] = ~class[c]; + } + else + { + *code++ = OP_CLASS; + memcpy(code, class, 32); + } + code += 32; + break; + + /* Various kinds of repeat */ + + case '{': + if (!is_counted_repeat(ptr+1, cd)) goto NORMAL_CHAR; + ptr = read_repeat_counts(ptr+1, &repeat_min, &repeat_max, errorptr, cd); + if (*errorptr != NULL) goto FAILED; + goto REPEAT; + + case '*': + repeat_min = 0; + repeat_max = -1; + goto REPEAT; + + case '+': + repeat_min = 1; + repeat_max = -1; + goto REPEAT; + + case '?': + repeat_min = 0; + repeat_max = 1; + + REPEAT: + if (previous == NULL) + { + *errorptr = ERR9; + goto FAILED; + } + + if (repeat_min == 0) + { + firstbyte = zerofirstbyte; /* Adjust for zero repeat */ + reqbyte = zeroreqbyte; /* Ditto */ + } + + /* Remember whether this is a variable length repeat */ + + reqvary = (repeat_min == repeat_max)? 0 : REQ_VARY; + + op_type = 0; /* Default single-char op codes */ + possessive_quantifier = FALSE; /* Default not possessive quantifier */ + + /* Save start of previous item, in case we have to move it up to make space + for an inserted OP_ONCE for the additional '+' extension. */ + + tempcode = previous; + + /* If the next character is '+', we have a possessive quantifier. This + implies greediness, whatever the setting of the PCRE_UNGREEDY option. + If the next character is '?' this is a minimizing repeat, by default, + but if PCRE_UNGREEDY is set, it works the other way round. We change the + repeat type to the non-default. */ + + if (ptr[1] == '+') + { + repeat_type = 0; /* Force greedy */ + possessive_quantifier = TRUE; + ptr++; + } + else if (ptr[1] == '?') + { + repeat_type = greedy_non_default; + ptr++; + } + else repeat_type = greedy_default; + + /* If previous was a recursion, we need to wrap it inside brackets so that + it can be replicated if necessary. */ + + if (*previous == OP_RECURSE) + { + memmove(previous + 1 + LINK_SIZE, previous, 1 + LINK_SIZE); + code += 1 + LINK_SIZE; + *previous = OP_BRA; + PUT(previous, 1, code - previous); + *code = OP_KET; + PUT(code, 1, code - previous); + code += 1 + LINK_SIZE; + } + + /* If previous was a string of characters, chop off the last one and use it + as the subject of the repeat. If there was only one character, we can + abolish the previous item altogether. If a one-char item has a minumum of + more than one, ensure that it is set in reqbyte - it might not be if a + sequence such as x{3} is the first thing in a branch because the x will + have gone into firstbyte instead. */ + + if (*previous == OP_CHARS) + { + /* Deal with UTF-8 characters that take up more than one byte. It's + easier to write this out separately than try to macrify it. Use c to + hold the length of the character in bytes, plus 0x80 to flag that it's a + length rather than a small character. */ + +#ifdef SUPPORT_UTF8 + if (utf8 && (code[-1] & 0x80) != 0) + { + uschar *lastchar = code - 1; + while((*lastchar & 0xc0) == 0x80) lastchar--; + c = code - lastchar; /* Length of UTF-8 character */ + memcpy(utf8_char, lastchar, c); /* Save the char */ + if (lastchar == previous + 2) /* There was only one character */ + { + code = previous; /* Abolish the previous item */ + } + else + { + previous[1] -= c; /* Adjust length of previous */ + code = lastchar; /* Lost char off the end */ + tempcode = code; /* Adjust position to be moved for '+' */ + } + c |= 0x80; /* Flag c as a length */ + } + else +#endif + + /* Handle the case of a single byte - either with no UTF8 support, or + with UTF-8 disabled, or for a UTF-8 character < 128. */ + + { + c = *(--code); + if (code == previous + 2) /* There was only one character */ + { + code = previous; /* Abolish the previous item */ + if (repeat_min > 1) reqbyte = c | req_caseopt | cd->req_varyopt; + } + else + { + previous[1]--; /* adjust length */ + tempcode = code; /* Adjust position to be moved for '+' */ + } + } + + goto OUTPUT_SINGLE_REPEAT; /* Code shared with single character types */ + } + + /* If previous was a single negated character ([^a] or similar), we use + one of the special opcodes, replacing it. The code is shared with single- + character repeats by setting opt_type to add a suitable offset into + repeat_type. OP_NOT is currently used only for single-byte chars. */ + + else if (*previous == OP_NOT) + { + op_type = OP_NOTSTAR - OP_STAR; /* Use "not" opcodes */ + c = previous[1]; + code = previous; + goto OUTPUT_SINGLE_REPEAT; + } + + /* If previous was a character type match (\d or similar), abolish it and + create a suitable repeat item. The code is shared with single-character + repeats by setting op_type to add a suitable offset into repeat_type. */ + + else if (*previous < OP_EODN) + { + op_type = OP_TYPESTAR - OP_STAR; /* Use type opcodes */ + c = *previous; + code = previous; + + OUTPUT_SINGLE_REPEAT: + + /* If the maximum is zero then the minimum must also be zero; Perl allows + this case, so we do too - by simply omitting the item altogether. */ + + if (repeat_max == 0) goto END_REPEAT; + + /* Combine the op_type with the repeat_type */ + + repeat_type += op_type; + + /* A minimum of zero is handled either as the special case * or ?, or as + an UPTO, with the maximum given. */ + + if (repeat_min == 0) + { + if (repeat_max == -1) *code++ = OP_STAR + repeat_type; + else if (repeat_max == 1) *code++ = OP_QUERY + repeat_type; + else + { + *code++ = OP_UPTO + repeat_type; + PUT2INC(code, 0, repeat_max); + } + } + + /* The case {1,} is handled as the special case + */ + + else if (repeat_min == 1 && repeat_max == -1) + *code++ = OP_PLUS + repeat_type; + + /* The case {n,n} is just an EXACT, while the general case {n,m} is + handled as an EXACT followed by an UPTO. An EXACT of 1 is optimized. */ + + else + { + if (repeat_min != 1) + { + *code++ = OP_EXACT + op_type; /* NB EXACT doesn't have repeat_type */ + PUT2INC(code, 0, repeat_min); + } + + /* If the mininum is 1 and the previous item was a character string, + we either have to put back the item that got cancelled if the string + length was 1, or add the character back onto the end of a longer + string. For a character type nothing need be done; it will just get + put back naturally. Note that the final character is always going to + get added below, so we leave code ready for its insertion. */ + + else if (*previous == OP_CHARS) + { + if (code == previous) code += 2; else + + /* In UTF-8 mode, a multibyte char has its length in c, with the 0x80 + bit set as a flag. The length will always be between 2 and 6. */ + +#ifdef SUPPORT_UTF8 + if (utf8 && c >= 128) previous[1] += c & 7; else +#endif + previous[1]++; + } + + /* For a single negated character we also have to put back the + item that got cancelled. At present this applies only to single byte + characters in any mode. */ + + else if (*previous == OP_NOT) code++; + + /* If the maximum is unlimited, insert an OP_STAR. Before doing so, + we have to insert the character for the previous code. In UTF-8 mode, + long characters have their length in c, with the 0x80 bit as a flag. */ + + if (repeat_max < 0) + { +#ifdef SUPPORT_UTF8 + if (utf8 && c >= 128) + { + memcpy(code, utf8_char, c & 7); + code += c & 7; + } + else +#endif + *code++ = c; + *code++ = OP_STAR + repeat_type; + } + + /* Else insert an UPTO if the max is greater than the min, again + preceded by the character, for the previously inserted code. */ + + else if (repeat_max != repeat_min) + { +#ifdef SUPPORT_UTF8 + if (utf8 && c >= 128) + { + memcpy(code, utf8_char, c & 7); + code += c & 7; + } + else +#endif + *code++ = c; + repeat_max -= repeat_min; + *code++ = OP_UPTO + repeat_type; + PUT2INC(code, 0, repeat_max); + } + } + + /* The character or character type itself comes last in all cases. */ + +#ifdef SUPPORT_UTF8 + if (utf8 && c >= 128) + { + memcpy(code, utf8_char, c & 7); + code += c & 7; + } + else +#endif + + *code++ = c; + } + + /* If previous was a character class or a back reference, we put the repeat + stuff after it, but just skip the item if the repeat was {0,0}. */ + + else if (*previous == OP_CLASS || + *previous == OP_NCLASS || +#ifdef SUPPORT_UTF8 + *previous == OP_XCLASS || +#endif + *previous == OP_REF) + { + if (repeat_max == 0) + { + code = previous; + goto END_REPEAT; + } + if (repeat_min == 0 && repeat_max == -1) + *code++ = OP_CRSTAR + repeat_type; + else if (repeat_min == 1 && repeat_max == -1) + *code++ = OP_CRPLUS + repeat_type; + else if (repeat_min == 0 && repeat_max == 1) + *code++ = OP_CRQUERY + repeat_type; + else + { + *code++ = OP_CRRANGE + repeat_type; + PUT2INC(code, 0, repeat_min); + if (repeat_max == -1) repeat_max = 0; /* 2-byte encoding for max */ + PUT2INC(code, 0, repeat_max); + } + } + + /* If previous was a bracket group, we may have to replicate it in certain + cases. */ + + else if (*previous >= OP_BRA || *previous == OP_ONCE || + *previous == OP_COND) + { + register int i; + int ketoffset = 0; + int len = code - previous; + uschar *bralink = NULL; + + /* If the maximum repeat count is unlimited, find the end of the bracket + by scanning through from the start, and compute the offset back to it + from the current code pointer. There may be an OP_OPT setting following + the final KET, so we can't find the end just by going back from the code + pointer. */ + + if (repeat_max == -1) + { + register uschar *ket = previous; + do ket += GET(ket, 1); while (*ket != OP_KET); + ketoffset = code - ket; + } + + /* The case of a zero minimum is special because of the need to stick + OP_BRAZERO in front of it, and because the group appears once in the + data, whereas in other cases it appears the minimum number of times. For + this reason, it is simplest to treat this case separately, as otherwise + the code gets far too messy. There are several special subcases when the + minimum is zero. */ + + if (repeat_min == 0) + { + /* If the maximum is also zero, we just omit the group from the output + altogether. */ + + if (repeat_max == 0) + { + code = previous; + goto END_REPEAT; + } + + /* If the maximum is 1 or unlimited, we just have to stick in the + BRAZERO and do no more at this point. */ + + if (repeat_max <= 1) + { + memmove(previous+1, previous, len); + code++; + *previous++ = OP_BRAZERO + repeat_type; + } + + /* If the maximum is greater than 1 and limited, we have to replicate + in a nested fashion, sticking OP_BRAZERO before each set of brackets. + The first one has to be handled carefully because it's the original + copy, which has to be moved up. The remainder can be handled by code + that is common with the non-zero minimum case below. We just have to + adjust the value or repeat_max, since one less copy is required. */ + + else + { + int offset; + memmove(previous + 2 + LINK_SIZE, previous, len); + code += 2 + LINK_SIZE; + *previous++ = OP_BRAZERO + repeat_type; + *previous++ = OP_BRA; + + /* We chain together the bracket offset fields that have to be + filled in later when the ends of the brackets are reached. */ + + offset = (bralink == NULL)? 0 : previous - bralink; + bralink = previous; + PUTINC(previous, 0, offset); + } + + repeat_max--; + } + + /* If the minimum is greater than zero, replicate the group as many + times as necessary, and adjust the maximum to the number of subsequent + copies that we need. If we set a first char from the group, and didn't + set a required char, copy the latter from the former. */ + + else + { + if (repeat_min > 1) + { + if (groupsetfirstbyte && reqbyte < 0) reqbyte = firstbyte; + for (i = 1; i < repeat_min; i++) + { + memcpy(code, previous, len); + code += len; + } + } + if (repeat_max > 0) repeat_max -= repeat_min; + } + + /* This code is common to both the zero and non-zero minimum cases. If + the maximum is limited, it replicates the group in a nested fashion, + remembering the bracket starts on a stack. In the case of a zero minimum, + the first one was set up above. In all cases the repeat_max now specifies + the number of additional copies needed. */ + + if (repeat_max >= 0) + { + for (i = repeat_max - 1; i >= 0; i--) + { + *code++ = OP_BRAZERO + repeat_type; + + /* All but the final copy start a new nesting, maintaining the + chain of brackets outstanding. */ + + if (i != 0) + { + int offset; + *code++ = OP_BRA; + offset = (bralink == NULL)? 0 : code - bralink; + bralink = code; + PUTINC(code, 0, offset); + } + + memcpy(code, previous, len); + code += len; + } + + /* Now chain through the pending brackets, and fill in their length + fields (which are holding the chain links pro tem). */ + + while (bralink != NULL) + { + int oldlinkoffset; + int offset = code - bralink + 1; + uschar *bra = code - offset; + oldlinkoffset = GET(bra, 1); + bralink = (oldlinkoffset == 0)? NULL : bralink - oldlinkoffset; + *code++ = OP_KET; + PUTINC(code, 0, offset); + PUT(bra, 1, offset); + } + } + + /* If the maximum is unlimited, set a repeater in the final copy. We + can't just offset backwards from the current code point, because we + don't know if there's been an options resetting after the ket. The + correct offset was computed above. */ + + else code[-ketoffset] = OP_KETRMAX + repeat_type; + } + + /* Else there's some kind of shambles */ + + else + { + *errorptr = ERR11; + goto FAILED; + } + + /* If the character following a repeat is '+', we wrap the entire repeated + item inside OP_ONCE brackets. This is just syntactic sugar, taken from + Sun's Java package. The repeated item starts at tempcode, not at previous, + which might be the first part of a string whose (former) last char we + repeated. However, we don't support '+' after a greediness '?'. */ + + if (possessive_quantifier) + { + int len = code - tempcode; + memmove(tempcode + 1+LINK_SIZE, tempcode, len); + code += 1 + LINK_SIZE; + len += 1 + LINK_SIZE; + tempcode[0] = OP_ONCE; + *code++ = OP_KET; + PUTINC(code, 0, len); + PUT(tempcode, 1, len); + } + + /* In all case we no longer have a previous item. We also set the + "follows varying string" flag for subsequently encountered reqbytes if + it isn't already set and we have just passed a varying length item. */ + + END_REPEAT: + previous = NULL; + cd->req_varyopt |= reqvary; + break; + + + /* Start of nested bracket sub-expression, or comment or lookahead or + lookbehind or option setting or condition. First deal with special things + that can come after a bracket; all are introduced by ?, and the appearance + of any of them means that this is not a referencing group. They were + checked for validity in the first pass over the string, so we don't have to + check for syntax errors here. */ + + case '(': + newoptions = options; + skipbytes = 0; + + if (*(++ptr) == '?') + { + int set, unset; + int *optset; + + switch (*(++ptr)) + { + case '#': /* Comment; skip to ket */ + ptr++; + while (*ptr != ')') ptr++; + continue; + + case ':': /* Non-extracting bracket */ + bravalue = OP_BRA; + ptr++; + break; + + case '(': + bravalue = OP_COND; /* Conditional group */ + + /* Condition to test for recursion */ + + if (ptr[1] == 'R') + { + code[1+LINK_SIZE] = OP_CREF; + PUT2(code, 2+LINK_SIZE, CREF_RECURSE); + skipbytes = 3; + ptr += 3; + } + + /* Condition to test for a numbered subpattern match. We know that + if a digit follows ( then there will just be digits until ) because + the syntax was checked in the first pass. */ + + else if ((digitab[ptr[1]] && ctype_digit) != 0) + { + int condref; /* Don't amalgamate; some compilers */ + condref = *(++ptr) - '0'; /* grumble at autoincrement in declaration */ + while (*(++ptr) != ')') condref = condref*10 + *ptr - '0'; + if (condref == 0) + { + *errorptr = ERR35; + goto FAILED; + } + ptr++; + code[1+LINK_SIZE] = OP_CREF; + PUT2(code, 2+LINK_SIZE, condref); + skipbytes = 3; + } + /* For conditions that are assertions, we just fall through, having + set bravalue above. */ + break; + + case '=': /* Positive lookahead */ + bravalue = OP_ASSERT; + ptr++; + break; + + case '!': /* Negative lookahead */ + bravalue = OP_ASSERT_NOT; + ptr++; + break; + + case '<': /* Lookbehinds */ + switch (*(++ptr)) + { + case '=': /* Positive lookbehind */ + bravalue = OP_ASSERTBACK; + ptr++; + break; + + case '!': /* Negative lookbehind */ + bravalue = OP_ASSERTBACK_NOT; + ptr++; + break; + } + break; + + case '>': /* One-time brackets */ + bravalue = OP_ONCE; + ptr++; + break; + + case 'C': /* Callout - may be followed by digits */ + *code++ = OP_CALLOUT; + { + int n = 0; + while ((digitab[*(++ptr)] & ctype_digit) != 0) + n = n * 10 + *ptr - '0'; + if (n > 255) + { + *errorptr = ERR38; + goto FAILED; + } + *code++ = n; + } + previous = NULL; + continue; + + case 'P': /* Named subpattern handling */ + if (*(++ptr) == '<') /* Definition */ + { + int i, namelen; + uschar *slot = cd->name_table; + const uschar *name; /* Don't amalgamate; some compilers */ + name = ++ptr; /* grumble at autoincrement in declaration */ + + while (*ptr++ != '>'); + namelen = ptr - name - 1; + + for (i = 0; i < cd->names_found; i++) + { + int crc = memcmp(name, slot+2, namelen); + if (crc == 0) + { + if (slot[2+namelen] == 0) + { + *errorptr = ERR43; + goto FAILED; + } + crc = -1; /* Current name is substring */ + } + if (crc < 0) + { + memmove(slot + cd->name_entry_size, slot, + (cd->names_found - i) * cd->name_entry_size); + break; + } + slot += cd->name_entry_size; + } + + PUT2(slot, 0, *brackets + 1); + memcpy(slot + 2, name, namelen); + slot[2+namelen] = 0; + cd->names_found++; + goto NUMBERED_GROUP; + } + + if (*ptr == '=' || *ptr == '>') /* Reference or recursion */ + { + int i, namelen; + int type = *ptr++; + const uschar *name = ptr; + uschar *slot = cd->name_table; + + while (*ptr != ')') ptr++; + namelen = ptr - name; + + for (i = 0; i < cd->names_found; i++) + { + if (strncmp((char *)name, (char *)slot+2, namelen) == 0) break; + slot += cd->name_entry_size; + } + if (i >= cd->names_found) + { + *errorptr = ERR15; + goto FAILED; + } + + recno = GET2(slot, 0); + + if (type == '>') goto HANDLE_RECURSION; /* A few lines below */ + + /* Back reference */ + + previous = code; + *code++ = OP_REF; + PUT2INC(code, 0, recno); + cd->backref_map |= (recno < 32)? (1 << recno) : 1; + if (recno > cd->top_backref) cd->top_backref = recno; + continue; + } + + /* Should never happen */ + break; + + case 'R': /* Pattern recursion */ + ptr++; /* Same as (?0) */ + /* Fall through */ + + /* Recursion or "subroutine" call */ + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + { + const uschar *called; + recno = 0; + while((digitab[*ptr] & ctype_digit) != 0) + recno = recno * 10 + *ptr++ - '0'; + + /* Come here from code above that handles a named recursion */ + + HANDLE_RECURSION: + + previous = code; + + /* Find the bracket that is being referenced. Temporarily end the + regex in case it doesn't exist. */ + + *code = OP_END; + called = (recno == 0)? + cd->start_code : find_bracket(cd->start_code, utf8, recno); + + if (called == NULL) + { + *errorptr = ERR15; + goto FAILED; + } + + /* If the subpattern is still open, this is a recursive call. We + check to see if this is a left recursion that could loop for ever, + and diagnose that case. */ + + if (GET(called, 1) == 0 && could_be_empty(called, code, bcptr, utf8)) + { + *errorptr = ERR40; + goto FAILED; + } + + /* Insert the recursion/subroutine item */ + + *code = OP_RECURSE; + PUT(code, 1, called - cd->start_code); + code += 1 + LINK_SIZE; + } + continue; + + /* Character after (? not specially recognized */ + + default: /* Option setting */ + set = unset = 0; + optset = &set; + + while (*ptr != ')' && *ptr != ':') + { + switch (*ptr++) + { + case '-': optset = &unset; break; + + case 'i': *optset |= PCRE_CASELESS; break; + case 'm': *optset |= PCRE_MULTILINE; break; + case 's': *optset |= PCRE_DOTALL; break; + case 'x': *optset |= PCRE_EXTENDED; break; + case 'U': *optset |= PCRE_UNGREEDY; break; + case 'X': *optset |= PCRE_EXTRA; break; + } + } + + /* Set up the changed option bits, but don't change anything yet. */ + + newoptions = (options | set) & (~unset); + + /* If the options ended with ')' this is not the start of a nested + group with option changes, so the options change at this level. Compile + code to change the ims options if this setting actually changes any of + them. We also pass the new setting back so that it can be put at the + start of any following branches, and when this group ends (if we are in + a group), a resetting item can be compiled. + + Note that if this item is right at the start of the pattern, the + options will have been abstracted and made global, so there will be no + change to compile. */ + + if (*ptr == ')') + { + if ((options & PCRE_IMS) != (newoptions & PCRE_IMS)) + { + *code++ = OP_OPT; + *code++ = newoptions & PCRE_IMS; + } + + /* Change options at this level, and pass them back for use + in subsequent branches. Reset the greedy defaults and the case + value for firstbyte and reqbyte. */ + + *optionsptr = options = newoptions; + greedy_default = ((newoptions & PCRE_UNGREEDY) != 0); + greedy_non_default = greedy_default ^ 1; + req_caseopt = ((options & PCRE_CASELESS) != 0)? REQ_CASELESS : 0; + + previous = NULL; /* This item can't be repeated */ + continue; /* It is complete */ + } + + /* If the options ended with ':' we are heading into a nested group + with possible change of options. Such groups are non-capturing and are + not assertions of any kind. All we need to do is skip over the ':'; + the newoptions value is handled below. */ + + bravalue = OP_BRA; + ptr++; + } + } + + /* If PCRE_NO_AUTO_CAPTURE is set, all unadorned brackets become + non-capturing and behave like (?:...) brackets */ + + else if ((options & PCRE_NO_AUTO_CAPTURE) != 0) + { + bravalue = OP_BRA; + } + + /* Else we have a referencing group; adjust the opcode. If the bracket + number is greater than EXTRACT_BASIC_MAX, we set the opcode one higher, and + arrange for the true number to follow later, in an OP_BRANUMBER item. */ + + else + { + NUMBERED_GROUP: + if (++(*brackets) > EXTRACT_BASIC_MAX) + { + bravalue = OP_BRA + EXTRACT_BASIC_MAX + 1; + code[1+LINK_SIZE] = OP_BRANUMBER; + PUT2(code, 2+LINK_SIZE, *brackets); + skipbytes = 3; + } + else bravalue = OP_BRA + *brackets; + } + + /* Process nested bracketed re. Assertions may not be repeated, but other + kinds can be. We copy code into a non-register variable in order to be able + to pass its address because some compilers complain otherwise. Pass in a + new setting for the ims options if they have changed. */ + + previous = (bravalue >= OP_ONCE)? code : NULL; + *code = bravalue; + tempcode = code; + tempreqvary = cd->req_varyopt; /* Save value before bracket */ + + if (!compile_regex( + newoptions, /* The complete new option state */ + options & PCRE_IMS, /* The previous ims option state */ + brackets, /* Extracting bracket count */ + &tempcode, /* Where to put code (updated) */ + &ptr, /* Input pointer (updated) */ + errorptr, /* Where to put an error message */ + (bravalue == OP_ASSERTBACK || + bravalue == OP_ASSERTBACK_NOT), /* TRUE if back assert */ + skipbytes, /* Skip over OP_COND/OP_BRANUMBER */ + &subfirstbyte, /* For possible first char */ + &subreqbyte, /* For possible last char */ + bcptr, /* Current branch chain */ + cd)) /* Tables block */ + goto FAILED; + + /* At the end of compiling, code is still pointing to the start of the + group, while tempcode has been updated to point past the end of the group + and any option resetting that may follow it. The pattern pointer (ptr) + is on the bracket. */ + + /* If this is a conditional bracket, check that there are no more than + two branches in the group. */ + + else if (bravalue == OP_COND) + { + uschar *tc = code; + condcount = 0; + + do { + condcount++; + tc += GET(tc,1); + } + while (*tc != OP_KET); + + if (condcount > 2) + { + *errorptr = ERR27; + goto FAILED; + } + + /* If there is just one branch, we must not make use of its firstbyte or + reqbyte, because this is equivalent to an empty second branch. */ + + if (condcount == 1) subfirstbyte = subreqbyte = REQ_NONE; + } + + /* Handle updating of the required and first characters. Update for normal + brackets of all kinds, and conditions with two branches (see code above). + If the bracket is followed by a quantifier with zero repeat, we have to + back off. Hence the definition of zeroreqbyte and zerofirstbyte outside the + main loop so that they can be accessed for the back off. */ + + zeroreqbyte = reqbyte; + zerofirstbyte = firstbyte; + groupsetfirstbyte = FALSE; + + if (bravalue >= OP_BRA || bravalue == OP_ONCE || bravalue == OP_COND) + { + /* If we have not yet set a firstbyte in this branch, take it from the + subpattern, remembering that it was set here so that a repeat of more + than one can replicate it as reqbyte if necessary. If the subpattern has + no firstbyte, set "none" for the whole branch. In both cases, a zero + repeat forces firstbyte to "none". */ + + if (firstbyte == REQ_UNSET) + { + if (subfirstbyte >= 0) + { + firstbyte = subfirstbyte; + groupsetfirstbyte = TRUE; + } + else firstbyte = REQ_NONE; + zerofirstbyte = REQ_NONE; + } + + /* If firstbyte was previously set, convert the subpattern's firstbyte + into reqbyte if there wasn't one, using the vary flag that was in + existence beforehand. */ + + else if (subfirstbyte >= 0 && subreqbyte < 0) + subreqbyte = subfirstbyte | tempreqvary; + + /* If the subpattern set a required byte (or set a first byte that isn't + really the first byte - see above), set it. */ + + if (subreqbyte >= 0) reqbyte = subreqbyte; + } + + /* For a forward assertion, we take the reqbyte, if set. This can be + helpful if the pattern that follows the assertion doesn't set a different + char. For example, it's useful for /(?=abcde).+/. We can't set firstbyte + for an assertion, however because it leads to incorrect effect for patterns + such as /(?=a)a.+/ when the "real" "a" would then become a reqbyte instead + of a firstbyte. This is overcome by a scan at the end if there's no + firstbyte, looking for an asserted first char. */ + + else if (bravalue == OP_ASSERT && subreqbyte >= 0) reqbyte = subreqbyte; + + /* Now update the main code pointer to the end of the group. */ + + code = tempcode; + + /* Error if hit end of pattern */ + + if (*ptr != ')') + { + *errorptr = ERR14; + goto FAILED; + } + break; + + /* Check \ for being a real metacharacter; if not, fall through and handle + it as a data character at the start of a string. Escape items are checked + for validity in the pre-compiling pass. */ + + case '\\': + tempptr = ptr; + c = check_escape(&ptr, errorptr, *brackets, options, FALSE, cd); + + /* Handle metacharacters introduced by \. For ones like \d, the ESC_ values + are arranged to be the negation of the corresponding OP_values. For the + back references, the values are ESC_REF plus the reference number. Only + back references and those types that consume a character may be repeated. + We can test for values between ESC_b and ESC_Z for the latter; this may + have to change if any new ones are ever created. */ + + if (c < 0) + { + if (-c == ESC_Q) /* Handle start of quoted string */ + { + if (ptr[1] == '\\' && ptr[2] == 'E') ptr += 2; /* avoid empty string */ + else inescq = TRUE; + continue; + } + + /* For metasequences that actually match a character, we disable the + setting of a first character if it hasn't already been set. */ + + if (firstbyte == REQ_UNSET && -c > ESC_b && -c < ESC_Z) + firstbyte = REQ_NONE; + + /* Set values to reset to if this is followed by a zero repeat. */ + + zerofirstbyte = firstbyte; + zeroreqbyte = reqbyte; + + /* Back references are handled specially */ + + if (-c >= ESC_REF) + { + int number = -c - ESC_REF; + previous = code; + *code++ = OP_REF; + PUT2INC(code, 0, number); + } + else + { + previous = (-c > ESC_b && -c < ESC_Z)? code : NULL; + *code++ = -c; + } + continue; + } + + /* Data character: reset and fall through */ + + ptr = tempptr; + c = '\\'; + + /* Handle a run of data characters until a metacharacter is encountered. + The first character is guaranteed not to be whitespace or # when the + extended flag is set. */ + + NORMAL_CHAR: + default: + previous = code; + *code = OP_CHARS; + code += 2; + length = 0; + + do + { + /* If in \Q...\E, check for the end; if not, we always have a literal */ + + if (inescq) + { + if (c == '\\' && ptr[1] == 'E') + { + inescq = FALSE; + ptr++; + } + else + { + *code++ = c; + length++; + } + continue; + } + + /* Skip white space and comments for /x patterns */ + + if ((options & PCRE_EXTENDED) != 0) + { + if ((cd->ctypes[c] & ctype_space) != 0) continue; + if (c == '#') + { + /* The space before the ; is to avoid a warning on a silly compiler + on the Macintosh. */ + while ((c = *(++ptr)) != 0 && c != NEWLINE) ; + if (c == 0) break; + continue; + } + } + + /* Backslash may introduce a data char or a metacharacter. Escaped items + are checked for validity in the pre-compiling pass. Stop the string + before a metaitem. */ + + if (c == '\\') + { + tempptr = ptr; + c = check_escape(&ptr, errorptr, *brackets, options, FALSE, cd); + if (c < 0) { ptr = tempptr; break; } + + /* If a character is > 127 in UTF-8 mode, we have to turn it into + two or more characters in the UTF-8 encoding. */ + +#ifdef SUPPORT_UTF8 + if (utf8 && c > 127) + { + uschar buffer[8]; + int len = ord2utf8(c, buffer); + for (c = 0; c < len; c++) *code++ = buffer[c]; + length += len; + continue; + } +#endif + } + + /* Ordinary character or single-char escape */ + + *code++ = c; + length++; + } + + /* This "while" is the end of the "do" above. */ + + while (length < MAXLIT && (cd->ctypes[c = *(++ptr)] & ctype_meta) == 0); + + /* Update the first and last requirements. These are always bytes, even in + UTF-8 mode. However, there is a special case to be considered when there + are only one or two characters. Because this gets messy in UTF-8 mode, the + code is kept separate. When we get here "length" contains the number of + bytes. */ + +#ifdef SUPPORT_UTF8 + if (utf8 && length > 1) + { + uschar *t = previous + 3; /* After this code, t */ + while (t < code && (*t & 0xc0) == 0x80) t++; /* follows the 1st char */ + + /* Handle the case when there is only one multibyte character. It must + have at least two bytes because of the "length > 1" test above. */ + + if (t == code) + { + /* If no previous first byte, set it from this character, but revert to + none on a zero repeat. */ + + if (firstbyte == REQ_UNSET) + { + zerofirstbyte = REQ_NONE; + firstbyte = previous[2]; + } + + /* Otherwise, leave the first byte value alone, and don't change it on + a zero repeat */ + + else zerofirstbyte = firstbyte; + + /* In both cases, a zero repeat resets the previous required byte */ + + zeroreqbyte = reqbyte; + } + + /* Handle the case when there is more than one character. These may be + single-byte or multibyte characters */ + + else + { + t = code - 1; /* After this code, t is at the */ + while ((*t & 0xc0) == 0x80) t--; /* start of the last character */ + + /* If no previous first byte, set it from the first character, and + retain it on a zero repeat (of the last character). The required byte + is reset on a zero repeat, either to the byte before the last + character, unless this is the first byte of the string. In that case, + it reverts to its previous value. */ + + if (firstbyte == REQ_UNSET) + { + zerofirstbyte = firstbyte = previous[2] | req_caseopt; + zeroreqbyte = (t - 1 == previous + 2)? + reqbyte : t[-1] | req_caseopt | cd->req_varyopt; + } + + /* If there was a previous first byte, leave it alone, and don't change + it on a zero repeat. The required byte is reset on a zero repeat to the + byte before the last character. */ + + else + { + zerofirstbyte = firstbyte; + zeroreqbyte = t[-1] | req_caseopt | cd->req_varyopt; + } + } + + /* In all cases (we know length > 1), the new required byte is the last + byte of the string. */ + + reqbyte = code[-1] | req_caseopt | cd->req_varyopt; + } + + else /* End of UTF-8 coding */ +#endif + + /* This is the code for non-UTF-8 operation, either without UTF-8 support, + or when UTF-8 is not enabled. */ + + { + /* firstbyte was not previously set; take it from this string */ + + if (firstbyte == REQ_UNSET) + { + if (length == 1) + { + zerofirstbyte = REQ_NONE; + firstbyte = previous[2] | req_caseopt; + zeroreqbyte = reqbyte; + } + else + { + zerofirstbyte = firstbyte = previous[2] | req_caseopt; + zeroreqbyte = (length > 2)? + (code[-2] | req_caseopt | cd->req_varyopt) : reqbyte; + reqbyte = code[-1] | req_caseopt | cd->req_varyopt; + } + } + + /* firstbyte was previously set */ + + else + { + zerofirstbyte = firstbyte; + zeroreqbyte = (length == 1)? reqbyte : + code[-2] | req_caseopt | cd->req_varyopt; + reqbyte = code[-1] | req_caseopt | cd->req_varyopt; + } + } + + /* Set the length in the data vector, and advance to the next state. */ + + previous[1] = length; + if (length < MAXLIT) ptr--; + break; + } + } /* end of big loop */ + +/* Control never reaches here by falling through, only by a goto for all the +error states. Pass back the position in the pattern so that it can be displayed +to the user for diagnosing the error. */ + +FAILED: +*ptrptr = ptr; +return FALSE; +} + + + + +/************************************************* +* Compile sequence of alternatives * +*************************************************/ + +/* On entry, ptr is pointing past the bracket character, but on return +it points to the closing bracket, or vertical bar, or end of string. +The code variable is pointing at the byte into which the BRA operator has been +stored. If the ims options are changed at the start (for a (?ims: group) or +during any branch, we need to insert an OP_OPT item at the start of every +following branch to ensure they get set correctly at run time, and also pass +the new options into every subsequent branch compile. + +Argument: + options option bits, including any changes for this subpattern + oldims previous settings of ims option bits + brackets -> int containing the number of extracting brackets used + codeptr -> the address of the current code pointer + ptrptr -> the address of the current pattern pointer + errorptr -> pointer to error message + lookbehind TRUE if this is a lookbehind assertion + skipbytes skip this many bytes at start (for OP_COND, OP_BRANUMBER) + firstbyteptr place to put the first required character, or a negative number + reqbyteptr place to put the last required character, or a negative number + bcptr pointer to the chain of currently open branches + cd points to the data block with tables pointers etc. + +Returns: TRUE on success +*/ + +static BOOL +compile_regex(int options, int oldims, int *brackets, uschar **codeptr, + const uschar **ptrptr, const char **errorptr, BOOL lookbehind, int skipbytes, + int *firstbyteptr, int *reqbyteptr, branch_chain *bcptr, compile_data *cd) +{ +const uschar *ptr = *ptrptr; +uschar *code = *codeptr; +uschar *last_branch = code; +uschar *start_bracket = code; +uschar *reverse_count = NULL; +int firstbyte, reqbyte; +int branchfirstbyte, branchreqbyte; +branch_chain bc; + +bc.outer = bcptr; +bc.current = code; + +firstbyte = reqbyte = REQ_UNSET; + +/* Offset is set zero to mark that this bracket is still open */ + +PUT(code, 1, 0); +code += 1 + LINK_SIZE + skipbytes; + +/* Loop for each alternative branch */ + +for (;;) + { + /* Handle a change of ims options at the start of the branch */ + + if ((options & PCRE_IMS) != oldims) + { + *code++ = OP_OPT; + *code++ = options & PCRE_IMS; + } + + /* Set up dummy OP_REVERSE if lookbehind assertion */ + + if (lookbehind) + { + *code++ = OP_REVERSE; + reverse_count = code; + PUTINC(code, 0, 0); + } + + /* Now compile the branch */ + + if (!compile_branch(&options, brackets, &code, &ptr, errorptr, + &branchfirstbyte, &branchreqbyte, &bc, cd)) + { + *ptrptr = ptr; + return FALSE; + } + + /* If this is the first branch, the firstbyte and reqbyte values for the + branch become the values for the regex. */ + + if (*last_branch != OP_ALT) + { + firstbyte = branchfirstbyte; + reqbyte = branchreqbyte; + } + + /* If this is not the first branch, the first char and reqbyte have to + match the values from all the previous branches, except that if the previous + value for reqbyte didn't have REQ_VARY set, it can still match, and we set + REQ_VARY for the regex. */ + + else + { + /* If we previously had a firstbyte, but it doesn't match the new branch, + we have to abandon the firstbyte for the regex, but if there was previously + no reqbyte, it takes on the value of the old firstbyte. */ + + if (firstbyte >= 0 && firstbyte != branchfirstbyte) + { + if (reqbyte < 0) reqbyte = firstbyte; + firstbyte = REQ_NONE; + } + + /* If we (now or from before) have no firstbyte, a firstbyte from the + branch becomes a reqbyte if there isn't a branch reqbyte. */ + + if (firstbyte < 0 && branchfirstbyte >= 0 && branchreqbyte < 0) + branchreqbyte = branchfirstbyte; + + /* Now ensure that the reqbytes match */ + + if ((reqbyte & ~REQ_VARY) != (branchreqbyte & ~REQ_VARY)) + reqbyte = REQ_NONE; + else reqbyte |= branchreqbyte; /* To "or" REQ_VARY */ + } + + /* If lookbehind, check that this branch matches a fixed-length string, + and put the length into the OP_REVERSE item. Temporarily mark the end of + the branch with OP_END. */ + + if (lookbehind) + { + int length; + *code = OP_END; + length = find_fixedlength(last_branch, options); + DPRINTF(("fixed length = %d\n", length)); + if (length < 0) + { + *errorptr = (length == -2)? ERR36 : ERR25; + *ptrptr = ptr; + return FALSE; + } + PUT(reverse_count, 0, length); + } + + /* Reached end of expression, either ')' or end of pattern. Go back through + the alternative branches and reverse the chain of offsets, with the field in + the BRA item now becoming an offset to the first alternative. If there are + no alternatives, it points to the end of the group. The length in the + terminating ket is always the length of the whole bracketed item. If any of + the ims options were changed inside the group, compile a resetting op-code + following, except at the very end of the pattern. Return leaving the pointer + at the terminating char. */ + + if (*ptr != '|') + { + int length = code - last_branch; + do + { + int prev_length = GET(last_branch, 1); + PUT(last_branch, 1, length); + length = prev_length; + last_branch -= length; + } + while (length > 0); + + /* Fill in the ket */ + + *code = OP_KET; + PUT(code, 1, code - start_bracket); + code += 1 + LINK_SIZE; + + /* Resetting option if needed */ + + if ((options & PCRE_IMS) != oldims && *ptr == ')') + { + *code++ = OP_OPT; + *code++ = oldims; + } + + /* Set values to pass back */ + + *codeptr = code; + *ptrptr = ptr; + *firstbyteptr = firstbyte; + *reqbyteptr = reqbyte; + return TRUE; + } + + /* Another branch follows; insert an "or" node. Its length field points back + to the previous branch while the bracket remains open. At the end the chain + is reversed. It's done like this so that the start of the bracket has a + zero offset until it is closed, making it possible to detect recursion. */ + + *code = OP_ALT; + PUT(code, 1, code - last_branch); + bc.current = last_branch = code; + code += 1 + LINK_SIZE; + ptr++; + } +/* Control never reaches here */ +} + + + + +/************************************************* +* Check for anchored expression * +*************************************************/ + +/* Try to find out if this is an anchored regular expression. Consider each +alternative branch. If they all start with OP_SOD or OP_CIRC, or with a bracket +all of whose alternatives start with OP_SOD or OP_CIRC (recurse ad lib), then +it's anchored. However, if this is a multiline pattern, then only OP_SOD +counts, since OP_CIRC can match in the middle. + +We can also consider a regex to be anchored if OP_SOM starts all its branches. +This is the code for \G, which means "match at start of match position, taking +into account the match offset". + +A branch is also implicitly anchored if it starts with .* and DOTALL is set, +because that will try the rest of the pattern at all possible matching points, +so there is no point trying again.... er .... + +.... except when the .* appears inside capturing parentheses, and there is a +subsequent back reference to those parentheses. We haven't enough information +to catch that case precisely. + +At first, the best we could do was to detect when .* was in capturing brackets +and the highest back reference was greater than or equal to that level. +However, by keeping a bitmap of the first 31 back references, we can catch some +of the more common cases more precisely. + +Arguments: + code points to start of expression (the bracket) + options points to the options setting + bracket_map a bitmap of which brackets we are inside while testing; this + handles up to substring 31; after that we just have to take + the less precise approach + backref_map the back reference bitmap + +Returns: TRUE or FALSE +*/ + +static BOOL +is_anchored(register const uschar *code, int *options, unsigned int bracket_map, + unsigned int backref_map) +{ +do { + const uschar *scode = + first_significant_code(code + 1+LINK_SIZE, options, PCRE_MULTILINE); + register int op = *scode; + + /* Capturing brackets */ + + if (op > OP_BRA) + { + int new_map; + op -= OP_BRA; + if (op > EXTRACT_BASIC_MAX) op = GET2(scode, 2+LINK_SIZE); + new_map = bracket_map | ((op < 32)? (1 << op) : 1); + if (!is_anchored(scode, options, new_map, backref_map)) return FALSE; + } + + /* Other brackets */ + + else if (op == OP_BRA || op == OP_ASSERT || op == OP_ONCE || op == OP_COND) + { + if (!is_anchored(scode, options, bracket_map, backref_map)) return FALSE; + } + + /* .* is not anchored unless DOTALL is set and it isn't in brackets that + are or may be referenced. */ + + else if ((op == OP_TYPESTAR || op == OP_TYPEMINSTAR) && + (*options & PCRE_DOTALL) != 0) + { + if (scode[1] != OP_ANY || (bracket_map & backref_map) != 0) return FALSE; + } + + /* Check for explicit anchoring */ + + else if (op != OP_SOD && op != OP_SOM && + ((*options & PCRE_MULTILINE) != 0 || op != OP_CIRC)) + return FALSE; + code += GET(code, 1); + } +while (*code == OP_ALT); /* Loop for each alternative */ +return TRUE; +} + + + +/************************************************* +* Check for starting with ^ or .* * +*************************************************/ + +/* This is called to find out if every branch starts with ^ or .* so that +"first char" processing can be done to speed things up in multiline +matching and for non-DOTALL patterns that start with .* (which must start at +the beginning or after \n). As in the case of is_anchored() (see above), we +have to take account of back references to capturing brackets that contain .* +because in that case we can't make the assumption. + +Arguments: + code points to start of expression (the bracket) + bracket_map a bitmap of which brackets we are inside while testing; this + handles up to substring 31; after that we just have to take + the less precise approach + backref_map the back reference bitmap + +Returns: TRUE or FALSE +*/ + +static BOOL +is_startline(const uschar *code, unsigned int bracket_map, + unsigned int backref_map) +{ +do { + const uschar *scode = first_significant_code(code + 1+LINK_SIZE, NULL, 0); + register int op = *scode; + + /* Capturing brackets */ + + if (op > OP_BRA) + { + int new_map; + op -= OP_BRA; + if (op > EXTRACT_BASIC_MAX) op = GET2(scode, 2+LINK_SIZE); + new_map = bracket_map | ((op < 32)? (1 << op) : 1); + if (!is_startline(scode, new_map, backref_map)) return FALSE; + } + + /* Other brackets */ + + else if (op == OP_BRA || op == OP_ASSERT || op == OP_ONCE || op == OP_COND) + { if (!is_startline(scode, bracket_map, backref_map)) return FALSE; } + + /* .* is not anchored unless DOTALL is set and it isn't in brackets that + may be referenced. */ + + else if (op == OP_TYPESTAR || op == OP_TYPEMINSTAR) + { + if (scode[1] != OP_ANY || (bracket_map & backref_map) != 0) return FALSE; + } + + /* Check for explicit circumflex */ + + else if (op != OP_CIRC) return FALSE; + code += GET(code, 1); + } +while (*code == OP_ALT); /* Loop for each alternative */ +return TRUE; +} + + + +/************************************************* +* Check for asserted fixed first char * +*************************************************/ + +/* During compilation, the "first char" settings from forward assertions are +discarded, because they can cause conflicts with actual literals that follow. +However, if we end up without a first char setting for an unanchored pattern, +it is worth scanning the regex to see if there is an initial asserted first +char. If all branches start with the same asserted char, or with a bracket all +of whose alternatives start with the same asserted char (recurse ad lib), then +we return that char, otherwise -1. + +Arguments: + code points to start of expression (the bracket) + options pointer to the options (used to check casing changes) + inassert TRUE if in an assertion + +Returns: -1 or the fixed first char +*/ + +static int +find_firstassertedchar(const uschar *code, int *options, BOOL inassert) +{ +register int c = -1; +do { + int d; + const uschar *scode = + first_significant_code(code + 1+LINK_SIZE, options, PCRE_CASELESS); + register int op = *scode; + + if (op >= OP_BRA) op = OP_BRA; + + switch(op) + { + default: + return -1; + + case OP_BRA: + case OP_ASSERT: + case OP_ONCE: + case OP_COND: + if ((d = find_firstassertedchar(scode, options, op == OP_ASSERT)) < 0) + return -1; + if (c < 0) c = d; else if (c != d) return -1; + break; + + case OP_EXACT: /* Fall through */ + scode++; + + case OP_CHARS: /* Fall through */ + scode++; + + case OP_PLUS: + case OP_MINPLUS: + if (!inassert) return -1; + if (c < 0) + { + c = scode[1]; + if ((*options & PCRE_CASELESS) != 0) c |= REQ_CASELESS; + } + else if (c != scode[1]) return -1; + break; + } + + code += GET(code, 1); + } +while (*code == OP_ALT); +return c; +} + + + + +/************************************************* +* Compile a Regular Expression * +*************************************************/ + +/* This function takes a string and returns a pointer to a block of store +holding a compiled version of the expression. + +Arguments: + pattern the regular expression + options various option bits + errorptr pointer to pointer to error text + erroroffset ptr offset in pattern where error was detected + tables pointer to character tables or NULL + +Returns: pointer to compiled data block, or NULL on error, + with errorptr and erroroffset set +*/ + +pcre * +pcre_compile(const char *pattern, int options, const char **errorptr, + int *erroroffset, const unsigned char *tables) +{ +real_pcre *re; +int length = 1 + LINK_SIZE; /* For initial BRA plus length */ +int runlength; +int c, firstbyte, reqbyte; +int bracount = 0; +int branch_extra = 0; +int branch_newextra; +int item_count = -1; +int name_count = 0; +int max_name_size = 0; +#ifdef SUPPORT_UTF8 +int lastcharlength = 0; +BOOL utf8; +BOOL class_utf8; +#endif +BOOL inescq = FALSE; +unsigned int brastackptr = 0; +size_t size; +uschar *code; +const uschar *codestart; +const uschar *ptr; +compile_data compile_block; +int brastack[BRASTACK_SIZE]; +uschar bralenstack[BRASTACK_SIZE]; + +/* We can't pass back an error message if errorptr is NULL; I guess the best we +can do is just return NULL. */ + +if (errorptr == NULL) return NULL; +*errorptr = NULL; + +/* However, we can give a message for this error */ + +if (erroroffset == NULL) + { + *errorptr = ERR16; + return NULL; + } +*erroroffset = 0; + +/* Can't support UTF8 unless PCRE has been compiled to include the code. */ + +#ifdef SUPPORT_UTF8 +utf8 = (options & PCRE_UTF8) != 0; +#else +if ((options & PCRE_UTF8) != 0) + { + *errorptr = ERR32; + return NULL; + } +#endif + +if ((options & ~PUBLIC_OPTIONS) != 0) + { + *errorptr = ERR17; + return NULL; + } + +/* Set up pointers to the individual character tables */ + +if (tables == NULL) tables = pcre_default_tables; +compile_block.lcc = tables + lcc_offset; +compile_block.fcc = tables + fcc_offset; +compile_block.cbits = tables + cbits_offset; +compile_block.ctypes = tables + ctypes_offset; + +/* Maximum back reference and backref bitmap. This is updated for numeric +references during the first pass, but for named references during the actual +compile pass. The bitmap records up to 31 back references to help in deciding +whether (.*) can be treated as anchored or not. */ + +compile_block.top_backref = 0; +compile_block.backref_map = 0; + +/* Reflect pattern for debugging output */ + +DPRINTF(("------------------------------------------------------------------\n")); +DPRINTF(("%s\n", pattern)); + +/* The first thing to do is to make a pass over the pattern to compute the +amount of store required to hold the compiled code. This does not have to be +perfect as long as errors are overestimates. At the same time we can detect any +flag settings right at the start, and extract them. Make an attempt to correct +for any counted white space if an "extended" flag setting appears late in the +pattern. We can't be so clever for #-comments. */ + +ptr = (const uschar *)(pattern - 1); +while ((c = *(++ptr)) != 0) + { + int min, max; + int class_optcount; + int bracket_length; + int duplength; + + /* If we are inside a \Q...\E sequence, all chars are literal */ + + if (inescq) goto NORMAL_CHAR; + + /* Otherwise, first check for ignored whitespace and comments */ + + if ((options & PCRE_EXTENDED) != 0) + { + if ((compile_block.ctypes[c] & ctype_space) != 0) continue; + if (c == '#') + { + /* The space before the ; is to avoid a warning on a silly compiler + on the Macintosh. */ + while ((c = *(++ptr)) != 0 && c != NEWLINE) ; + if (c == 0) break; + continue; + } + } + + item_count++; /* Is zero for the first non-comment item */ + + switch(c) + { + /* A backslashed item may be an escaped "normal" character or a + character type. For a "normal" character, put the pointers and + character back so that tests for whitespace etc. in the input + are done correctly. */ + + case '\\': + { + const uschar *save_ptr = ptr; + c = check_escape(&ptr, errorptr, bracount, options, FALSE, &compile_block); + if (*errorptr != NULL) goto PCRE_ERROR_RETURN; + if (c >= 0) + { + ptr = save_ptr; + c = '\\'; + goto NORMAL_CHAR; + } + } + + /* If \Q, enter "literal" mode */ + + if (-c == ESC_Q) + { + inescq = TRUE; + continue; + } + + /* Other escapes need one byte, and are of length one for repeats */ + + length++; +#ifdef SUPPORT_UTF8 + lastcharlength = 1; +#endif + + /* A back reference needs an additional 2 bytes, plus either one or 5 + bytes for a repeat. We also need to keep the value of the highest + back reference. */ + + if (c <= -ESC_REF) + { + int refnum = -c - ESC_REF; + compile_block.backref_map |= (refnum < 32)? (1 << refnum) : 1; + if (refnum > compile_block.top_backref) + compile_block.top_backref = refnum; + length += 2; /* For single back reference */ + if (ptr[1] == '{' && is_counted_repeat(ptr+2, &compile_block)) + { + ptr = read_repeat_counts(ptr+2, &min, &max, errorptr, &compile_block); + if (*errorptr != NULL) goto PCRE_ERROR_RETURN; + if ((min == 0 && (max == 1 || max == -1)) || + (min == 1 && max == -1)) + length++; + else length += 5; + if (ptr[1] == '?') ptr++; + } + } + continue; + + case '^': /* Single-byte metacharacters */ + case '.': + case '$': + length++; +#ifdef SUPPORT_UTF8 + lastcharlength = 1; +#endif + continue; + + case '*': /* These repeats won't be after brackets; */ + case '+': /* those are handled separately */ + case '?': + length++; + goto POSESSIVE; /* A few lines below */ + + /* This covers the cases of braced repeats after a single char, metachar, + class, or back reference. */ + + case '{': + if (!is_counted_repeat(ptr+1, &compile_block)) goto NORMAL_CHAR; + ptr = read_repeat_counts(ptr+1, &min, &max, errorptr, &compile_block); + if (*errorptr != NULL) goto PCRE_ERROR_RETURN; + + /* These special cases just insert one extra opcode */ + + if ((min == 0 && (max == 1 || max == -1)) || + (min == 1 && max == -1)) + length++; + + /* These cases might insert additional copies of a preceding character. */ + + else + { +#ifdef SUPPORT_UTF8 + /* In UTF-8 mode, we should find the length in lastcharlength */ + if (utf8) + { + if (min != 1) + { + length -= lastcharlength; /* Uncount the original char or metachar */ + if (min > 0) length += 3 + lastcharlength; + } + length += lastcharlength + ((max > 0)? 3 : 1); + } + else +#endif + + /* Not UTF-8 mode: all characters are one byte */ + { + if (min != 1) + { + length--; /* Uncount the original char or metachar */ + if (min > 0) length += 4; + } + + length += (max > 0)? 4 : 2; + } + } + + if (ptr[1] == '?') ptr++; /* Needs no extra length */ + + POSESSIVE: /* Test for possessive quantifier */ + if (ptr[1] == '+') + { + ptr++; + length += 2 + 2*LINK_SIZE; /* Allow for atomic brackets */ + } + continue; + + /* An alternation contains an offset to the next branch or ket. If any ims + options changed in the previous branch(es), and/or if we are in a + lookbehind assertion, extra space will be needed at the start of the + branch. This is handled by branch_extra. */ + + case '|': + length += 1 + LINK_SIZE + branch_extra; + continue; + + /* A character class uses 33 characters provided that all the character + values are less than 256. Otherwise, it uses a bit map for low valued + characters, and individual items for others. Don't worry about character + types that aren't allowed in classes - they'll get picked up during the + compile. A character class that contains only one single-byte character + uses 2 or 3 bytes, depending on whether it is negated or not. Notice this + where we can. (In UTF-8 mode we can do this only for chars < 128.) */ + + case '[': + class_optcount = 0; + +#ifdef SUPPORT_UTF8 + class_utf8 = FALSE; +#endif + + if (*(++ptr) == '^') ptr++; + + /* Written as a "do" so that an initial ']' is taken as data */ + + if (*ptr != 0) do + { + /* Inside \Q...\E everything is literal except \E */ + + if (inescq) + { + if (*ptr != '\\' || ptr[1] != 'E') goto NON_SPECIAL_CHARACTER; + inescq = FALSE; + ptr += 1; + continue; + } + + /* Outside \Q...\E, check for escapes */ + + if (*ptr == '\\') + { +#ifdef SUPPORT_UTF8 + int prevchar = ptr[-1]; +#endif + int ch = check_escape(&ptr, errorptr, bracount, options, TRUE, + &compile_block); + if (*errorptr != NULL) goto PCRE_ERROR_RETURN; + + /* \b is backspace inside a class */ + + if (-ch == ESC_b) ch = '\b'; + + /* \Q enters quoting mode */ + + if (-ch == ESC_Q) + { + inescq = TRUE; + continue; + } + + /* Handle escapes that turn into characters */ + + if (ch >= 0) + { +#ifdef SUPPORT_UTF8 + if (utf8) + { + if (ch > 127) class_optcount = 10; /* Ensure > 1 */ + if (ch > 255) + { + uschar buffer[6]; + if (!class_utf8) + { + class_utf8 = TRUE; + length += LINK_SIZE + 1 + 1; + } + length += 1 + ord2utf8(ch, buffer); + + /* If this wide character is preceded by '-', add an extra 2 to + the length in case the previous character was < 128, because in + this case the whole range will be put into the list. */ + + if (prevchar == '-') length += 2; + } + } +#endif + class_optcount++; /* for possible optimization */ + } + else class_optcount = 10; /* \d, \s etc; make sure > 1 */ + } + + /* Check the syntax for POSIX stuff. The bits we actually handle are + checked during the real compile phase. */ + + else if (*ptr == '[' && check_posix_syntax(ptr, &ptr, &compile_block)) + { + ptr++; + class_optcount = 10; /* Make sure > 1 */ + } + + /* Anything else just increments the possible optimization count. If + there are wide characters, we are going to have to use an XCLASS. */ + + else + { + NON_SPECIAL_CHARACTER: + class_optcount++; + +#ifdef SUPPORT_UTF8 + if (utf8) + { + int ch; + int extra = 0; + GETCHARLEN(ch, ptr, extra); + if (ch > 127) class_optcount = 10; /* No optimization possible */ + if (ch > 255) + { + if (!class_utf8) + { + class_utf8 = TRUE; + length += LINK_SIZE + 1 + 1; + } + length += 2 + extra; + + /* If this wide character is preceded by '-', add an extra 2 to + the length in case the previous character was < 128, because in + this case the whole range will be put into the list. */ + + if (ptr[-1] == '-') length += 2; + + /* Advance to the end of this character */ + + ptr += extra; + } + } +#endif + } + } + while (*(++ptr) != 0 && (inescq || *ptr != ']')); /* Concludes "do" above */ + + if (*ptr == 0) /* Missing terminating ']' */ + { + *errorptr = ERR6; + goto PCRE_ERROR_RETURN; + } + + /* We can optimize when there was only one optimizable character. Repeats + for positive and negated single one-byte chars are handled by the general + code. Here, we handle repeats for the class opcodes. */ + + if (class_optcount == 1) length += 3; else + { + length += 33; + + /* A repeat needs either 1 or 5 bytes. */ + + if (*ptr != 0 && ptr[1] == '{' && is_counted_repeat(ptr+2, &compile_block)) + { + ptr = read_repeat_counts(ptr+2, &min, &max, errorptr, &compile_block); + if (*errorptr != NULL) goto PCRE_ERROR_RETURN; + if ((min == 0 && (max == 1 || max == -1)) || + (min == 1 && max == -1)) + length++; + else length += 5; + if (ptr[1] == '?') ptr++; + } + } + continue; + + /* Brackets may be genuine groups or special things */ + + case '(': + branch_newextra = 0; + bracket_length = 1 + LINK_SIZE; + + /* Handle special forms of bracket, which all start (? */ + + if (ptr[1] == '?') + { + int set, unset; + int *optset; + + switch (c = ptr[2]) + { + /* Skip over comments entirely */ + case '#': + ptr += 3; + while (*ptr != 0 && *ptr != ')') ptr++; + if (*ptr == 0) + { + *errorptr = ERR18; + goto PCRE_ERROR_RETURN; + } + continue; + + /* Non-referencing groups and lookaheads just move the pointer on, and + then behave like a non-special bracket, except that they don't increment + the count of extracting brackets. Ditto for the "once only" bracket, + which is in Perl from version 5.005. */ + + case ':': + case '=': + case '!': + case '>': + ptr += 2; + break; + + /* (?R) specifies a recursive call to the regex, which is an extension + to provide the facility which can be obtained by (?p{perl-code}) in + Perl 5.6. In Perl 5.8 this has become (??{perl-code}). + + From PCRE 4.00, items such as (?3) specify subroutine-like "calls" to + the appropriate numbered brackets. This includes both recursive and + non-recursive calls. (?R) is now synonymous with (?0). */ + + case 'R': + ptr++; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + ptr += 2; + if (c != 'R') + while ((digitab[*(++ptr)] & ctype_digit) != 0); + if (*ptr != ')') + { + *errorptr = ERR29; + goto PCRE_ERROR_RETURN; + } + length += 1 + LINK_SIZE; + + /* If this item is quantified, it will get wrapped inside brackets so + as to use the code for quantified brackets. We jump down and use the + code that handles this for real brackets. */ + + if (ptr[1] == '+' || ptr[1] == '*' || ptr[1] == '?' || ptr[1] == '{') + { + length += 2 + 2 * LINK_SIZE; /* to make bracketed */ + duplength = 5 + 3 * LINK_SIZE; + goto HANDLE_QUANTIFIED_BRACKETS; + } + continue; + + /* (?C) is an extension which provides "callout" - to provide a bit of + the functionality of the Perl (?{...}) feature. An optional number may + follow (default is zero). */ + + case 'C': + ptr += 2; + while ((digitab[*(++ptr)] & ctype_digit) != 0); + if (*ptr != ')') + { + *errorptr = ERR39; + goto PCRE_ERROR_RETURN; + } + length += 2; + continue; + + /* Named subpatterns are an extension copied from Python */ + + case 'P': + ptr += 3; + if (*ptr == '<') + { + const uschar *p; /* Don't amalgamate; some compilers */ + p = ++ptr; /* grumble at autoincrement in declaration */ + while ((compile_block.ctypes[*ptr] & ctype_word) != 0) ptr++; + if (*ptr != '>') + { + *errorptr = ERR42; + goto PCRE_ERROR_RETURN; + } + name_count++; + if (ptr - p > max_name_size) max_name_size = (ptr - p); + break; + } + + if (*ptr == '=' || *ptr == '>') + { + while ((compile_block.ctypes[*(++ptr)] & ctype_word) != 0); + if (*ptr != ')') + { + *errorptr = ERR42; + goto PCRE_ERROR_RETURN; + } + break; + } + + /* Unknown character after (?P */ + + *errorptr = ERR41; + goto PCRE_ERROR_RETURN; + + /* Lookbehinds are in Perl from version 5.005 */ + + case '<': + ptr += 3; + if (*ptr == '=' || *ptr == '!') + { + branch_newextra = 1 + LINK_SIZE; + length += 1 + LINK_SIZE; /* For the first branch */ + break; + } + *errorptr = ERR24; + goto PCRE_ERROR_RETURN; + + /* Conditionals are in Perl from version 5.005. The bracket must either + be followed by a number (for bracket reference) or by an assertion + group, or (a PCRE extension) by 'R' for a recursion test. */ + + case '(': + if (ptr[3] == 'R' && ptr[4] == ')') + { + ptr += 4; + length += 3; + } + else if ((digitab[ptr[3]] & ctype_digit) != 0) + { + ptr += 4; + length += 3; + while ((digitab[*ptr] & ctype_digit) != 0) ptr++; + if (*ptr != ')') + { + *errorptr = ERR26; + goto PCRE_ERROR_RETURN; + } + } + else /* An assertion must follow */ + { + ptr++; /* Can treat like ':' as far as spacing is concerned */ + if (ptr[2] != '?' || + (ptr[3] != '=' && ptr[3] != '!' && ptr[3] != '<') ) + { + ptr += 2; /* To get right offset in message */ + *errorptr = ERR28; + goto PCRE_ERROR_RETURN; + } + } + break; + + /* Else loop checking valid options until ) is met. Anything else is an + error. If we are without any brackets, i.e. at top level, the settings + act as if specified in the options, so massage the options immediately. + This is for backward compatibility with Perl 5.004. */ + + default: + set = unset = 0; + optset = &set; + ptr += 2; + + for (;; ptr++) + { + c = *ptr; + switch (c) + { + case 'i': + *optset |= PCRE_CASELESS; + continue; + + case 'm': + *optset |= PCRE_MULTILINE; + continue; + + case 's': + *optset |= PCRE_DOTALL; + continue; + + case 'x': + *optset |= PCRE_EXTENDED; + continue; + + case 'X': + *optset |= PCRE_EXTRA; + continue; + + case 'U': + *optset |= PCRE_UNGREEDY; + continue; + + case '-': + optset = &unset; + continue; + + /* A termination by ')' indicates an options-setting-only item; if + this is at the very start of the pattern (indicated by item_count + being zero), we use it to set the global options. This is helpful + when analyzing the pattern for first characters, etc. Otherwise + nothing is done here and it is handled during the compiling + process. + + [Historical note: Up to Perl 5.8, options settings at top level + were always global settings, wherever they appeared in the pattern. + That is, they were equivalent to an external setting. From 5.8 + onwards, they apply only to what follows (which is what you might + expect).] */ + + case ')': + if (item_count == 0) + { + options = (options | set) & (~unset); + set = unset = 0; /* To save length */ + item_count--; /* To allow for several */ + } + + /* Fall through */ + + /* A termination by ':' indicates the start of a nested group with + the given options set. This is again handled at compile time, but + we must allow for compiled space if any of the ims options are + set. We also have to allow for resetting space at the end of + the group, which is why 4 is added to the length and not just 2. + If there are several changes of options within the same group, this + will lead to an over-estimate on the length, but this shouldn't + matter very much. We also have to allow for resetting options at + the start of any alternations, which we do by setting + branch_newextra to 2. Finally, we record whether the case-dependent + flag ever changes within the regex. This is used by the "required + character" code. */ + + case ':': + if (((set|unset) & PCRE_IMS) != 0) + { + length += 4; + branch_newextra = 2; + if (((set|unset) & PCRE_CASELESS) != 0) options |= PCRE_ICHANGED; + } + goto END_OPTIONS; + + /* Unrecognized option character */ + + default: + *errorptr = ERR12; + goto PCRE_ERROR_RETURN; + } + } + + /* If we hit a closing bracket, that's it - this is a freestanding + option-setting. We need to ensure that branch_extra is updated if + necessary. The only values branch_newextra can have here are 0 or 2. + If the value is 2, then branch_extra must either be 2 or 5, depending + on whether this is a lookbehind group or not. */ + + END_OPTIONS: + if (c == ')') + { + if (branch_newextra == 2 && + (branch_extra == 0 || branch_extra == 1+LINK_SIZE)) + branch_extra += branch_newextra; + continue; + } + + /* If options were terminated by ':' control comes here. Fall through + to handle the group below. */ + } + } + + /* Extracting brackets must be counted so we can process escapes in a + Perlish way. If the number exceeds EXTRACT_BASIC_MAX we are going to + need an additional 3 bytes of store per extracting bracket. However, if + PCRE_NO_AUTO)CAPTURE is set, unadorned brackets become non-capturing, so we + must leave the count alone (it will aways be zero). */ + + else if ((options & PCRE_NO_AUTO_CAPTURE) == 0) + { + bracount++; + if (bracount > EXTRACT_BASIC_MAX) bracket_length += 3; + } + + /* Save length for computing whole length at end if there's a repeat that + requires duplication of the group. Also save the current value of + branch_extra, and start the new group with the new value. If non-zero, this + will either be 2 for a (?imsx: group, or 3 for a lookbehind assertion. */ + + if (brastackptr >= sizeof(brastack)/sizeof(int)) + { + *errorptr = ERR19; + goto PCRE_ERROR_RETURN; + } + + bralenstack[brastackptr] = branch_extra; + branch_extra = branch_newextra; + + brastack[brastackptr++] = length; + length += bracket_length; + continue; + + /* Handle ket. Look for subsequent max/min; for certain sets of values we + have to replicate this bracket up to that many times. If brastackptr is + 0 this is an unmatched bracket which will generate an error, but take care + not to try to access brastack[-1] when computing the length and restoring + the branch_extra value. */ + + case ')': + length += 1 + LINK_SIZE; + if (brastackptr > 0) + { + duplength = length - brastack[--brastackptr]; + branch_extra = bralenstack[brastackptr]; + } + else duplength = 0; + + /* The following code is also used when a recursion such as (?3) is + followed by a quantifier, because in that case, it has to be wrapped inside + brackets so that the quantifier works. The value of duplength must be + set before arrival. */ + + HANDLE_QUANTIFIED_BRACKETS: + + /* Leave ptr at the final char; for read_repeat_counts this happens + automatically; for the others we need an increment. */ + + if ((c = ptr[1]) == '{' && is_counted_repeat(ptr+2, &compile_block)) + { + ptr = read_repeat_counts(ptr+2, &min, &max, errorptr, &compile_block); + if (*errorptr != NULL) goto PCRE_ERROR_RETURN; + } + else if (c == '*') { min = 0; max = -1; ptr++; } + else if (c == '+') { min = 1; max = -1; ptr++; } + else if (c == '?') { min = 0; max = 1; ptr++; } + else { min = 1; max = 1; } + + /* If the minimum is zero, we have to allow for an OP_BRAZERO before the + group, and if the maximum is greater than zero, we have to replicate + maxval-1 times; each replication acquires an OP_BRAZERO plus a nesting + bracket set. */ + + if (min == 0) + { + length++; + if (max > 0) length += (max - 1) * (duplength + 3 + 2*LINK_SIZE); + } + + /* When the minimum is greater than zero, we have to replicate up to + minval-1 times, with no additions required in the copies. Then, if there + is a limited maximum we have to replicate up to maxval-1 times allowing + for a BRAZERO item before each optional copy and nesting brackets for all + but one of the optional copies. */ + + else + { + length += (min - 1) * duplength; + if (max > min) /* Need this test as max=-1 means no limit */ + length += (max - min) * (duplength + 3 + 2*LINK_SIZE) + - (2 + 2*LINK_SIZE); + } + + /* Allow space for once brackets for "possessive quantifier" */ + + if (ptr[1] == '+') + { + ptr++; + length += 2 + 2*LINK_SIZE; + } + continue; + + /* Non-special character. For a run of such characters the length required + is the number of characters + 2, except that the maximum run length is + MAXLIT. We won't get a skipped space or a non-data escape or the start of a + # comment as the first character, so the length can't be zero. */ + + NORMAL_CHAR: + default: + length += 2; + runlength = 0; + do + { +#ifdef SUPPORT_UTF8 + lastcharlength = 1; /* Need length of last char for UTF-8 repeats */ +#endif + + /* If in a \Q...\E sequence, check for end; otherwise it's a literal */ + if (inescq) + { + if (c == '\\' && ptr[1] == 'E') + { + inescq = FALSE; + ptr++; + } + else runlength++; + continue; + } + + /* Skip whitespace and comments for /x */ + + if ((options & PCRE_EXTENDED) != 0) + { + if ((compile_block.ctypes[c] & ctype_space) != 0) continue; + if (c == '#') + { + /* The space before the ; is to avoid a warning on a silly compiler + on the Macintosh. */ + while ((c = *(++ptr)) != 0 && c != NEWLINE) ; + continue; + } + } + + /* Backslash may introduce a data char or a metacharacter; stop the + string before the latter. */ + + if (c == '\\') + { + const uschar *saveptr = ptr; + c = check_escape(&ptr, errorptr, bracount, options, FALSE, + &compile_block); + if (*errorptr != NULL) goto PCRE_ERROR_RETURN; + if (c < 0) { ptr = saveptr; break; } + + /* In UTF-8 mode, add on the number of additional bytes needed to + encode this character, and save the total length in case this is a + final char that is repeated. */ + +#ifdef SUPPORT_UTF8 + if (utf8 && c > 127) + { + int i; + for (i = 0; i < sizeof(utf8_table1)/sizeof(int); i++) + if (c <= utf8_table1[i]) break; + runlength += i; + lastcharlength += i; + } +#endif + } + + /* Ordinary character or single-char escape */ + + runlength++; + } + + /* This "while" is the end of the "do" above. */ + + while (runlength < MAXLIT && + (compile_block.ctypes[c = *(++ptr)] & ctype_meta) == 0); + + /* If we hit a meta-character, back off to point to it */ + + if (runlength < MAXLIT) ptr--; + + /* If the last char in the string is a UTF-8 multibyte character, we must + set lastcharlength correctly. If it was specified as an escape, this will + already have been done above. However, we also have to support in-line + UTF-8 characters, so check backwards from where we are. */ + +#ifdef SUPPORT_UTF8 + if (utf8) + { + const uschar *lastptr = ptr - 1; + if ((*lastptr & 0x80) != 0) + { + while((*lastptr & 0xc0) == 0x80) lastptr--; + lastcharlength = ptr - lastptr; + } + } +#endif + + length += runlength; + continue; + } + } + +length += 2 + LINK_SIZE; /* For final KET and END */ + +if (length > MAX_PATTERN_SIZE) + { + *errorptr = ERR20; + return NULL; + } + +/* Compute the size of data block needed and get it, either from malloc or +externally provided function. */ + +size = length + sizeof(real_pcre) + name_count * (max_name_size + 3); +re = (real_pcre *)(pcre_malloc)(size); + +if (re == NULL) + { + *errorptr = ERR21; + return NULL; + } + +/* Put in the magic number, and save the size, options, and table pointer */ + +re->magic_number = MAGIC_NUMBER; +re->size = size; +re->options = options; +re->tables = tables; +re->name_entry_size = max_name_size + 3; +re->name_count = name_count; + +/* The starting points of the name/number translation table and of the code are +passed around in the compile data block. */ + +compile_block.names_found = 0; +compile_block.name_entry_size = max_name_size + 3; +compile_block.name_table = (uschar *)re + sizeof(real_pcre); +codestart = compile_block.name_table + re->name_entry_size * re->name_count; +compile_block.start_code = codestart; +compile_block.req_varyopt = 0; + +/* Set up a starting, non-extracting bracket, then compile the expression. On +error, *errorptr will be set non-NULL, so we don't need to look at the result +of the function here. */ + +ptr = (const uschar *)pattern; +code = (uschar *)codestart; +*code = OP_BRA; +bracount = 0; +(void)compile_regex(options, options & PCRE_IMS, &bracount, &code, &ptr, + errorptr, FALSE, 0, &firstbyte, &reqbyte, NULL, &compile_block); +re->top_bracket = bracount; +re->top_backref = compile_block.top_backref; + +/* If not reached end of pattern on success, there's an excess bracket. */ + +if (*errorptr == NULL && *ptr != 0) *errorptr = ERR22; + +/* Fill in the terminating state and check for disastrous overflow, but +if debugging, leave the test till after things are printed out. */ + +*code++ = OP_END; + +#ifndef DEBUG +if (code - codestart > length) *errorptr = ERR23; +#endif + +/* Give an error if there's back reference to a non-existent capturing +subpattern. */ + +if (re->top_backref > re->top_bracket) *errorptr = ERR15; + +/* Failed to compile, or error while post-processing */ + +if (*errorptr != NULL) + { + (pcre_free)(re); + PCRE_ERROR_RETURN: + *erroroffset = ptr - (const uschar *)pattern; + return NULL; + } + +/* If the anchored option was not passed, set the flag if we can determine that +the pattern is anchored by virtue of ^ characters or \A or anything else (such +as starting with .* when DOTALL is set). + +Otherwise, if we know what the first character has to be, save it, because that +speeds up unanchored matches no end. If not, see if we can set the +PCRE_STARTLINE flag. This is helpful for multiline matches when all branches +start with ^. and also when all branches start with .* for non-DOTALL matches. +*/ + +if ((options & PCRE_ANCHORED) == 0) + { + int temp_options = options; + if (is_anchored(codestart, &temp_options, 0, compile_block.backref_map)) + re->options |= PCRE_ANCHORED; + else + { + if (firstbyte < 0) + firstbyte = find_firstassertedchar(codestart, &temp_options, FALSE); + if (firstbyte >= 0) /* Remove caseless flag for non-caseable chars */ + { + int ch = firstbyte & 255; + re->first_byte = ((firstbyte & REQ_CASELESS) != 0 && + compile_block.fcc[ch] == ch)? ch : firstbyte; + re->options |= PCRE_FIRSTSET; + } + else if (is_startline(codestart, 0, compile_block.backref_map)) + re->options |= PCRE_STARTLINE; + } + } + +/* For an anchored pattern, we use the "required byte" only if it follows a +variable length item in the regex. Remove the caseless flag for non-caseable +chars. */ + +if (reqbyte >= 0 && + ((re->options & PCRE_ANCHORED) == 0 || (reqbyte & REQ_VARY) != 0)) + { + int ch = reqbyte & 255; + re->req_byte = ((reqbyte & REQ_CASELESS) != 0 && + compile_block.fcc[ch] == ch)? (reqbyte & ~REQ_CASELESS) : reqbyte; + re->options |= PCRE_REQCHSET; + } + +/* Print out the compiled data for debugging */ + +#ifdef DEBUG + +printf("Length = %d top_bracket = %d top_backref = %d\n", + length, re->top_bracket, re->top_backref); + +if (re->options != 0) + { + printf("%s%s%s%s%s%s%s%s%s\n", + ((re->options & PCRE_ANCHORED) != 0)? "anchored " : "", + ((re->options & PCRE_CASELESS) != 0)? "caseless " : "", + ((re->options & PCRE_ICHANGED) != 0)? "case state changed " : "", + ((re->options & PCRE_EXTENDED) != 0)? "extended " : "", + ((re->options & PCRE_MULTILINE) != 0)? "multiline " : "", + ((re->options & PCRE_DOTALL) != 0)? "dotall " : "", + ((re->options & PCRE_DOLLAR_ENDONLY) != 0)? "endonly " : "", + ((re->options & PCRE_EXTRA) != 0)? "extra " : "", + ((re->options & PCRE_UNGREEDY) != 0)? "ungreedy " : ""); + } + +if ((re->options & PCRE_FIRSTSET) != 0) + { + int ch = re->first_byte & 255; + char *caseless = ((re->first_byte & REQ_CASELESS) == 0)? "" : " (caseless)"; + if (isprint(ch)) printf("First char = %c%s\n", ch, caseless); + else printf("First char = \\x%02x%s\n", ch, caseless); + } + +if ((re->options & PCRE_REQCHSET) != 0) + { + int ch = re->req_byte & 255; + char *caseless = ((re->req_byte & REQ_CASELESS) == 0)? "" : " (caseless)"; + if (isprint(ch)) printf("Req char = %c%s\n", ch, caseless); + else printf("Req char = \\x%02x%s\n", ch, caseless); + } + +print_internals(re, stdout); + +/* This check is done here in the debugging case so that the code that +was compiled can be seen. */ + +if (code - codestart > length) + { + *errorptr = ERR23; + (pcre_free)(re); + *erroroffset = ptr - (uschar *)pattern; + return NULL; + } +#endif + +return (pcre *)re; +} + + + +/************************************************* +* Match a back-reference * +*************************************************/ + +/* If a back reference hasn't been set, the length that is passed is greater +than the number of characters left in the string, so the match fails. + +Arguments: + offset index into the offset vector + eptr points into the subject + length length to be matched + md points to match data block + ims the ims flags + +Returns: TRUE if matched +*/ + +static BOOL +match_ref(int offset, register const uschar *eptr, int length, match_data *md, + unsigned long int ims) +{ +const uschar *p = md->start_subject + md->offset_vector[offset]; + +#ifdef DEBUG +if (eptr >= md->end_subject) + printf("matching subject "); +else + { + printf("matching subject "); + pchars(eptr, length, TRUE, md); + } +printf(" against backref "); +pchars(p, length, FALSE, md); +printf("\n"); +#endif + +/* Always fail if not enough characters left */ + +if (length > md->end_subject - eptr) return FALSE; + +/* Separate the caselesss case for speed */ + +if ((ims & PCRE_CASELESS) != 0) + { + while (length-- > 0) + if (md->lcc[*p++] != md->lcc[*eptr++]) return FALSE; + } +else + { while (length-- > 0) if (*p++ != *eptr++) return FALSE; } + +return TRUE; +} + + +#ifdef SUPPORT_UTF8 +/************************************************* +* Match character against an XCLASS * +*************************************************/ + +/* This function is called from within the XCLASS code below, to match a +character against an extended class which might match values > 255. + +Arguments: + c the character + data points to the flag byte of the XCLASS data + +Returns: TRUE if character matches, else FALSE +*/ + +static BOOL +match_xclass(int c, const uschar *data) +{ +int t; +BOOL negated = (*data & XCL_NOT) != 0; + +/* Character values < 256 are matched against a bitmap, if one is present. If +not, we still carry on, because there may be ranges that start below 256 in the +additional data. */ + +if (c < 256) + { + if ((*data & XCL_MAP) != 0 && (data[1 + c/8] & (1 << (c&7))) != 0) + return !negated; /* char found */ + } + +/* Now match against the list of large chars or ranges that end with a large +char. First skip the bit map if present. */ + +if ((*data++ & XCL_MAP) != 0) data += 32; + +while ((t = *data++) != XCL_END) + { + int x, y; + GETCHARINC(x, data); + if (t == XCL_SINGLE) + { + if (c == x) return !negated; + } + else + { + GETCHARINC(y, data); + if (c >= x && c <= y) return !negated; + } + } + +return negated; /* char was not found */ +} +#endif + + + + +/************************************************* +* Match from current position * +*************************************************/ + +/* On entry ecode points to the first opcode, and eptr to the first character +in the subject string, while eptrb holds the value of eptr at the start of the +last bracketed group - used for breaking infinite loops matching zero-length +strings. This function is called recursively in many circumstances. Whenever it +returns a negative (error) response, the outer incarnation must also return the +same response. + +Performance note: It might be tempting to extract commonly used fields from the +md structure (e.g. utf8, end_subject) into individual variables to improve +performance. Tests using gcc on a SPARC disproved this; in the first case, it +made performance worse. + +Arguments: + eptr pointer in subject + ecode position in code + offset_top current top pointer + md pointer to "static" info for the match + ims current /i, /m, and /s options + eptrb pointer to chain of blocks containing eptr at start of + brackets - for testing for empty matches + flags can contain + match_condassert - this is an assertion condition + match_isgroup - this is the start of a bracketed group + +Returns: MATCH_MATCH if matched ) these values are >= 0 + MATCH_NOMATCH if failed to match ) + a negative PCRE_ERROR_xxx value if aborted by an error condition + (e.g. stopped by recursion limit) +*/ + +static int +match(register const uschar *eptr, register const uschar *ecode, + int offset_top, match_data *md, unsigned long int ims, eptrblock *eptrb, + int flags) +{ +unsigned long int original_ims = ims; /* Save for resetting on ')' */ +register int rrc; +eptrblock newptrb; + +if (md->match_call_count++ >= md->match_limit) return PCRE_ERROR_MATCHLIMIT; + +/* At the start of a bracketed group, add the current subject pointer to the +stack of such pointers, to be re-instated at the end of the group when we hit +the closing ket. When match() is called in other circumstances, we don't add to +the stack. */ + +if ((flags & match_isgroup) != 0) + { + newptrb.prev = eptrb; + newptrb.saved_eptr = eptr; + eptrb = &newptrb; + } + +/* Now start processing the operations. */ + +for (;;) + { + int op = (int)*ecode; + int min, max, ctype; + register int i; + register int c; + BOOL minimize = FALSE; + + /* Opening capturing bracket. If there is space in the offset vector, save + the current subject position in the working slot at the top of the vector. We + mustn't change the current values of the data slot, because they may be set + from a previous iteration of this group, and be referred to by a reference + inside the group. + + If the bracket fails to match, we need to restore this value and also the + values of the final offsets, in case they were set by a previous iteration of + the same bracket. + + If there isn't enough space in the offset vector, treat this as if it were a + non-capturing bracket. Don't worry about setting the flag for the error case + here; that is handled in the code for KET. */ + + if (op > OP_BRA) + { + int offset; + int number = op - OP_BRA; + + /* For extended extraction brackets (large number), we have to fish out the + number from a dummy opcode at the start. */ + + if (number > EXTRACT_BASIC_MAX) + number = GET2(ecode, 2+LINK_SIZE); + offset = number << 1; + +#ifdef DEBUG + printf("start bracket %d subject=", number); + pchars(eptr, 16, TRUE, md); + printf("\n"); +#endif + + if (offset < md->offset_max) + { + int save_offset1 = md->offset_vector[offset]; + int save_offset2 = md->offset_vector[offset+1]; + int save_offset3 = md->offset_vector[md->offset_end - number]; + int save_capture_last = md->capture_last; + + DPRINTF(("saving %d %d %d\n", save_offset1, save_offset2, save_offset3)); + md->offset_vector[md->offset_end - number] = eptr - md->start_subject; + + do + { + if ((rrc = match(eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, + eptrb, match_isgroup)) != MATCH_NOMATCH) return rrc; + md->capture_last = save_capture_last; + ecode += GET(ecode, 1); + } + while (*ecode == OP_ALT); + + DPRINTF(("bracket %d failed\n", number)); + + md->offset_vector[offset] = save_offset1; + md->offset_vector[offset+1] = save_offset2; + md->offset_vector[md->offset_end - number] = save_offset3; + + return MATCH_NOMATCH; + } + + /* Insufficient room for saving captured contents */ + + else op = OP_BRA; + } + + /* Other types of node can be handled by a switch */ + + switch(op) + { + case OP_BRA: /* Non-capturing bracket: optimized */ + DPRINTF(("start bracket 0\n")); + do + { + if ((rrc = match(eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, eptrb, + match_isgroup)) != MATCH_NOMATCH) return rrc; + ecode += GET(ecode, 1); + } + while (*ecode == OP_ALT); + DPRINTF(("bracket 0 failed\n")); + return MATCH_NOMATCH; + + /* Conditional group: compilation checked that there are no more than + two branches. If the condition is false, skipping the first branch takes us + past the end if there is only one branch, but that's OK because that is + exactly what going to the ket would do. */ + + case OP_COND: + if (ecode[LINK_SIZE+1] == OP_CREF) /* Condition extract or recurse test */ + { + int offset = GET2(ecode, LINK_SIZE+2) << 1; /* Doubled ref number */ + BOOL condition = (offset == CREF_RECURSE * 2)? + (md->recursive != NULL) : + (offset < offset_top && md->offset_vector[offset] >= 0); + return match(eptr, ecode + (condition? + (LINK_SIZE + 4) : (LINK_SIZE + 1 + GET(ecode, 1))), + offset_top, md, ims, eptrb, match_isgroup); + } + + /* The condition is an assertion. Call match() to evaluate it - setting + the final argument TRUE causes it to stop at the end of an assertion. */ + + else + { + if ((rrc = match(eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, NULL, + match_condassert | match_isgroup)) == MATCH_MATCH) + { + ecode += 1 + LINK_SIZE + GET(ecode, LINK_SIZE+2); + while (*ecode == OP_ALT) ecode += GET(ecode, 1); + } + else if (rrc != MATCH_NOMATCH) return rrc; + else ecode += GET(ecode, 1); + return match(eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, eptrb, + match_isgroup); + } + /* Control never reaches here */ + + /* Skip over conditional reference or large extraction number data if + encountered. */ + + case OP_CREF: + case OP_BRANUMBER: + ecode += 3; + break; + + /* End of the pattern. If we are in a recursion, we should restore the + offsets appropriately and continue from after the call. */ + + case OP_END: + if (md->recursive != NULL && md->recursive->group_num == 0) + { + recursion_info *rec = md->recursive; + DPRINTF(("Hit the end in a (?0) recursion\n")); + md->recursive = rec->prev; + memmove(md->offset_vector, rec->offset_save, + rec->saved_max * sizeof(int)); + md->start_match = rec->save_start; + ims = original_ims; + ecode = rec->after_call; + break; + } + + /* Otherwise, if PCRE_NOTEMPTY is set, fail if we have matched an empty + string - backtracking will then try other alternatives, if any. */ + + if (md->notempty && eptr == md->start_match) return MATCH_NOMATCH; + md->end_match_ptr = eptr; /* Record where we ended */ + md->end_offset_top = offset_top; /* and how many extracts were taken */ + return MATCH_MATCH; + + /* Change option settings */ + + case OP_OPT: + ims = ecode[1]; + ecode += 2; + DPRINTF(("ims set to %02lx\n", ims)); + break; + + /* Assertion brackets. Check the alternative branches in turn - the + matching won't pass the KET for an assertion. If any one branch matches, + the assertion is true. Lookbehind assertions have an OP_REVERSE item at the + start of each branch to move the current point backwards, so the code at + this level is identical to the lookahead case. */ + + case OP_ASSERT: + case OP_ASSERTBACK: + do + { + if ((rrc = match(eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, NULL, + match_isgroup)) == MATCH_MATCH) break; + if (rrc != MATCH_NOMATCH) return rrc; + ecode += GET(ecode, 1); + } + while (*ecode == OP_ALT); + if (*ecode == OP_KET) return MATCH_NOMATCH; + + /* If checking an assertion for a condition, return MATCH_MATCH. */ + + if ((flags & match_condassert) != 0) return MATCH_MATCH; + + /* Continue from after the assertion, updating the offsets high water + mark, since extracts may have been taken during the assertion. */ + + do ecode += GET(ecode,1); while (*ecode == OP_ALT); + ecode += 1 + LINK_SIZE; + offset_top = md->end_offset_top; + continue; + + /* Negative assertion: all branches must fail to match */ + + case OP_ASSERT_NOT: + case OP_ASSERTBACK_NOT: + do + { + if ((rrc = match(eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, NULL, + match_isgroup)) == MATCH_MATCH) return MATCH_NOMATCH; + if (rrc != MATCH_NOMATCH) return rrc; + ecode += GET(ecode,1); + } + while (*ecode == OP_ALT); + + if ((flags & match_condassert) != 0) return MATCH_MATCH; + + ecode += 1 + LINK_SIZE; + continue; + + /* Move the subject pointer back. This occurs only at the start of + each branch of a lookbehind assertion. If we are too close to the start to + move back, this match function fails. When working with UTF-8 we move + back a number of characters, not bytes. */ + + case OP_REVERSE: +#ifdef SUPPORT_UTF8 + if (md->utf8) + { + c = GET(ecode,1); + for (i = 0; i < c; i++) + { + eptr--; + if (eptr < md->start_subject) return MATCH_NOMATCH; + BACKCHAR(eptr) + } + } + else +#endif + + /* No UTF-8 support, or not in UTF-8 mode: count is byte count */ + + { + eptr -= GET(ecode,1); + if (eptr < md->start_subject) return MATCH_NOMATCH; + } + + /* Skip to next op code */ + + ecode += 1 + LINK_SIZE; + break; + + /* The callout item calls an external function, if one is provided, passing + details of the match so far. This is mainly for debugging, though the + function is able to force a failure. */ + + case OP_CALLOUT: + if (pcre_callout != NULL) + { + pcre_callout_block cb; + cb.version = 0; /* Version 0 of the callout block */ + cb.callout_number = ecode[1]; + cb.offset_vector = md->offset_vector; + cb.subject = (const char *)md->start_subject; + cb.subject_length = md->end_subject - md->start_subject; + cb.start_match = md->start_match - md->start_subject; + cb.current_position = eptr - md->start_subject; + cb.capture_top = offset_top/2; + cb.capture_last = md->capture_last; + cb.callout_data = md->callout_data; + if ((rrc = (*pcre_callout)(&cb)) > 0) return MATCH_NOMATCH; + if (rrc < 0) return rrc; + } + ecode += 2; + break; + + /* Recursion either matches the current regex, or some subexpression. The + offset data is the offset to the starting bracket from the start of the + whole pattern. However, it is possible that a BRAZERO was inserted before + this bracket after we took the offset - we just skip it if encountered. + + If there are any capturing brackets started but not finished, we have to + save their starting points and reinstate them after the recursion. However, + we don't know how many such there are (offset_top records the completed + total) so we just have to save all the potential data. There may be up to + 65535 such values, which is too large to put on the stack, but using malloc + for small numbers seems expensive. As a compromise, the stack is used when + there are no more than REC_STACK_SAVE_MAX values to store; otherwise malloc + is used. A problem is what to do if the malloc fails ... there is no way of + returning to the top level with an error. Save the top REC_STACK_SAVE_MAX + values on the stack, and accept that the rest may be wrong. + + There are also other values that have to be saved. We use a chained + sequence of blocks that actually live on the stack. Thanks to Robin Houston + for the original version of this logic. */ + + case OP_RECURSE: + { + int stacksave[REC_STACK_SAVE_MAX]; + recursion_info new_recursive; + const uschar *callpat = md->start_code + GET(ecode, 1); + + if (*callpat == OP_BRAZERO) callpat++; + + new_recursive.group_num = *callpat - OP_BRA; + + /* For extended extraction brackets (large number), we have to fish out + the number from a dummy opcode at the start. */ + + if (new_recursive.group_num > EXTRACT_BASIC_MAX) + new_recursive.group_num = GET2(callpat, 2+LINK_SIZE); + + /* Add to "recursing stack" */ + + new_recursive.prev = md->recursive; + md->recursive = &new_recursive; + + /* Find where to continue from afterwards */ + + ecode += 1 + LINK_SIZE; + new_recursive.after_call = ecode; + + /* Now save the offset data. */ + + new_recursive.saved_max = md->offset_end; + if (new_recursive.saved_max <= REC_STACK_SAVE_MAX) + new_recursive.offset_save = stacksave; + else + { + new_recursive.offset_save = + (int *)(pcre_malloc)(new_recursive.saved_max * sizeof(int)); + if (new_recursive.offset_save == NULL) return PCRE_ERROR_NOMEMORY; + } + + memcpy(new_recursive.offset_save, md->offset_vector, + new_recursive.saved_max * sizeof(int)); + new_recursive.save_start = md->start_match; + md->start_match = eptr; + + /* OK, now we can do the recursion. For each top-level alternative we + restore the offset and recursion data. */ + + DPRINTF(("Recursing into group %d\n", new_recursive.group_num)); + do + { + if ((rrc = match(eptr, callpat + 1 + LINK_SIZE, offset_top, md, ims, + eptrb, match_isgroup)) == MATCH_MATCH) + { + md->recursive = new_recursive.prev; + if (new_recursive.offset_save != stacksave) + (pcre_free)(new_recursive.offset_save); + return MATCH_MATCH; + } + else if (rrc != MATCH_NOMATCH) return rrc; + + md->recursive = &new_recursive; + memcpy(md->offset_vector, new_recursive.offset_save, + new_recursive.saved_max * sizeof(int)); + callpat += GET(callpat, 1); + } + while (*callpat == OP_ALT); + + DPRINTF(("Recursion didn't match\n")); + md->recursive = new_recursive.prev; + if (new_recursive.offset_save != stacksave) + (pcre_free)(new_recursive.offset_save); + return MATCH_NOMATCH; + } + /* Control never reaches here */ + + /* "Once" brackets are like assertion brackets except that after a match, + the point in the subject string is not moved back. Thus there can never be + a move back into the brackets. Friedl calls these "atomic" subpatterns. + Check the alternative branches in turn - the matching won't pass the KET + for this kind of subpattern. If any one branch matches, we carry on as at + the end of a normal bracket, leaving the subject pointer. */ + + case OP_ONCE: + { + const uschar *prev = ecode; + const uschar *saved_eptr = eptr; + + do + { + if ((rrc = match(eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, + eptrb, match_isgroup)) == MATCH_MATCH) break; + if (rrc != MATCH_NOMATCH) return rrc; + ecode += GET(ecode,1); + } + while (*ecode == OP_ALT); + + /* If hit the end of the group (which could be repeated), fail */ + + if (*ecode != OP_ONCE && *ecode != OP_ALT) return MATCH_NOMATCH; + + /* Continue as from after the assertion, updating the offsets high water + mark, since extracts may have been taken. */ + + do ecode += GET(ecode,1); while (*ecode == OP_ALT); + + offset_top = md->end_offset_top; + eptr = md->end_match_ptr; + + /* For a non-repeating ket, just continue at this level. This also + happens for a repeating ket if no characters were matched in the group. + This is the forcible breaking of infinite loops as implemented in Perl + 5.005. If there is an options reset, it will get obeyed in the normal + course of events. */ + + if (*ecode == OP_KET || eptr == saved_eptr) + { + ecode += 1+LINK_SIZE; + break; + } + + /* The repeating kets try the rest of the pattern or restart from the + preceding bracket, in the appropriate order. We need to reset any options + that changed within the bracket before re-running it, so check the next + opcode. */ + + if (ecode[1+LINK_SIZE] == OP_OPT) + { + ims = (ims & ~PCRE_IMS) | ecode[4]; + DPRINTF(("ims set to %02lx at group repeat\n", ims)); + } + + if (*ecode == OP_KETRMIN) + { + if ((rrc = match(eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, + eptrb, 0)) != MATCH_NOMATCH) return rrc; + if ((rrc = match(eptr, prev, offset_top, md, ims, eptrb, + match_isgroup)) != MATCH_NOMATCH) return rrc; + } + else /* OP_KETRMAX */ + { + if ((rrc = match(eptr, prev, offset_top, md, ims, eptrb, + match_isgroup)) != MATCH_NOMATCH) return rrc; + if ((rrc = match(eptr, ecode + 1+LINK_SIZE, offset_top, md, ims, eptrb, + 0)) != MATCH_NOMATCH) return rrc; + } + } + return MATCH_NOMATCH; + + /* An alternation is the end of a branch; scan along to find the end of the + bracketed group and go to there. */ + + case OP_ALT: + do ecode += GET(ecode,1); while (*ecode == OP_ALT); + break; + + /* BRAZERO and BRAMINZERO occur just before a bracket group, indicating + that it may occur zero times. It may repeat infinitely, or not at all - + i.e. it could be ()* or ()? in the pattern. Brackets with fixed upper + repeat limits are compiled as a number of copies, with the optional ones + preceded by BRAZERO or BRAMINZERO. */ + + case OP_BRAZERO: + { + const uschar *next = ecode+1; + if ((rrc = match(eptr, next, offset_top, md, ims, eptrb, match_isgroup)) + != MATCH_NOMATCH) return rrc; + do next += GET(next,1); while (*next == OP_ALT); + ecode = next + 1+LINK_SIZE; + } + break; + + case OP_BRAMINZERO: + { + const uschar *next = ecode+1; + do next += GET(next,1); while (*next == OP_ALT); + if ((rrc = match(eptr, next + 1+LINK_SIZE, offset_top, md, ims, eptrb, + match_isgroup)) != MATCH_NOMATCH) return rrc; + ecode++; + } + break; + + /* End of a group, repeated or non-repeating. If we are at the end of + an assertion "group", stop matching and return MATCH_MATCH, but record the + current high water mark for use by positive assertions. Do this also + for the "once" (not-backup up) groups. */ + + case OP_KET: + case OP_KETRMIN: + case OP_KETRMAX: + { + const uschar *prev = ecode - GET(ecode, 1); + const uschar *saved_eptr = eptrb->saved_eptr; + + eptrb = eptrb->prev; /* Back up the stack of bracket start pointers */ + + if (*prev == OP_ASSERT || *prev == OP_ASSERT_NOT || + *prev == OP_ASSERTBACK || *prev == OP_ASSERTBACK_NOT || + *prev == OP_ONCE) + { + md->end_match_ptr = eptr; /* For ONCE */ + md->end_offset_top = offset_top; + return MATCH_MATCH; + } + + /* In all other cases except a conditional group we have to check the + group number back at the start and if necessary complete handling an + extraction by setting the offsets and bumping the high water mark. */ + + if (*prev != OP_COND) + { + int offset; + int number = *prev - OP_BRA; + + /* For extended extraction brackets (large number), we have to fish out + the number from a dummy opcode at the start. */ + + if (number > EXTRACT_BASIC_MAX) number = GET2(prev, 2+LINK_SIZE); + offset = number << 1; + +#ifdef DEBUG + printf("end bracket %d", number); + printf("\n"); +#endif + + /* Test for a numbered group. This includes groups called as a result + of recursion. Note that whole-pattern recursion is coded as a recurse + into group 0, so it won't be picked up here. Instead, we catch it when + the OP_END is reached. */ + + if (number > 0) + { + md->capture_last = number; + if (offset >= md->offset_max) md->offset_overflow = TRUE; else + { + md->offset_vector[offset] = + md->offset_vector[md->offset_end - number]; + md->offset_vector[offset+1] = eptr - md->start_subject; + if (offset_top <= offset) offset_top = offset + 2; + } + + /* Handle a recursively called group. Restore the offsets + appropriately and continue from after the call. */ + + if (md->recursive != NULL && md->recursive->group_num == number) + { + recursion_info *rec = md->recursive; + DPRINTF(("Recursion (%d) succeeded - continuing\n", number)); + md->recursive = rec->prev; + md->start_match = rec->save_start; + memcpy(md->offset_vector, rec->offset_save, + rec->saved_max * sizeof(int)); + ecode = rec->after_call; + ims = original_ims; + break; + } + } + } + + /* Reset the value of the ims flags, in case they got changed during + the group. */ + + ims = original_ims; + DPRINTF(("ims reset to %02lx\n", ims)); + + /* For a non-repeating ket, just continue at this level. This also + happens for a repeating ket if no characters were matched in the group. + This is the forcible breaking of infinite loops as implemented in Perl + 5.005. If there is an options reset, it will get obeyed in the normal + course of events. */ + + if (*ecode == OP_KET || eptr == saved_eptr) + { + ecode += 1 + LINK_SIZE; + break; + } + + /* The repeating kets try the rest of the pattern or restart from the + preceding bracket, in the appropriate order. */ + + if (*ecode == OP_KETRMIN) + { + if ((rrc = match(eptr, ecode + 1+LINK_SIZE, offset_top, md, ims, eptrb, + 0)) != MATCH_NOMATCH) return rrc; + if ((rrc = match(eptr, prev, offset_top, md, ims, eptrb, + match_isgroup)) != MATCH_NOMATCH) return rrc; + } + else /* OP_KETRMAX */ + { + if ((rrc = match(eptr, prev, offset_top, md, ims, eptrb, + match_isgroup)) != MATCH_NOMATCH) return rrc; + if ((rrc = match(eptr, ecode + 1+LINK_SIZE, offset_top, md, ims, eptrb, + 0)) != MATCH_NOMATCH) return rrc; + } + } + return MATCH_NOMATCH; + + /* Start of subject unless notbol, or after internal newline if multiline */ + + case OP_CIRC: + if (md->notbol && eptr == md->start_subject) return MATCH_NOMATCH; + if ((ims & PCRE_MULTILINE) != 0) + { + if (eptr != md->start_subject && eptr[-1] != NEWLINE) + return MATCH_NOMATCH; + ecode++; + break; + } + /* ... else fall through */ + + /* Start of subject assertion */ + + case OP_SOD: + if (eptr != md->start_subject) return MATCH_NOMATCH; + ecode++; + break; + + /* Start of match assertion */ + + case OP_SOM: + if (eptr != md->start_subject + md->start_offset) return MATCH_NOMATCH; + ecode++; + break; + + /* Assert before internal newline if multiline, or before a terminating + newline unless endonly is set, else end of subject unless noteol is set. */ + + case OP_DOLL: + if ((ims & PCRE_MULTILINE) != 0) + { + if (eptr < md->end_subject) + { if (*eptr != NEWLINE) return MATCH_NOMATCH; } + else + { if (md->noteol) return MATCH_NOMATCH; } + ecode++; + break; + } + else + { + if (md->noteol) return MATCH_NOMATCH; + if (!md->endonly) + { + if (eptr < md->end_subject - 1 || + (eptr == md->end_subject - 1 && *eptr != NEWLINE)) + return MATCH_NOMATCH; + ecode++; + break; + } + } + /* ... else fall through */ + + /* End of subject assertion (\z) */ + + case OP_EOD: + if (eptr < md->end_subject) return MATCH_NOMATCH; + ecode++; + break; + + /* End of subject or ending \n assertion (\Z) */ + + case OP_EODN: + if (eptr < md->end_subject - 1 || + (eptr == md->end_subject - 1 && *eptr != NEWLINE)) return MATCH_NOMATCH; + ecode++; + break; + + /* Word boundary assertions */ + + case OP_NOT_WORD_BOUNDARY: + case OP_WORD_BOUNDARY: + { + BOOL prev_is_word, cur_is_word; + + /* Find out if the previous and current characters are "word" characters. + It takes a bit more work in UTF-8 mode. Characters > 255 are assumed to + be "non-word" characters. */ + +#ifdef SUPPORT_UTF8 + if (md->utf8) + { + if (eptr == md->start_subject) prev_is_word = FALSE; else + { + const uschar *lastptr = eptr - 1; + while((*lastptr & 0xc0) == 0x80) lastptr--; + GETCHAR(c, lastptr); + prev_is_word = c < 256 && (md->ctypes[c] & ctype_word) != 0; + } + if (eptr >= md->end_subject) cur_is_word = FALSE; else + { + GETCHAR(c, eptr); + cur_is_word = c < 256 && (md->ctypes[c] & ctype_word) != 0; + } + } + else +#endif + + /* More streamlined when not in UTF-8 mode */ + + { + prev_is_word = (eptr != md->start_subject) && + ((md->ctypes[eptr[-1]] & ctype_word) != 0); + cur_is_word = (eptr < md->end_subject) && + ((md->ctypes[*eptr] & ctype_word) != 0); + } + + /* Now see if the situation is what we want */ + + if ((*ecode++ == OP_WORD_BOUNDARY)? + cur_is_word == prev_is_word : cur_is_word != prev_is_word) + return MATCH_NOMATCH; + } + break; + + /* Match a single character type; inline for speed */ + + case OP_ANY: + if ((ims & PCRE_DOTALL) == 0 && eptr < md->end_subject && *eptr == NEWLINE) + return MATCH_NOMATCH; + if (eptr++ >= md->end_subject) return MATCH_NOMATCH; +#ifdef SUPPORT_UTF8 + if (md->utf8) + while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++; +#endif + ecode++; + break; + + /* Match a single byte, even in UTF-8 mode. This opcode really does match + any byte, even newline, independent of the setting of PCRE_DOTALL. */ + + case OP_ANYBYTE: + if (eptr++ >= md->end_subject) return MATCH_NOMATCH; + ecode++; + break; + + case OP_NOT_DIGIT: + if (eptr >= md->end_subject) return MATCH_NOMATCH; + GETCHARINCTEST(c, eptr); + if ( +#ifdef SUPPORT_UTF8 + c < 256 && +#endif + (md->ctypes[c] & ctype_digit) != 0 + ) + return MATCH_NOMATCH; + ecode++; + break; + + case OP_DIGIT: + if (eptr >= md->end_subject) return MATCH_NOMATCH; + GETCHARINCTEST(c, eptr); + if ( +#ifdef SUPPORT_UTF8 + c >= 256 || +#endif + (md->ctypes[c] & ctype_digit) == 0 + ) + return MATCH_NOMATCH; + ecode++; + break; + + case OP_NOT_WHITESPACE: + if (eptr >= md->end_subject) return MATCH_NOMATCH; + GETCHARINCTEST(c, eptr); + if ( +#ifdef SUPPORT_UTF8 + c < 256 && +#endif + (md->ctypes[c] & ctype_space) != 0 + ) + return MATCH_NOMATCH; + ecode++; + break; + + case OP_WHITESPACE: + if (eptr >= md->end_subject) return MATCH_NOMATCH; + GETCHARINCTEST(c, eptr); + if ( +#ifdef SUPPORT_UTF8 + c >= 256 || +#endif + (md->ctypes[c] & ctype_space) == 0 + ) + return MATCH_NOMATCH; + ecode++; + break; + + case OP_NOT_WORDCHAR: + if (eptr >= md->end_subject) return MATCH_NOMATCH; + GETCHARINCTEST(c, eptr); + if ( +#ifdef SUPPORT_UTF8 + c < 256 && +#endif + (md->ctypes[c] & ctype_word) != 0 + ) + return MATCH_NOMATCH; + ecode++; + break; + + case OP_WORDCHAR: + if (eptr >= md->end_subject) return MATCH_NOMATCH; + GETCHARINCTEST(c, eptr); + if ( +#ifdef SUPPORT_UTF8 + c >= 256 || +#endif + (md->ctypes[c] & ctype_word) == 0 + ) + return MATCH_NOMATCH; + ecode++; + break; + + /* Match a back reference, possibly repeatedly. Look past the end of the + item to see if there is repeat information following. The code is similar + to that for character classes, but repeated for efficiency. Then obey + similar code to character type repeats - written out again for speed. + However, if the referenced string is the empty string, always treat + it as matched, any number of times (otherwise there could be infinite + loops). */ + + case OP_REF: + { + int length; + int offset = GET2(ecode, 1) << 1; /* Doubled ref number */ + ecode += 3; /* Advance past item */ + + /* If the reference is unset, set the length to be longer than the amount + of subject left; this ensures that every attempt at a match fails. We + can't just fail here, because of the possibility of quantifiers with zero + minima. */ + + length = (offset >= offset_top || md->offset_vector[offset] < 0)? + md->end_subject - eptr + 1 : + md->offset_vector[offset+1] - md->offset_vector[offset]; + + /* Set up for repetition, or handle the non-repeated case */ + + switch (*ecode) + { + case OP_CRSTAR: + case OP_CRMINSTAR: + case OP_CRPLUS: + case OP_CRMINPLUS: + case OP_CRQUERY: + case OP_CRMINQUERY: + c = *ecode++ - OP_CRSTAR; + minimize = (c & 1) != 0; + min = rep_min[c]; /* Pick up values from tables; */ + max = rep_max[c]; /* zero for max => infinity */ + if (max == 0) max = INT_MAX; + break; + + case OP_CRRANGE: + case OP_CRMINRANGE: + minimize = (*ecode == OP_CRMINRANGE); + min = GET2(ecode, 1); + max = GET2(ecode, 3); + if (max == 0) max = INT_MAX; + ecode += 5; + break; + + default: /* No repeat follows */ + if (!match_ref(offset, eptr, length, md, ims)) return MATCH_NOMATCH; + eptr += length; + continue; /* With the main loop */ + } + + /* If the length of the reference is zero, just continue with the + main loop. */ + + if (length == 0) continue; + + /* First, ensure the minimum number of matches are present. We get back + the length of the reference string explicitly rather than passing the + address of eptr, so that eptr can be a register variable. */ + + for (i = 1; i <= min; i++) + { + if (!match_ref(offset, eptr, length, md, ims)) return MATCH_NOMATCH; + eptr += length; + } + + /* If min = max, continue at the same level without recursion. + They are not both allowed to be zero. */ + + if (min == max) continue; + + /* If minimizing, keep trying and advancing the pointer */ + + if (minimize) + { + for (i = min;; i++) + { + if ((rrc = match(eptr, ecode, offset_top, md, ims, eptrb, 0)) != + MATCH_NOMATCH) return rrc; + if (i >= max || !match_ref(offset, eptr, length, md, ims)) + return MATCH_NOMATCH; + eptr += length; + } + /* Control never gets here */ + } + + /* If maximizing, find the longest string and work backwards */ + + else + { + const uschar *pp = eptr; + for (i = min; i < max; i++) + { + if (!match_ref(offset, eptr, length, md, ims)) break; + eptr += length; + } + while (eptr >= pp) + { + if ((rrc = match(eptr, ecode, offset_top, md, ims, eptrb, 0)) != + MATCH_NOMATCH) return rrc; + eptr -= length; + } + return MATCH_NOMATCH; + } + } + /* Control never gets here */ + + + + /* Match a bit-mapped character class, possibly repeatedly. This op code is + used when all the characters in the class have values in the range 0-255. + The only difference between OP_CLASS and OP_NCLASS occurs when a data + character outside the range is encountered. + + First, look past the end of the item to see if there is repeat information + following. Then obey similar code to character type repeats - written out + again for speed. */ + + case OP_NCLASS: + case OP_CLASS: + { + const uschar *data = ecode + 1; /* Save for matching */ + ecode += 33; /* Advance past the item */ + + switch (*ecode) + { + case OP_CRSTAR: + case OP_CRMINSTAR: + case OP_CRPLUS: + case OP_CRMINPLUS: + case OP_CRQUERY: + case OP_CRMINQUERY: + c = *ecode++ - OP_CRSTAR; + minimize = (c & 1) != 0; + min = rep_min[c]; /* Pick up values from tables; */ + max = rep_max[c]; /* zero for max => infinity */ + if (max == 0) max = INT_MAX; + break; + + case OP_CRRANGE: + case OP_CRMINRANGE: + minimize = (*ecode == OP_CRMINRANGE); + min = GET2(ecode, 1); + max = GET2(ecode, 3); + if (max == 0) max = INT_MAX; + ecode += 5; + break; + + default: /* No repeat follows */ + min = max = 1; + break; + } + + /* First, ensure the minimum number of matches are present. */ + +#ifdef SUPPORT_UTF8 + /* UTF-8 mode */ + if (md->utf8) + { + for (i = 1; i <= min; i++) + { + if (eptr >= md->end_subject) return MATCH_NOMATCH; + GETCHARINC(c, eptr); + if (c > 255) + { + if (op == OP_CLASS) return MATCH_NOMATCH; + } + else + { + if ((data[c/8] & (1 << (c&7))) == 0) return MATCH_NOMATCH; + } + } + } + else +#endif + /* Not UTF-8 mode */ + { + for (i = 1; i <= min; i++) + { + if (eptr >= md->end_subject) return MATCH_NOMATCH; + c = *eptr++; + if ((data[c/8] & (1 << (c&7))) == 0) return MATCH_NOMATCH; + } + } + + /* If max == min we can continue with the main loop without the + need to recurse. */ + + if (min == max) continue; + + /* If minimizing, keep testing the rest of the expression and advancing + the pointer while it matches the class. */ + + if (minimize) + { +#ifdef SUPPORT_UTF8 + /* UTF-8 mode */ + if (md->utf8) + { + for (i = min;; i++) + { + if ((rrc = match(eptr, ecode, offset_top, md, ims, eptrb, 0)) != + MATCH_NOMATCH) return rrc; + if (i >= max || eptr >= md->end_subject) return MATCH_NOMATCH; + GETCHARINC(c, eptr); + if (c > 255) + { + if (op == OP_CLASS) return MATCH_NOMATCH; + } + else + { + if ((data[c/8] & (1 << (c&7))) == 0) return MATCH_NOMATCH; + } + } + } + else +#endif + /* Not UTF-8 mode */ + { + for (i = min;; i++) + { + if ((rrc = match(eptr, ecode, offset_top, md, ims, eptrb, 0)) != + MATCH_NOMATCH) return rrc; + if (i >= max || eptr >= md->end_subject) return MATCH_NOMATCH; + c = *eptr++; + if ((data[c/8] & (1 << (c&7))) == 0) return MATCH_NOMATCH; + } + } + /* Control never gets here */ + } + + /* If maximizing, find the longest possible run, then work backwards. */ + + else + { + const uschar *pp = eptr; + +#ifdef SUPPORT_UTF8 + /* UTF-8 mode */ + if (md->utf8) + { + for (i = min; i < max; i++) + { + int len = 1; + if (eptr >= md->end_subject) break; + GETCHARLEN(c, eptr, len); + if (c > 255) + { + if (op == OP_CLASS) break; + } + else + { + if ((data[c/8] & (1 << (c&7))) == 0) break; + } + eptr += len; + } + for (;;) + { + if ((rrc = match(eptr, ecode, offset_top, md, ims, eptrb, 0)) != + MATCH_NOMATCH) return rrc; + if (eptr-- == pp) break; /* Stop if tried at original pos */ + BACKCHAR(eptr); + } + } + else +#endif + /* Not UTF-8 mode */ + { + for (i = min; i < max; i++) + { + if (eptr >= md->end_subject) break; + c = *eptr; + if ((data[c/8] & (1 << (c&7))) == 0) break; + eptr++; + } + while (eptr >= pp) + { + if ((rrc = match(eptr--, ecode, offset_top, md, ims, eptrb, 0)) != + MATCH_NOMATCH) return rrc; + } + } + + return MATCH_NOMATCH; + } + } + /* Control never gets here */ + + + /* Match an extended character class. This opcode is encountered only + in UTF-8 mode, because that's the only time it is compiled. */ + +#ifdef SUPPORT_UTF8 + case OP_XCLASS: + { + const uschar *data = ecode + 1 + LINK_SIZE; /* Save for matching */ + ecode += GET(ecode, 1); /* Advance past the item */ + + switch (*ecode) + { + case OP_CRSTAR: + case OP_CRMINSTAR: + case OP_CRPLUS: + case OP_CRMINPLUS: + case OP_CRQUERY: + case OP_CRMINQUERY: + c = *ecode++ - OP_CRSTAR; + minimize = (c & 1) != 0; + min = rep_min[c]; /* Pick up values from tables; */ + max = rep_max[c]; /* zero for max => infinity */ + if (max == 0) max = INT_MAX; + break; + + case OP_CRRANGE: + case OP_CRMINRANGE: + minimize = (*ecode == OP_CRMINRANGE); + min = GET2(ecode, 1); + max = GET2(ecode, 3); + if (max == 0) max = INT_MAX; + ecode += 5; + break; + + default: /* No repeat follows */ + min = max = 1; + break; + } + + /* First, ensure the minimum number of matches are present. */ + + for (i = 1; i <= min; i++) + { + if (eptr >= md->end_subject) return MATCH_NOMATCH; + GETCHARINC(c, eptr); + if (!match_xclass(c, data)) return MATCH_NOMATCH; + } + + /* If max == min we can continue with the main loop without the + need to recurse. */ + + if (min == max) continue; + + /* If minimizing, keep testing the rest of the expression and advancing + the pointer while it matches the class. */ + + if (minimize) + { + for (i = min;; i++) + { + if ((rrc = match(eptr, ecode, offset_top, md, ims, eptrb, 0)) != + MATCH_NOMATCH) return rrc; + if (i >= max || eptr >= md->end_subject) return MATCH_NOMATCH; + GETCHARINC(c, eptr); + if (!match_xclass(c, data)) return MATCH_NOMATCH; + } + /* Control never gets here */ + } + + /* If maximizing, find the longest possible run, then work backwards. */ + + else + { + const uschar *pp = eptr; + for (i = min; i < max; i++) + { + int len = 1; + if (eptr >= md->end_subject) break; + GETCHARLEN(c, eptr, len); + if (!match_xclass(c, data)) break; + eptr += len; + } + for(;;) + { + if ((rrc = match(eptr, ecode, offset_top, md, ims, eptrb, 0)) != + MATCH_NOMATCH) return rrc; + if (eptr-- == pp) break; /* Stop if tried at original pos */ + BACKCHAR(eptr) + } + return MATCH_NOMATCH; + } + + /* Control never gets here */ + } +#endif /* End of XCLASS */ + + /* Match a run of characters */ + + case OP_CHARS: + { + register int length = ecode[1]; + ecode += 2; + +#ifdef DEBUG /* Sigh. Some compilers never learn. */ + if (eptr >= md->end_subject) + printf("matching subject against pattern "); + else + { + printf("matching subject "); + pchars(eptr, length, TRUE, md); + printf(" against pattern "); + } + pchars(ecode, length, FALSE, md); + printf("\n"); +#endif + + if (length > md->end_subject - eptr) return MATCH_NOMATCH; + if ((ims & PCRE_CASELESS) != 0) + { + while (length-- > 0) + if (md->lcc[*ecode++] != md->lcc[*eptr++]) + return MATCH_NOMATCH; + } + else + { + while (length-- > 0) if (*ecode++ != *eptr++) return MATCH_NOMATCH; + } + } + break; + + /* Match a single character repeatedly; different opcodes share code. */ + + case OP_EXACT: + min = max = GET2(ecode, 1); + ecode += 3; + goto REPEATCHAR; + + case OP_UPTO: + case OP_MINUPTO: + min = 0; + max = GET2(ecode, 1); + minimize = *ecode == OP_MINUPTO; + ecode += 3; + goto REPEATCHAR; + + case OP_STAR: + case OP_MINSTAR: + case OP_PLUS: + case OP_MINPLUS: + case OP_QUERY: + case OP_MINQUERY: + c = *ecode++ - OP_STAR; + minimize = (c & 1) != 0; + min = rep_min[c]; /* Pick up values from tables; */ + max = rep_max[c]; /* zero for max => infinity */ + if (max == 0) max = INT_MAX; + + /* Common code for all repeated single-character matches. We can give + up quickly if there are fewer than the minimum number of characters left in + the subject. */ + + REPEATCHAR: +#ifdef SUPPORT_UTF8 + if (md->utf8) + { + int len = 1; + const uschar *charptr = ecode; + GETCHARLEN(c, ecode, len); + if (min * len > md->end_subject - eptr) return MATCH_NOMATCH; + ecode += len; + + /* Handle multibyte character matching specially here. There is no + support for any kind of casing for multibyte characters. */ + + if (len > 1) + { + for (i = 1; i <= min; i++) + { + if (memcmp(eptr, charptr, len) != 0) return MATCH_NOMATCH; + eptr += len; + } + + if (min == max) continue; + + if (minimize) + { + for (i = min;; i++) + { + if ((rrc = match(eptr, ecode, offset_top, md, ims, eptrb, 0)) != + MATCH_NOMATCH) return rrc; + if (i >= max || + eptr >= md->end_subject || + memcmp(eptr, charptr, len) != 0) + return MATCH_NOMATCH; + eptr += len; + } + /* Control never gets here */ + } + else + { + const uschar *pp = eptr; + for (i = min; i < max; i++) + { + if (eptr > md->end_subject - len || + memcmp(eptr, charptr, len) != 0) + break; + eptr += len; + } + while (eptr >= pp) + { + if ((rrc = match(eptr, ecode, offset_top, md, ims, eptrb, 0)) != + MATCH_NOMATCH) return rrc; + eptr -= len; + } + return MATCH_NOMATCH; + } + /* Control never gets here */ + } + + /* If the length of a UTF-8 character is 1, we fall through here, and + obey the code as for non-UTF-8 characters below, though in this case the + value of c will always be < 128. */ + } + else +#endif + + /* When not in UTF-8 mode, load a single-byte character. */ + { + if (min > md->end_subject - eptr) return MATCH_NOMATCH; + c = *ecode++; + } + + /* The value of c at this point is always less than 256, though we may or + may not be in UTF-8 mode. The code is duplicated for the caseless and + caseful cases, for speed, since matching characters is likely to be quite + common. First, ensure the minimum number of matches are present. If min = + max, continue at the same level without recursing. Otherwise, if + minimizing, keep trying the rest of the expression and advancing one + matching character if failing, up to the maximum. Alternatively, if + maximizing, find the maximum number of characters and work backwards. */ + + DPRINTF(("matching %c{%d,%d} against subject %.*s\n", c, min, max, + max, eptr)); + + if ((ims & PCRE_CASELESS) != 0) + { + c = md->lcc[c]; + for (i = 1; i <= min; i++) + if (c != md->lcc[*eptr++]) return MATCH_NOMATCH; + if (min == max) continue; + if (minimize) + { + for (i = min;; i++) + { + if ((rrc = match(eptr, ecode, offset_top, md, ims, eptrb, 0)) != + MATCH_NOMATCH) return rrc; + if (i >= max || eptr >= md->end_subject || + c != md->lcc[*eptr++]) + return MATCH_NOMATCH; + } + /* Control never gets here */ + } + else + { + const uschar *pp = eptr; + for (i = min; i < max; i++) + { + if (eptr >= md->end_subject || c != md->lcc[*eptr]) break; + eptr++; + } + while (eptr >= pp) + if ((rrc = match(eptr--, ecode, offset_top, md, ims, eptrb, 0)) != + MATCH_NOMATCH) return rrc; + return MATCH_NOMATCH; + } + /* Control never gets here */ + } + + /* Caseful comparisons (includes all multi-byte characters) */ + + else + { + for (i = 1; i <= min; i++) if (c != *eptr++) return MATCH_NOMATCH; + if (min == max) continue; + if (minimize) + { + for (i = min;; i++) + { + if ((rrc = match(eptr, ecode, offset_top, md, ims, eptrb, 0)) != + MATCH_NOMATCH) return rrc; + if (i >= max || eptr >= md->end_subject || c != *eptr++) + return MATCH_NOMATCH; + } + /* Control never gets here */ + } + else + { + const uschar *pp = eptr; + for (i = min; i < max; i++) + { + if (eptr >= md->end_subject || c != *eptr) break; + eptr++; + } + while (eptr >= pp) + if ((rrc = match(eptr--, ecode, offset_top, md, ims, eptrb, 0)) != + MATCH_NOMATCH) return rrc; + return MATCH_NOMATCH; + } + } + /* Control never gets here */ + + /* Match a negated single one-byte character. The character we are + checking can be multibyte. */ + + case OP_NOT: + if (eptr >= md->end_subject) return MATCH_NOMATCH; + ecode++; + GETCHARINCTEST(c, eptr); + if ((ims & PCRE_CASELESS) != 0) + { +#ifdef SUPPORT_UTF8 + if (c < 256) +#endif + c = md->lcc[c]; + if (md->lcc[*ecode++] == c) return MATCH_NOMATCH; + } + else + { + if (*ecode++ == c) return MATCH_NOMATCH; + } + break; + + /* Match a negated single one-byte character repeatedly. This is almost a + repeat of the code for a repeated single character, but I haven't found a + nice way of commoning these up that doesn't require a test of the + positive/negative option for each character match. Maybe that wouldn't add + very much to the time taken, but character matching *is* what this is all + about... */ + + case OP_NOTEXACT: + min = max = GET2(ecode, 1); + ecode += 3; + goto REPEATNOTCHAR; + + case OP_NOTUPTO: + case OP_NOTMINUPTO: + min = 0; + max = GET2(ecode, 1); + minimize = *ecode == OP_NOTMINUPTO; + ecode += 3; + goto REPEATNOTCHAR; + + case OP_NOTSTAR: + case OP_NOTMINSTAR: + case OP_NOTPLUS: + case OP_NOTMINPLUS: + case OP_NOTQUERY: + case OP_NOTMINQUERY: + c = *ecode++ - OP_NOTSTAR; + minimize = (c & 1) != 0; + min = rep_min[c]; /* Pick up values from tables; */ + max = rep_max[c]; /* zero for max => infinity */ + if (max == 0) max = INT_MAX; + + /* Common code for all repeated single-character (less than 255) matches. + We can give up quickly if there are fewer than the minimum number of + characters left in the subject. */ + + REPEATNOTCHAR: + if (min > md->end_subject - eptr) return MATCH_NOMATCH; + c = *ecode++; + + /* The code is duplicated for the caseless and caseful cases, for speed, + since matching characters is likely to be quite common. First, ensure the + minimum number of matches are present. If min = max, continue at the same + level without recursing. Otherwise, if minimizing, keep trying the rest of + the expression and advancing one matching character if failing, up to the + maximum. Alternatively, if maximizing, find the maximum number of + characters and work backwards. */ + + DPRINTF(("negative matching %c{%d,%d} against subject %.*s\n", c, min, max, + max, eptr)); + + if ((ims & PCRE_CASELESS) != 0) + { + c = md->lcc[c]; + +#ifdef SUPPORT_UTF8 + /* UTF-8 mode */ + if (md->utf8) + { + register int d; + for (i = 1; i <= min; i++) + { + GETCHARINC(d, eptr); + if (d < 256) d = md->lcc[d]; + if (c == d) return MATCH_NOMATCH; + } + } + else +#endif + + /* Not UTF-8 mode */ + { + for (i = 1; i <= min; i++) + if (c == md->lcc[*eptr++]) return MATCH_NOMATCH; + } + + if (min == max) continue; + + if (minimize) + { +#ifdef SUPPORT_UTF8 + /* UTF-8 mode */ + if (md->utf8) + { + register int d; + for (i = min;; i++) + { + if ((rrc = match(eptr, ecode, offset_top, md, ims, eptrb, 0)) != + MATCH_NOMATCH) return rrc; + GETCHARINC(d, eptr); + if (d < 256) d = md->lcc[d]; + if (i >= max || eptr >= md->end_subject || c == d) + return MATCH_NOMATCH; + } + } + else +#endif + /* Not UTF-8 mode */ + { + for (i = min;; i++) + { + if ((rrc = match(eptr, ecode, offset_top, md, ims, eptrb, 0)) != + MATCH_NOMATCH) return rrc; + if (i >= max || eptr >= md->end_subject || c == md->lcc[*eptr++]) + return MATCH_NOMATCH; + } + } + /* Control never gets here */ + } + + /* Maximize case */ + + else + { + const uschar *pp = eptr; + +#ifdef SUPPORT_UTF8 + /* UTF-8 mode */ + if (md->utf8) + { + register int d; + for (i = min; i < max; i++) + { + int len = 1; + if (eptr >= md->end_subject) break; + GETCHARLEN(d, eptr, len); + if (d < 256) d = md->lcc[d]; + if (c == d) break; + eptr += len; + } + for(;;) + { + if ((rrc = match(eptr, ecode, offset_top, md, ims, eptrb, 0)) != + MATCH_NOMATCH) return rrc; + if (eptr-- == pp) break; /* Stop if tried at original pos */ + BACKCHAR(eptr); + } + } + else +#endif + /* Not UTF-8 mode */ + { + for (i = min; i < max; i++) + { + if (eptr >= md->end_subject || c == md->lcc[*eptr]) break; + eptr++; + } + while (eptr >= pp) + { + if ((rrc = match(eptr, ecode, offset_top, md, ims, eptrb, 0)) != + MATCH_NOMATCH) return rrc; + eptr--; + } + } + + return MATCH_NOMATCH; + } + /* Control never gets here */ + } + + /* Caseful comparisons */ + + else + { +#ifdef SUPPORT_UTF8 + /* UTF-8 mode */ + if (md->utf8) + { + register int d; + for (i = 1; i <= min; i++) + { + GETCHARINC(d, eptr); + if (c == d) return MATCH_NOMATCH; + } + } + else +#endif + /* Not UTF-8 mode */ + { + for (i = 1; i <= min; i++) + if (c == *eptr++) return MATCH_NOMATCH; + } + + if (min == max) continue; + + if (minimize) + { +#ifdef SUPPORT_UTF8 + /* UTF-8 mode */ + if (md->utf8) + { + register int d; + for (i = min;; i++) + { + if ((rrc = match(eptr, ecode, offset_top, md, ims, eptrb, 0)) != + MATCH_NOMATCH) return rrc; + GETCHARINC(d, eptr); + if (i >= max || eptr >= md->end_subject || c == d) + return MATCH_NOMATCH; + } + } + else +#endif + /* Not UTF-8 mode */ + { + for (i = min;; i++) + { + if ((rrc = match(eptr, ecode, offset_top, md, ims, eptrb, 0)) != + MATCH_NOMATCH) return rrc; + if (i >= max || eptr >= md->end_subject || c == *eptr++) + return MATCH_NOMATCH; + } + } + /* Control never gets here */ + } + + /* Maximize case */ + + else + { + const uschar *pp = eptr; + +#ifdef SUPPORT_UTF8 + /* UTF-8 mode */ + if (md->utf8) + { + register int d; + for (i = min; i < max; i++) + { + int len = 1; + if (eptr >= md->end_subject) break; + GETCHARLEN(d, eptr, len); + if (c == d) break; + eptr += len; + } + for(;;) + { + if ((rrc = match(eptr, ecode, offset_top, md, ims, eptrb, 0)) != + MATCH_NOMATCH) return rrc; + if (eptr-- == pp) break; /* Stop if tried at original pos */ + BACKCHAR(eptr); + } + } + else +#endif + /* Not UTF-8 mode */ + { + for (i = min; i < max; i++) + { + if (eptr >= md->end_subject || c == *eptr) break; + eptr++; + } + while (eptr >= pp) + { + if ((rrc = match(eptr, ecode, offset_top, md, ims, eptrb, 0)) != + MATCH_NOMATCH) return rrc; + eptr--; + } + } + + return MATCH_NOMATCH; + } + } + /* Control never gets here */ + + /* Match a single character type repeatedly; several different opcodes + share code. This is very similar to the code for single characters, but we + repeat it in the interests of efficiency. */ + + case OP_TYPEEXACT: + min = max = GET2(ecode, 1); + minimize = TRUE; + ecode += 3; + goto REPEATTYPE; + + case OP_TYPEUPTO: + case OP_TYPEMINUPTO: + min = 0; + max = GET2(ecode, 1); + minimize = *ecode == OP_TYPEMINUPTO; + ecode += 3; + goto REPEATTYPE; + + case OP_TYPESTAR: + case OP_TYPEMINSTAR: + case OP_TYPEPLUS: + case OP_TYPEMINPLUS: + case OP_TYPEQUERY: + case OP_TYPEMINQUERY: + c = *ecode++ - OP_TYPESTAR; + minimize = (c & 1) != 0; + min = rep_min[c]; /* Pick up values from tables; */ + max = rep_max[c]; /* zero for max => infinity */ + if (max == 0) max = INT_MAX; + + /* Common code for all repeated single character type matches. Note that + in UTF-8 mode, '.' matches a character of any length, but for the other + character types, the valid characters are all one-byte long. */ + + REPEATTYPE: + ctype = *ecode++; /* Code for the character type */ + + /* First, ensure the minimum number of matches are present. Use inline + code for maximizing the speed, and do the type test once at the start + (i.e. keep it out of the loop). Also we can test that there are at least + the minimum number of bytes before we start. This isn't as effective in + UTF-8 mode, but it does no harm. Separate the UTF-8 code completely as that + is tidier. */ + + if (min > md->end_subject - eptr) return MATCH_NOMATCH; + if (min > 0) + { +#ifdef SUPPORT_UTF8 + if (md->utf8) switch(ctype) + { + case OP_ANY: + for (i = 1; i <= min; i++) + { + if (eptr >= md->end_subject || + (*eptr++ == NEWLINE && (ims & PCRE_DOTALL) == 0)) + return MATCH_NOMATCH; + while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++; + } + break; + + case OP_ANYBYTE: + eptr += min; + break; + + case OP_NOT_DIGIT: + for (i = 1; i <= min; i++) + { + if (eptr >= md->end_subject) return MATCH_NOMATCH; + GETCHARINC(c, eptr); + if (c < 256 && (md->ctypes[c] & ctype_digit) != 0) + return MATCH_NOMATCH; + } + break; + + case OP_DIGIT: + for (i = 1; i <= min; i++) + { + if (eptr >= md->end_subject || + *eptr >= 128 || (md->ctypes[*eptr++] & ctype_digit) == 0) + return MATCH_NOMATCH; + /* No need to skip more bytes - we know it's a 1-byte character */ + } + break; + + case OP_NOT_WHITESPACE: + for (i = 1; i <= min; i++) + { + if (eptr >= md->end_subject || + (*eptr < 128 && (md->ctypes[*eptr++] & ctype_space) != 0)) + return MATCH_NOMATCH; + while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++; + } + break; + + case OP_WHITESPACE: + for (i = 1; i <= min; i++) + { + if (eptr >= md->end_subject || + *eptr >= 128 || (md->ctypes[*eptr++] & ctype_space) == 0) + return MATCH_NOMATCH; + /* No need to skip more bytes - we know it's a 1-byte character */ + } + break; + + case OP_NOT_WORDCHAR: + for (i = 1; i <= min; i++) + { + if (eptr >= md->end_subject || + (*eptr < 128 && (md->ctypes[*eptr++] & ctype_word) != 0)) + return MATCH_NOMATCH; + while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++; + } + break; + + case OP_WORDCHAR: + for (i = 1; i <= min; i++) + { + if (eptr >= md->end_subject || + *eptr >= 128 || (md->ctypes[*eptr++] & ctype_word) == 0) + return MATCH_NOMATCH; + /* No need to skip more bytes - we know it's a 1-byte character */ + } + break; + } + else +#endif + + /* Code for the non-UTF-8 case for minimum matching */ + + switch(ctype) + { + case OP_ANY: + if ((ims & PCRE_DOTALL) == 0) + { + for (i = 1; i <= min; i++) + if (*eptr++ == NEWLINE) return MATCH_NOMATCH; + } + else eptr += min; + break; + + case OP_ANYBYTE: + eptr += min; + break; + + case OP_NOT_DIGIT: + for (i = 1; i <= min; i++) + if ((md->ctypes[*eptr++] & ctype_digit) != 0) return MATCH_NOMATCH; + break; + + case OP_DIGIT: + for (i = 1; i <= min; i++) + if ((md->ctypes[*eptr++] & ctype_digit) == 0) return MATCH_NOMATCH; + break; + + case OP_NOT_WHITESPACE: + for (i = 1; i <= min; i++) + if ((md->ctypes[*eptr++] & ctype_space) != 0) return MATCH_NOMATCH; + break; + + case OP_WHITESPACE: + for (i = 1; i <= min; i++) + if ((md->ctypes[*eptr++] & ctype_space) == 0) return MATCH_NOMATCH; + break; + + case OP_NOT_WORDCHAR: + for (i = 1; i <= min; i++) + if ((md->ctypes[*eptr++] & ctype_word) != 0) + return MATCH_NOMATCH; + break; + + case OP_WORDCHAR: + for (i = 1; i <= min; i++) + if ((md->ctypes[*eptr++] & ctype_word) == 0) + return MATCH_NOMATCH; + break; + } + } + + /* If min = max, continue at the same level without recursing */ + + if (min == max) continue; + + /* If minimizing, we have to test the rest of the pattern before each + subsequent match. Again, separate the UTF-8 case for speed. */ + + if (minimize) + { +#ifdef SUPPORT_UTF8 + /* UTF-8 mode */ + if (md->utf8) + { + for (i = min;; i++) + { + if ((rrc = match(eptr, ecode, offset_top, md, ims, eptrb, 0)) != + MATCH_NOMATCH) return rrc; + if (i >= max || eptr >= md->end_subject) return MATCH_NOMATCH; + + GETCHARINC(c, eptr); + switch(ctype) + { + case OP_ANY: + if ((ims & PCRE_DOTALL) == 0 && c == NEWLINE) return MATCH_NOMATCH; + break; + + case OP_ANYBYTE: + break; + + case OP_NOT_DIGIT: + if (c < 256 && (md->ctypes[c] & ctype_digit) != 0) + return MATCH_NOMATCH; + break; + + case OP_DIGIT: + if (c >= 256 || (md->ctypes[c] & ctype_digit) == 0) + return MATCH_NOMATCH; + break; + + case OP_NOT_WHITESPACE: + if (c < 256 && (md->ctypes[c] & ctype_space) != 0) + return MATCH_NOMATCH; + break; + + case OP_WHITESPACE: + if (c >= 256 || (md->ctypes[c] & ctype_space) == 0) + return MATCH_NOMATCH; + break; + + case OP_NOT_WORDCHAR: + if (c < 256 && (md->ctypes[c] & ctype_word) != 0) + return MATCH_NOMATCH; + break; + + case OP_WORDCHAR: + if (c >= 256 && (md->ctypes[c] & ctype_word) == 0) + return MATCH_NOMATCH; + break; + } + } + } + else +#endif + /* Not UTF-8 mode */ + { + for (i = min;; i++) + { + if ((rrc = match(eptr, ecode, offset_top, md, ims, eptrb, 0)) != + MATCH_NOMATCH) return rrc; + if (i >= max || eptr >= md->end_subject) return MATCH_NOMATCH; + c = *eptr++; + switch(ctype) + { + case OP_ANY: + if ((ims & PCRE_DOTALL) == 0 && c == NEWLINE) return MATCH_NOMATCH; + break; + + case OP_ANYBYTE: + break; + + case OP_NOT_DIGIT: + if ((md->ctypes[c] & ctype_digit) != 0) return MATCH_NOMATCH; + break; + + case OP_DIGIT: + if ((md->ctypes[c] & ctype_digit) == 0) return MATCH_NOMATCH; + break; + + case OP_NOT_WHITESPACE: + if ((md->ctypes[c] & ctype_space) != 0) return MATCH_NOMATCH; + break; + + case OP_WHITESPACE: + if ((md->ctypes[c] & ctype_space) == 0) return MATCH_NOMATCH; + break; + + case OP_NOT_WORDCHAR: + if ((md->ctypes[c] & ctype_word) != 0) return MATCH_NOMATCH; + break; + + case OP_WORDCHAR: + if ((md->ctypes[c] & ctype_word) == 0) return MATCH_NOMATCH; + break; + } + } + } + /* Control never gets here */ + } + + /* If maximizing it is worth using inline code for speed, doing the type + test once at the start (i.e. keep it out of the loop). Again, keep the + UTF-8 stuff separate. */ + + else + { + const uschar *pp = eptr; + +#ifdef SUPPORT_UTF8 + /* UTF-8 mode */ + + if (md->utf8) + { + switch(ctype) + { + case OP_ANY: + + /* Special code is required for UTF8, but when the maximum is unlimited + we don't need it, so we repeat the non-UTF8 code. This is probably + worth it, because .* is quite a common idiom. */ + + if (max < INT_MAX) + { + if ((ims & PCRE_DOTALL) == 0) + { + for (i = min; i < max; i++) + { + if (eptr >= md->end_subject || *eptr == NEWLINE) break; + eptr++; + while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++; + } + } + else + { + for (i = min; i < max; i++) + { + eptr++; + while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++; + } + } + } + + /* Handle unlimited UTF-8 repeat */ + + else + { + if ((ims & PCRE_DOTALL) == 0) + { + for (i = min; i < max; i++) + { + if (eptr >= md->end_subject || *eptr == NEWLINE) break; + eptr++; + } + break; + } + else + { + c = max - min; + if (c > md->end_subject - eptr) c = md->end_subject - eptr; + eptr += c; + } + } + break; + + /* The byte case is the same as non-UTF8 */ + + case OP_ANYBYTE: + c = max - min; + if (c > md->end_subject - eptr) c = md->end_subject - eptr; + eptr += c; + break; + + case OP_NOT_DIGIT: + for (i = min; i < max; i++) + { + int len = 1; + if (eptr >= md->end_subject) break; + GETCHARLEN(c, eptr, len); + if (c < 256 && (md->ctypes[c] & ctype_digit) != 0) break; + eptr+= len; + } + break; + + case OP_DIGIT: + for (i = min; i < max; i++) + { + int len = 1; + if (eptr >= md->end_subject) break; + GETCHARLEN(c, eptr, len); + if (c >= 256 ||(md->ctypes[c] & ctype_digit) == 0) break; + eptr+= len; + } + break; + + case OP_NOT_WHITESPACE: + for (i = min; i < max; i++) + { + int len = 1; + if (eptr >= md->end_subject) break; + GETCHARLEN(c, eptr, len); + if (c < 256 && (md->ctypes[c] & ctype_space) != 0) break; + eptr+= len; + } + break; + + case OP_WHITESPACE: + for (i = min; i < max; i++) + { + int len = 1; + if (eptr >= md->end_subject) break; + GETCHARLEN(c, eptr, len); + if (c >= 256 ||(md->ctypes[c] & ctype_space) == 0) break; + eptr+= len; + } + break; + + case OP_NOT_WORDCHAR: + for (i = min; i < max; i++) + { + int len = 1; + if (eptr >= md->end_subject) break; + GETCHARLEN(c, eptr, len); + if (c < 256 && (md->ctypes[c] & ctype_word) != 0) break; + eptr+= len; + } + break; + + case OP_WORDCHAR: + for (i = min; i < max; i++) + { + int len = 1; + if (eptr >= md->end_subject) break; + GETCHARLEN(c, eptr, len); + if (c >= 256 || (md->ctypes[c] & ctype_word) == 0) break; + eptr+= len; + } + break; + } + + /* eptr is now past the end of the maximum run */ + + for(;;) + { + if ((rrc = match(eptr, ecode, offset_top, md, ims, eptrb, 0)) != + MATCH_NOMATCH) return rrc; + if (eptr-- == pp) break; /* Stop if tried at original pos */ + BACKCHAR(eptr); + } + } + else +#endif + + /* Not UTF-8 mode */ + { + switch(ctype) + { + case OP_ANY: + if ((ims & PCRE_DOTALL) == 0) + { + for (i = min; i < max; i++) + { + if (eptr >= md->end_subject || *eptr == NEWLINE) break; + eptr++; + } + break; + } + /* For DOTALL case, fall through and treat as \C */ + + case OP_ANYBYTE: + c = max - min; + if (c > md->end_subject - eptr) c = md->end_subject - eptr; + eptr += c; + break; + + case OP_NOT_DIGIT: + for (i = min; i < max; i++) + { + if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_digit) != 0) + break; + eptr++; + } + break; + + case OP_DIGIT: + for (i = min; i < max; i++) + { + if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_digit) == 0) + break; + eptr++; + } + break; + + case OP_NOT_WHITESPACE: + for (i = min; i < max; i++) + { + if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_space) != 0) + break; + eptr++; + } + break; + + case OP_WHITESPACE: + for (i = min; i < max; i++) + { + if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_space) == 0) + break; + eptr++; + } + break; + + case OP_NOT_WORDCHAR: + for (i = min; i < max; i++) + { + if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_word) != 0) + break; + eptr++; + } + break; + + case OP_WORDCHAR: + for (i = min; i < max; i++) + { + if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_word) == 0) + break; + eptr++; + } + break; + } + + /* eptr is now past the end of the maximum run */ + + while (eptr >= pp) + { + if ((rrc = match(eptr--, ecode, offset_top, md, ims, eptrb, 0)) != + MATCH_NOMATCH) return rrc; + } + } + + /* Get here if we can't make it match with any permitted repetitions */ + + return MATCH_NOMATCH; + } + /* Control never gets here */ + + /* There's been some horrible disaster. Since all codes > OP_BRA are + for capturing brackets, and there shouldn't be any gaps between 0 and + OP_BRA, arrival here can only mean there is something seriously wrong + in the code above or the OP_xxx definitions. */ + + default: + DPRINTF(("Unknown opcode %d\n", *ecode)); + return PCRE_ERROR_UNKNOWN_NODE; + } + + /* Do not stick any code in here without much thought; it is assumed + that "continue" in the code above comes out to here to repeat the main + loop. */ + + } /* End of main loop */ +/* Control never reaches here */ +} + + + + +/************************************************* +* Execute a Regular Expression * +*************************************************/ + +/* This function applies a compiled re to a subject string and picks out +portions of the string if it matches. Two elements in the vector are set for +each substring: the offsets to the start and end of the substring. + +Arguments: + external_re points to the compiled expression + extra_data points to extra data or is NULL + subject points to the subject string + length length of subject string (may contain binary zeros) + start_offset where to start in the subject string + options option bits + offsets points to a vector of ints to be filled in with offsets + offsetcount the number of elements in the vector + +Returns: > 0 => success; value is the number of elements filled in + = 0 => success, but offsets is not big enough + -1 => failed to match + < -1 => some kind of unexpected problem +*/ + +int +pcre_exec(const pcre *external_re, const pcre_extra *extra_data, + const char *subject, int length, int start_offset, int options, int *offsets, + int offsetcount) +{ +int rc, resetcount, ocount; +int first_byte = -1; +int req_byte = -1; +int req_byte2 = -1; +unsigned long int ims = 0; +BOOL using_temporary_offsets = FALSE; +BOOL anchored; +BOOL startline; +BOOL first_byte_caseless = FALSE; +BOOL req_byte_caseless = FALSE; +match_data match_block; +const uschar *start_bits = NULL; +const uschar *start_match = (const uschar *)subject + start_offset; +const uschar *end_subject; +const uschar *req_byte_ptr = start_match - 1; +const pcre_study_data *study; +const real_pcre *re = (const real_pcre *)external_re; + +/* Plausibility checks */ + +if ((options & ~PUBLIC_EXEC_OPTIONS) != 0) return PCRE_ERROR_BADOPTION; +if (re == NULL || subject == NULL || + (offsets == NULL && offsetcount > 0)) return PCRE_ERROR_NULL; + +/* Fish out the optional data from the extra_data structure, first setting +the default values. */ + +study = NULL; +match_block.match_limit = MATCH_LIMIT; +match_block.callout_data = NULL; + +if (extra_data != NULL) + { + register unsigned int flags = extra_data->flags; + if ((flags & PCRE_EXTRA_STUDY_DATA) != 0) + study = extra_data->study_data; + if ((flags & PCRE_EXTRA_MATCH_LIMIT) != 0) + match_block.match_limit = extra_data->match_limit; + if ((flags & PCRE_EXTRA_CALLOUT_DATA) != 0) + match_block.callout_data = extra_data->callout_data; + } + +/* Now we have re supposedly pointing to the regex */ + +if (re->magic_number != MAGIC_NUMBER) return PCRE_ERROR_BADMAGIC; + +anchored = ((re->options | options) & PCRE_ANCHORED) != 0; +startline = (re->options & PCRE_STARTLINE) != 0; + +match_block.start_code = + (const uschar *)re + sizeof(real_pcre) + re->name_count * re->name_entry_size; +match_block.start_subject = (const uschar *)subject; +match_block.start_offset = start_offset; +match_block.end_subject = match_block.start_subject + length; +end_subject = match_block.end_subject; + +match_block.endonly = (re->options & PCRE_DOLLAR_ENDONLY) != 0; +match_block.utf8 = (re->options & PCRE_UTF8) != 0; + +match_block.notbol = (options & PCRE_NOTBOL) != 0; +match_block.noteol = (options & PCRE_NOTEOL) != 0; +match_block.notempty = (options & PCRE_NOTEMPTY) != 0; + +match_block.recursive = NULL; /* No recursion at top level */ + +match_block.lcc = re->tables + lcc_offset; +match_block.ctypes = re->tables + ctypes_offset; + +/* The ims options can vary during the matching as a result of the presence +of (?ims) items in the pattern. They are kept in a local variable so that +restoring at the exit of a group is easy. */ + +ims = re->options & (PCRE_CASELESS|PCRE_MULTILINE|PCRE_DOTALL); + +/* If the expression has got more back references than the offsets supplied can +hold, we get a temporary bit of working store to use during the matching. +Otherwise, we can use the vector supplied, rounding down its size to a multiple +of 3. */ + +ocount = offsetcount - (offsetcount % 3); + +if (re->top_backref > 0 && re->top_backref >= ocount/3) + { + ocount = re->top_backref * 3 + 3; + match_block.offset_vector = (int *)(pcre_malloc)(ocount * sizeof(int)); + if (match_block.offset_vector == NULL) return PCRE_ERROR_NOMEMORY; + using_temporary_offsets = TRUE; + DPRINTF(("Got memory to hold back references\n")); + } +else match_block.offset_vector = offsets; + +match_block.offset_end = ocount; +match_block.offset_max = (2*ocount)/3; +match_block.offset_overflow = FALSE; +match_block.capture_last = -1; + +/* Compute the minimum number of offsets that we need to reset each time. Doing +this makes a huge difference to execution time when there aren't many brackets +in the pattern. */ + +resetcount = 2 + re->top_bracket * 2; +if (resetcount > offsetcount) resetcount = ocount; + +/* Reset the working variable associated with each extraction. These should +never be used unless previously set, but they get saved and restored, and so we +initialize them to avoid reading uninitialized locations. */ + +if (match_block.offset_vector != NULL) + { + register int *iptr = match_block.offset_vector + ocount; + register int *iend = iptr - resetcount/2 + 1; + while (--iptr >= iend) *iptr = -1; + } + +/* Set up the first character to match, if available. The first_byte value is +never set for an anchored regular expression, but the anchoring may be forced +at run time, so we have to test for anchoring. The first char may be unset for +an unanchored pattern, of course. If there's no first char and the pattern was +studied, there may be a bitmap of possible first characters. */ + +if (!anchored) + { + if ((re->options & PCRE_FIRSTSET) != 0) + { + first_byte = re->first_byte & 255; + if ((first_byte_caseless = ((re->first_byte & REQ_CASELESS) != 0)) == TRUE) + first_byte = match_block.lcc[first_byte]; + } + else + if (!startline && study != NULL && + (study->options & PCRE_STUDY_MAPPED) != 0) + start_bits = study->start_bits; + } + +/* For anchored or unanchored matches, there may be a "last known required +character" set. */ + +if ((re->options & PCRE_REQCHSET) != 0) + { + req_byte = re->req_byte & 255; + req_byte_caseless = (re->req_byte & REQ_CASELESS) != 0; + req_byte2 = (re->tables + fcc_offset)[req_byte]; /* case flipped */ + } + +/* Loop for handling unanchored repeated matching attempts; for anchored regexs +the loop runs just once. */ + +do + { + register int *iptr = match_block.offset_vector; + register int *iend = iptr + resetcount; + + /* Reset the maximum number of extractions we might see. */ + + while (iptr < iend) *iptr++ = -1; + + /* Advance to a unique first char if possible */ + + if (first_byte >= 0) + { + if (first_byte_caseless) + while (start_match < end_subject && + match_block.lcc[*start_match] != first_byte) + start_match++; + else + while (start_match < end_subject && *start_match != first_byte) + start_match++; + } + + /* Or to just after \n for a multiline match if possible */ + + else if (startline) + { + if (start_match > match_block.start_subject + start_offset) + { + while (start_match < end_subject && start_match[-1] != NEWLINE) + start_match++; + } + } + + /* Or to a non-unique first char after study */ + + else if (start_bits != NULL) + { + while (start_match < end_subject) + { + register int c = *start_match; + if ((start_bits[c/8] & (1 << (c&7))) == 0) start_match++; else break; + } + } + +#ifdef DEBUG /* Sigh. Some compilers never learn. */ + printf(">>>> Match against: "); + pchars(start_match, end_subject - start_match, TRUE, &match_block); + printf("\n"); +#endif + + /* If req_byte is set, we know that that character must appear in the subject + for the match to succeed. If the first character is set, req_byte must be + later in the subject; otherwise the test starts at the match point. This + optimization can save a huge amount of backtracking in patterns with nested + unlimited repeats that aren't going to match. Writing separate code for + cased/caseless versions makes it go faster, as does using an autoincrement + and backing off on a match. + + HOWEVER: when the subject string is very, very long, searching to its end can + take a long time, and give bad performance on quite ordinary patterns. This + showed up when somebody was matching /^C/ on a 32-megabyte string... so we + don't do this when the string is sufficiently long. */ + + if (req_byte >= 0 && end_subject - start_match < REQ_BYTE_MAX) + { + register const uschar *p = start_match + ((first_byte >= 0)? 1 : 0); + + /* We don't need to repeat the search if we haven't yet reached the + place we found it at last time. */ + + if (p > req_byte_ptr) + { + if (req_byte_caseless) + { + while (p < end_subject) + { + register int pp = *p++; + if (pp == req_byte || pp == req_byte2) { p--; break; } + } + } + else + { + while (p < end_subject) + { + if (*p++ == req_byte) { p--; break; } + } + } + + /* If we can't find the required character, break the matching loop */ + + if (p >= end_subject) break; + + /* If we have found the required character, save the point where we + found it, so that we don't search again next time round the loop if + the start hasn't passed this character yet. */ + + req_byte_ptr = p; + } + } + + /* When a match occurs, substrings will be set for all internal extractions; + we just need to set up the whole thing as substring 0 before returning. If + there were too many extractions, set the return code to zero. In the case + where we had to get some local store to hold offsets for backreferences, copy + those back references that we can. In this case there need not be overflow + if certain parts of the pattern were not used. */ + + match_block.start_match = start_match; + match_block.match_call_count = 0; + + rc = match(start_match, match_block.start_code, 2, &match_block, ims, NULL, + match_isgroup); + + if (rc == MATCH_NOMATCH) + { + start_match++; +#ifdef SUPPORT_UTF8 + if (match_block.utf8) + while((*start_match & 0xc0) == 0x80) start_match++; +#endif + continue; + } + + if (rc != MATCH_MATCH) + { + DPRINTF((">>>> error: returning %d\n", rc)); + return rc; + } + + /* We have a match! Copy the offset information from temporary store if + necessary */ + + if (using_temporary_offsets) + { + if (offsetcount >= 4) + { + memcpy(offsets + 2, match_block.offset_vector + 2, + (offsetcount - 2) * sizeof(int)); + DPRINTF(("Copied offsets from temporary memory\n")); + } + if (match_block.end_offset_top > offsetcount) + match_block.offset_overflow = TRUE; + + DPRINTF(("Freeing temporary memory\n")); + (pcre_free)(match_block.offset_vector); + } + + rc = match_block.offset_overflow? 0 : match_block.end_offset_top/2; + + if (offsetcount < 2) rc = 0; else + { + offsets[0] = start_match - match_block.start_subject; + offsets[1] = match_block.end_match_ptr - match_block.start_subject; + } + + DPRINTF((">>>> returning %d\n", rc)); + return rc; + } + +/* This "while" is the end of the "do" above */ + +while (!anchored && start_match <= end_subject); + +if (using_temporary_offsets) + { + DPRINTF(("Freeing temporary memory\n")); + (pcre_free)(match_block.offset_vector); + } + +DPRINTF((">>>> returning PCRE_ERROR_NOMATCH\n")); + +return PCRE_ERROR_NOMATCH; +} + +/* End of pcre.c */ diff --git a/mk4/continuity/pcre/pcre.def b/mk4/continuity/pcre/pcre.def new file mode 100644 index 0000000..4f6c4bf --- /dev/null +++ b/mk4/continuity/pcre/pcre.def @@ -0,0 +1,22 @@ +EXPORTS + +pcre_malloc DATA +pcre_free DATA + +pcre_compile +pcre_copy_substring +pcre_exec +pcre_get_substring +pcre_get_substring_list +pcre_free_substring +pcre_free_substring_list +pcre_info +pcre_fullinfo +pcre_maketables +pcre_study +pcre_version + +regcomp +regexec +regerror +regfree diff --git a/mk4/continuity/pcre/pcre.in b/mk4/continuity/pcre/pcre.in new file mode 100644 index 0000000..2aa44b9 --- /dev/null +++ b/mk4/continuity/pcre/pcre.in @@ -0,0 +1,184 @@ +/************************************************* +* Perl-Compatible Regular Expressions * +*************************************************/ + +/* Copyright (c) 1997-2003 University of Cambridge */ + +#ifndef _PCRE_H +#define _PCRE_H + +/* The file pcre.h is build by "configure". Do not edit it; instead +make changes to pcre.in. */ + +#define PCRE_MAJOR @PCRE_MAJOR@ +#define PCRE_MINOR @PCRE_MINOR@ +#define PCRE_DATE @PCRE_DATE@ + +/* Win32 uses DLL by default */ + +#ifdef _WIN32 +# ifdef PCRE_DEFINITION +# ifdef DLL_EXPORT +# define PCRE_DATA_SCOPE __declspec(dllexport) +# endif +# else +# ifndef PCRE_STATIC +# define PCRE_DATA_SCOPE __declspec(dllimport) +# endif +# endif +#endif +#ifndef PCRE_DATA_SCOPE +# define PCRE_DATA_SCOPE extern +#endif + +/* Have to include stdlib.h in order to ensure that size_t is defined; +it is needed here for malloc. */ + +#include + +/* Allow for C++ users */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Options */ + +#define PCRE_CASELESS 0x0001 +#define PCRE_MULTILINE 0x0002 +#define PCRE_DOTALL 0x0004 +#define PCRE_EXTENDED 0x0008 +#define PCRE_ANCHORED 0x0010 +#define PCRE_DOLLAR_ENDONLY 0x0020 +#define PCRE_EXTRA 0x0040 +#define PCRE_NOTBOL 0x0080 +#define PCRE_NOTEOL 0x0100 +#define PCRE_UNGREEDY 0x0200 +#define PCRE_NOTEMPTY 0x0400 +#define PCRE_UTF8 0x0800 +#define PCRE_NO_AUTO_CAPTURE 0x1000 + +/* Exec-time and get/set-time error codes */ + +#define PCRE_ERROR_NOMATCH (-1) +#define PCRE_ERROR_NULL (-2) +#define PCRE_ERROR_BADOPTION (-3) +#define PCRE_ERROR_BADMAGIC (-4) +#define PCRE_ERROR_UNKNOWN_NODE (-5) +#define PCRE_ERROR_NOMEMORY (-6) +#define PCRE_ERROR_NOSUBSTRING (-7) +#define PCRE_ERROR_MATCHLIMIT (-8) +#define PCRE_ERROR_CALLOUT (-9) /* Never used by PCRE itself */ + +/* Request types for pcre_fullinfo() */ + +#define PCRE_INFO_OPTIONS 0 +#define PCRE_INFO_SIZE 1 +#define PCRE_INFO_CAPTURECOUNT 2 +#define PCRE_INFO_BACKREFMAX 3 +#define PCRE_INFO_FIRSTBYTE 4 +#define PCRE_INFO_FIRSTCHAR 4 /* For backwards compatibility */ +#define PCRE_INFO_FIRSTTABLE 5 +#define PCRE_INFO_LASTLITERAL 6 +#define PCRE_INFO_NAMEENTRYSIZE 7 +#define PCRE_INFO_NAMECOUNT 8 +#define PCRE_INFO_NAMETABLE 9 +#define PCRE_INFO_STUDYSIZE 10 + +/* Request types for pcre_config() */ + +#define PCRE_CONFIG_UTF8 0 +#define PCRE_CONFIG_NEWLINE 1 +#define PCRE_CONFIG_LINK_SIZE 2 +#define PCRE_CONFIG_POSIX_MALLOC_THRESHOLD 3 +#define PCRE_CONFIG_MATCH_LIMIT 4 + +/* Bit flags for the pcre_extra structure */ + +#define PCRE_EXTRA_STUDY_DATA 0x0001 +#define PCRE_EXTRA_MATCH_LIMIT 0x0002 +#define PCRE_EXTRA_CALLOUT_DATA 0x0004 + +/* Types */ + +struct real_pcre; /* declaration; the definition is private */ +typedef struct real_pcre pcre; + +/* The structure for passing additional data to pcre_exec(). This is defined in +such as way as to be extensible. */ + +typedef struct pcre_extra { + unsigned long int flags; /* Bits for which fields are set */ + void *study_data; /* Opaque data from pcre_study() */ + unsigned long int match_limit; /* Maximum number of calls to match() */ + void *callout_data; /* Data passed back in callouts */ +} pcre_extra; + +/* The structure for passing out data via the pcre_callout_function. We use a +structure so that new fields can be added on the end in future versions, +without changing the API of the function, thereby allowing old clients to work +without modification. */ + +typedef struct pcre_callout_block { + int version; /* Identifies version of block */ + /* ------------------------ Version 0 ------------------------------- */ + int callout_number; /* Number compiled into pattern */ + int *offset_vector; /* The offset vector */ + const char *subject; /* The subject being matched */ + int subject_length; /* The length of the subject */ + int start_match; /* Offset to start of this match attempt */ + int current_position; /* Where we currently are */ + int capture_top; /* Max current capture */ + int capture_last; /* Most recently closed capture */ + void *callout_data; /* Data passed in with the call */ + /* ------------------------------------------------------------------ */ +} pcre_callout_block; + +/* Indirection for store get and free functions. These can be set to +alternative malloc/free functions if required. There is also an optional +callout function that is triggered by the (?) regex item. Some magic is +required for Win32 DLL; it is null on other OS. For Virtual Pascal, these +have to be different again. */ + +#ifndef VPCOMPAT +PCRE_DATA_SCOPE void *(*pcre_malloc)(size_t); +PCRE_DATA_SCOPE void (*pcre_free)(void *); +PCRE_DATA_SCOPE int (*pcre_callout)(pcre_callout_block *); +#else /* VPCOMPAT */ +extern void *pcre_malloc(size_t); +extern void pcre_free(void *); +extern int pcre_callout(pcre_callout_block *); +#endif /* VPCOMPAT */ + +/* Exported PCRE functions */ + +extern pcre *pcre_compile(const char *, int, const char **, + int *, const unsigned char *); +extern int pcre_config(int, void *); +extern int pcre_copy_named_substring(const pcre *, const char *, + int *, int, const char *, char *, int); +extern int pcre_copy_substring(const char *, int *, int, int, + char *, int); +extern int pcre_exec(const pcre *, const pcre_extra *, + const char *, int, int, int, int *, int); +extern void pcre_free_substring(const char *); +extern void pcre_free_substring_list(const char **); +extern int pcre_fullinfo(const pcre *, const pcre_extra *, int, + void *); +extern int pcre_get_named_substring(const pcre *, const char *, + int *, int, const char *, const char **); +extern int pcre_get_stringnumber(const pcre *, const char *); +extern int pcre_get_substring(const char *, int *, int, int, + const char **); +extern int pcre_get_substring_list(const char *, int *, int, + const char ***); +extern int pcre_info(const pcre *, int *, int *); +extern const unsigned char *pcre_maketables(void); +extern pcre_extra *pcre_study(const pcre *, int, const char **); +extern const char *pcre_version(void); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* End of pcre.h */ diff --git a/mk4/continuity/pcre/pcredemo.c b/mk4/continuity/pcre/pcredemo.c new file mode 100644 index 0000000..2cfa492 --- /dev/null +++ b/mk4/continuity/pcre/pcredemo.c @@ -0,0 +1,329 @@ +/************************************************* +* PCRE DEMONSTRATION PROGRAM * +*************************************************/ + +/* + * This is a demonstration program to illustrate the most straightforward + * ways of calling the PCRE regular expression library from a C program. See + * the pcresample documentation for a short discussion. + * + * Compile thuswise: gcc -Wall pcredemo.c -I/opt/local/include -L/opt/local/lib + * \ -R/opt/local/lib -lpcre + * + * Replace "/opt/local/include" and "/opt/local/lib" with wherever the include + * and library files for PCRE are installed on your system. Only some + * operating systems (e.g. Solaris) use the -R option. + */ + + +#include +#include +#include + +#define OVECCOUNT 30 /* should be a multiple of 3 */ + + +int main(int argc, char **argv) +{ + pcre *re; + const char *error; + char *pattern; + char *subject; + unsigned char *name_table; + int erroffset; + int find_all; + int namecount; + int name_entry_size; + int ovector[OVECCOUNT]; + int subject_length; + int rc, i; + + + /************************************************************************* + * First, sort out the command line. There is only one possible option at * + * the moment, "-g" to request repeated matching to find all occurrences, * + * like Perl's /g option. We set the variable find_all non-zero if it is * + * present. Apart from that, there must be exactly two arguments. * + *************************************************************************/ + + find_all = 0; + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "-g") == 0) + find_all = 1; + else + break; + } + + /* + * After the options, we require exactly two arguments, which are the + * pattern, and the subject string. + */ + + if (argc - i != 2) { + printf("Two arguments required: a regex and a subject string\n"); + return 1; + } + pattern = argv[i]; + subject = argv[i + 1]; + subject_length = (int) strlen(subject); + + + /************************************************************************* + * Now we are going to compile the regular expression pattern, and handle * + * and errors that are detected. * + *************************************************************************/ + + re = pcre_compile( + pattern, /* the pattern */ + 0, /* default options */ + &error, /* for error message */ + &erroffset,/* for error offset */ + NULL); /* use default character tables */ + + /* Compilation failed: print the error message and exit */ + + if (re == NULL) { + printf("PCRE compilation failed at offset %d: %s\n", erroffset, error); + return 1; + } + /************************************************************************* + * If the compilation succeeded, we call PCRE again, in order to do a * + * pattern match against the subject string. This just does ONE match. If * + * further matching is needed, it will be done below. * + *************************************************************************/ + + rc = pcre_exec( + re, /* the compiled pattern */ + NULL, /* no extra data - we didn't study the + * pattern */ + subject, /* the subject string */ + subject_length, /* the length of the subject */ + 0, /* start at offset 0 in the subject */ + 0, /* default options */ + ovector, /* output vector for substring information */ + OVECCOUNT); /* number of elements in the output vector */ + + /* Matching failed: handle error cases */ + + if (rc < 0) { + switch (rc) { + case PCRE_ERROR_NOMATCH: + printf("No match\n"); + break; + /* + * Handle other special cases if you like + */ + default: + printf("Matching error %d\n", rc); + break; + } + return 1; + } + /* Match succeded */ + + printf("\nMatch succeeded at offset %d\n", ovector[0]); + + + /************************************************************************* + * We have found the first match within the subject string. If the output * + * vector wasn't big enough, set its size to the maximum. Then output any * + * substrings that were captured. * + *************************************************************************/ + + /* The output vector wasn't big enough */ + + if (rc == 0) { + rc = OVECCOUNT / 3; + printf("ovector only has room for %d captured substrings\n", rc - 1); + } + /* + * Show substrings stored in the output vector by number. Obviously, in a + * real application you might want to do things other than print them. + */ + + for (i = 0; i < rc; i++) { + char *substring_start = subject + ovector[2 * i]; + int substring_length = ovector[2 * i + 1] - ovector[2 * i]; + printf("%2d: %.*s\n", i, substring_length, substring_start); + } + + + /************************************************************************* + * That concludes the basic part of this demonstration program. We have * + * compiled a pattern, and performed a single match. The code that follows* + * first shows how to access named substrings, and then how to code for * + * repeated matches on the same subject. * + *************************************************************************/ + + /* + * See if there are any named substrings, and if so, show them by name. + * First we have to extract the count of named parentheses from the + * pattern. + */ + + (void) pcre_fullinfo( + re, /* the compiled pattern */ + NULL, /* no extra data - we didn't study the + * pattern */ + PCRE_INFO_NAMECOUNT, /* number of named substrings */ + &namecount); /* where to put the answer */ + + if (namecount <= 0) + printf("No named substrings\n"); + else { + unsigned char *tabptr; + printf("Named substrings\n"); + + /* + * Before we can access the substrings, we must extract the table for + * translating names to numbers, and the size of each entry in the + * table. + */ + + (void) pcre_fullinfo( + re, /* the compiled pattern */ + NULL,/* no extra data - we didn't study the + * pattern */ + PCRE_INFO_NAMETABLE, /* address of the table */ + &name_table); /* where to put the answer */ + + (void) pcre_fullinfo( + re, /* the compiled pattern */ + NULL,/* no extra data - we didn't study the + * pattern */ + PCRE_INFO_NAMEENTRYSIZE, /* size of each entry in + * the table */ + &name_entry_size); /* where to put the answer */ + + /* + * Now we can scan the table and, for each entry, print the number, the + * name, and the substring itself. + */ + + tabptr = name_table; + for (i = 0; i < namecount; i++) { + int n = (tabptr[0] << 8) | tabptr[1]; + printf("(%d) %*s: %.*s\n", n, name_entry_size - 3, tabptr + 2, + ovector[2 * n + 1] - ovector[2 * n], subject + ovector[2 * n]); + tabptr += name_entry_size; + } + } + + + /************************************************************************* + * If the "-g" option was given on the command line, we want to continue * + * to search for additional matches in the subject string, in a similar * + * way to the /g option in Perl. This turns out to be trickier than you * + * might think because of the possibility of matching an empty string. * + * What happens is as follows: * + * * + * If the previous match was NOT for an empty string, we can just start * + * the next match at the end of the previous one. * + * * + * If the previous match WAS for an empty string, we can't do that, as it * + * would lead to an infinite loop. Instead, a special call of pcre_exec() * + * is made with the PCRE_NOTEMPTY and PCRE_ANCHORED flags set. The first * + * of these tells PCRE that an empty string is not a valid match; other * + * possibilities must be tried. The second flag restricts PCRE to one * + * match attempt at the initial string position. If this match succeeds, * + * an alternative to the empty string match has been found, and we can * + * proceed round the loop. * + *************************************************************************/ + + if (!find_all) + return 0; /* Finish unless -g was given */ + + /* Loop for second and subsequent matches */ + + for (;;) { + int options = 0; /* Normally no options */ + int start_offset = ovector[1]; /* Start at end of previous match */ + + /* + * If the previous match was for an empty string, we are finished if we + * are at the end of the subject. Otherwise, arrange to run another + * match at the same point to see if a non-empty match can be found. + */ + + if (ovector[0] == ovector[1]) { + if (ovector[0] == subject_length) + break; + options = PCRE_NOTEMPTY | PCRE_ANCHORED; + } + /* Run the next matching operation */ + + rc = pcre_exec( + re, /* the compiled pattern */ + NULL, /* no extra data - we didn't study the + * pattern */ + subject, /* the subject string */ + subject_length, /* the length of the subject */ + start_offset, /* starting offset in the subject */ + options, /* options */ + ovector, /* output vector for substring information */ + OVECCOUNT);/* number of elements in the output vector */ + + /* + * This time, a result of NOMATCH isn't an error. If the value in + * "options" is zero, it just means we have found all possible matches, + * so the loop ends. Otherwise, it means we have failed to find a + * non-empty-string match at a point where there was a previous + * empty-string match. In this case, we do what Perl does: advance the + * matching position by one, and continue. We do this by setting the + * "end of previous match" offset, because that is picked up at the top + * of the loop as the point at which to start again. + */ + + if (rc == PCRE_ERROR_NOMATCH) { + if (options == 0) + break; + ovector[1] = start_offset + 1; + continue; /* Go round the loop again */ + } + /* Other matching errors are not recoverable. */ + + if (rc < 0) { + printf("Matching error %d\n", rc); + return 1; + } + /* Match succeded */ + + printf("\nMatch succeeded again at offset %d\n", ovector[0]); + + /* The match succeeded, but the output vector wasn't big enough. */ + + if (rc == 0) { + rc = OVECCOUNT / 3; + printf("ovector only has room for %d captured substrings\n", rc - 1); + } + /* + * As before, show substrings stored in the output vector by number, + * and then also any named substrings. + */ + + for (i = 0; i < rc; i++) { + char *substring_start = subject + ovector[2 * i]; + int substring_length = ovector[2 * i + 1] - ovector[2 * i]; + printf("%2d: %.*s\n", i, substring_length, substring_start); + } + + if (namecount <= 0) + printf("No named substrings\n"); + else { + unsigned char *tabptr = name_table; + printf("Named substrings\n"); + for (i = 0; i < namecount; i++) { + int n = (tabptr[0] << 8) | tabptr[1]; + printf("(%d) %*s: %.*s\n", n, name_entry_size - 3, tabptr + 2, + ovector[2 * n + 1] - ovector[2 * n], subject + ovector[2 * n]); + tabptr += name_entry_size; + } + } + } /* End of loop to find second and subsequent + * matches */ + + printf("\n"); + return 0; +} + +/* End of pcredemo.c */ diff --git a/mk4/continuity/pcre/pcregrep.c b/mk4/continuity/pcre/pcregrep.c new file mode 100644 index 0000000..f4a59f4 --- /dev/null +++ b/mk4/continuity/pcre/pcregrep.c @@ -0,0 +1,642 @@ +/************************************************* +* pcregrep program * +*************************************************/ + +/* This is a grep program that uses the PCRE regular expression library to do +its pattern matching. On a Unix or Win32 system it can recurse into +directories. */ + +#include +#include +#include +#include +#include +#include "config.h" +#include "pcre.h" + +#define FALSE 0 +#define TRUE 1 + +typedef int BOOL; + +#define VERSION "3.0 14-Jan-2003" +#define MAX_PATTERN_COUNT 100 + + +/************************************************* +* Global variables * +*************************************************/ + +static char *pattern_filename = NULL; +static int pattern_count = 0; +static pcre **pattern_list; +static pcre_extra **hints_list; + +static BOOL count_only = FALSE; +static BOOL filenames = TRUE; +static BOOL filenames_only = FALSE; +static BOOL invert = FALSE; +static BOOL number = FALSE; +static BOOL recurse = FALSE; +static BOOL silent = FALSE; +static BOOL whole_lines = FALSE; + +/* Structure for options and list of them */ + +typedef struct option_item { + int one_char; + const char *long_name; + const char *help_text; +} option_item; + +static option_item optionlist[] = { + { -1, "help", "display this help and exit" }, + { 'c', "count", "print only a count of matching lines per FILE" }, + { 'h', "no-filename", "suppress the prefixing filename on output" }, + { 'i', "ignore-case", "ignore case distinctions" }, + { 'l', "files-with-matches", "print only FILE names containing matches" }, + { 'n', "line-number", "print line number with output lines" }, + { 'r', "recursive", "recursively scan sub-directories" }, + { 's', "no-messages", "suppress error messages" }, + { 'u', "utf-8", "use UTF-8 mode" }, + { 'V', "version", "print version information and exit" }, + { 'v', "invert-match", "select non-matching lines" }, + { 'x', "line-regex", "force PATTERN to match only whole lines" }, + { 'x', "line-regexp", "force PATTERN to match only whole lines" }, + { 0, NULL, NULL } +}; + + +/************************************************* +* Functions for directory scanning * +*************************************************/ + +/* These functions are defined so that they can be made system specific, +although at present the only ones are for Unix, Win32, and for "no directory +recursion support". */ + + +/************* Directory scanning in Unix ***********/ + +#if IS_UNIX +#include +#include +#include + +typedef DIR directory_type; + +static int +isdirectory(char *filename) +{ +struct stat statbuf; +if (stat(filename, &statbuf) < 0) + return 0; /* In the expectation that opening as a file will fail */ +return ((statbuf.st_mode & S_IFMT) == S_IFDIR)? '/' : 0; +} + +static directory_type * +opendirectory(char *filename) +{ +return opendir(filename); +} + +static char * +readdirectory(directory_type *dir) +{ +for (;;) + { + struct dirent *dent = readdir(dir); + if (dent == NULL) return NULL; + if (strcmp(dent->d_name, ".") != 0 && strcmp(dent->d_name, "..") != 0) + return dent->d_name; + } +return NULL; /* Keep compiler happy; never executed */ +} + +static void +closedirectory(directory_type *dir) +{ +closedir(dir); +} + + +/************* Directory scanning in Win32 ***********/ + +/* I (Philip Hazel) have no means of testing this code. It was contributed by +Lionel Fourquaux. */ + + +#elif HAVE_WIN32API + +#ifndef STRICT +# define STRICT +#endif +#ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#include + +typedef struct directory_type +{ +HANDLE handle; +BOOL first; +WIN32_FIND_DATA data; +} directory_type; + +int +isdirectory(char *filename) +{ +DWORD attr = GetFileAttributes(filename); +if (attr == INVALID_FILE_ATTRIBUTES) + return 0; +return ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) ? '/' : 0; +} + +directory_type * +opendirectory(char *filename) +{ +size_t len; +char *pattern; +directory_type *dir; +DWORD err; +len = strlen(filename); +pattern = (char *) malloc(len + 3); +dir = (directory_type *) malloc(sizeof(*dir)); +if ((pattern == NULL) || (dir == NULL)) + { + fprintf(stderr, "pcregrep: malloc failed\n"); + exit(2); + } +memcpy(pattern, filename, len); +memcpy(&(pattern[len]), "\\*", 3); +dir->handle = FindFirstFile(pattern, &(dir->data)); +if (dir->handle != INVALID_HANDLE_VALUE) + { + free(pattern); + dir->first = TRUE; + return dir; + } +err = GetLastError(); +free(pattern); +free(dir); +errno = (err == ERROR_ACCESS_DENIED) ? EACCES : ENOENT; +return NULL; +} + +char * +readdirectory(directory_type *dir) +{ +for (;;) + { + if (!dir->first) + { + if (!FindNextFile(dir->handle, &(dir->data))) + return NULL; + } + else + { + dir->first = FALSE; + } + if (strcmp(dir->data.cFileName, ".") != 0 && strcmp(dir->data.cFileName, "..") != 0) + return dir->data.cFileName; + } +#ifndef _MSC_VER +return NULL; /* Keep compiler happy; never executed */ +#endif +} + +void +closedirectory(directory_type *dir) +{ +FindClose(dir->handle); +free(dir); +} + + +/************* Directory scanning when we can't do it ***********/ + +/* The type is void, and apart from isdirectory(), the functions do nothing. */ + +#else + +typedef void directory_type; + +int isdirectory(char *filename) { return FALSE; } +directory_type * opendirectory(char *filename) {} +char *readdirectory(directory_type *dir) {} +void closedirectory(directory_type *dir) {} + +#endif + + + +#if ! HAVE_STRERROR +/************************************************* +* Provide strerror() for non-ANSI libraries * +*************************************************/ + +/* Some old-fashioned systems still around (e.g. SunOS4) don't have strerror() +in their libraries, but can provide the same facility by this simple +alternative function. */ + +extern int sys_nerr; +extern char *sys_errlist[]; + +char * +strerror(int n) +{ +if (n < 0 || n >= sys_nerr) return "unknown error number"; +return sys_errlist[n]; +} +#endif /* HAVE_STRERROR */ + + + +/************************************************* +* Grep an individual file * +*************************************************/ + +static int +pcregrep(FILE *in, char *name) +{ +int rc = 1; +int linenumber = 0; +int count = 0; +int offsets[99]; +char buffer[BUFSIZ]; + +while (fgets(buffer, sizeof(buffer), in) != NULL) + { + BOOL match = FALSE; + int i; + int length = (int)strlen(buffer); + if (length > 0 && buffer[length-1] == '\n') buffer[--length] = 0; + linenumber++; + + for (i = 0; !match && i < pattern_count; i++) + { + match = pcre_exec(pattern_list[i], hints_list[i], buffer, length, 0, 0, + offsets, 99) >= 0; + if (match && whole_lines && offsets[1] != length) match = FALSE; + } + + if (match != invert) + { + if (count_only) count++; + + else if (filenames_only) + { + fprintf(stdout, "%s\n", (name == NULL)? "" : name); + return 0; + } + + else if (silent) return 0; + + else + { + if (name != NULL) fprintf(stdout, "%s:", name); + if (number) fprintf(stdout, "%d:", linenumber); + fprintf(stdout, "%s\n", buffer); + } + + rc = 0; + } + } + +if (count_only) + { + if (name != NULL) fprintf(stdout, "%s:", name); + fprintf(stdout, "%d\n", count); + } + +return rc; +} + + + + +/************************************************* +* Grep a file or recurse into a directory * +*************************************************/ + +static int +grep_or_recurse(char *filename, BOOL dir_recurse, BOOL show_filenames, + BOOL only_one_at_top) +{ +int rc = 1; +int sep; +FILE *in; + +/* If the file is a directory and we are recursing, scan each file within it. +The scanning code is localized so it can be made system-specific. */ + +if ((sep = isdirectory(filename)) != 0 && dir_recurse) + { + char buffer[1024]; + char *nextfile; + directory_type *dir = opendirectory(filename); + + if (dir == NULL) + { + fprintf(stderr, "pcregrep: Failed to open directory %s: %s\n", filename, + strerror(errno)); + return 2; + } + + while ((nextfile = readdirectory(dir)) != NULL) + { + int frc; + sprintf(buffer, "%.512s%c%.128s", filename, sep, nextfile); + frc = grep_or_recurse(buffer, dir_recurse, TRUE, FALSE); + if (frc == 0 && rc == 1) rc = 0; + } + + closedirectory(dir); + return rc; + } + +/* If the file is not a directory, or we are not recursing, scan it. If this is +the first and only argument at top level, we don't show the file name (unless +we are only showing the file name). Otherwise, control is via the +show_filenames variable. */ + +in = fopen(filename, "r"); +if (in == NULL) + { + fprintf(stderr, "pcregrep: Failed to open %s: %s\n", filename, strerror(errno)); + return 2; + } + +rc = pcregrep(in, (filenames_only || (show_filenames && !only_one_at_top))? + filename : NULL); +fclose(in); +return rc; +} + + + + +/************************************************* +* Usage function * +*************************************************/ + +static int +usage(int rc) +{ +fprintf(stderr, "Usage: pcregrep [-Vcfhilnrsvx] [long-options] [pattern] [file1 file2 ...]\n"); +fprintf(stderr, "Type `pcregrep --help' for more information.\n"); +return rc; +} + + + + +/************************************************* +* Help function * +*************************************************/ + +static void +help(void) +{ +option_item *op; + +printf("Usage: pcregrep [OPTION]... [PATTERN] [FILE1 FILE2 ...]\n"); +printf("Search for PATTERN in each FILE or standard input.\n"); +printf("PATTERN must be present if -f is not used.\n"); +printf("Example: pcregrep -i 'hello.*world' menu.h main.c\n\n"); + +printf("Options:\n"); + +for (op = optionlist; op->one_char != 0; op++) + { + int n; + char s[4]; + if (op->one_char > 0) sprintf(s, "-%c,", op->one_char); else strcpy(s, " "); + printf(" %s --%s%n", s, op->long_name, &n); + n = 30 - n; + if (n < 1) n = 1; + printf("%.*s%s\n", n, " ", op->help_text); + } + +printf("\n -f or --file=\n"); +printf(" Read patterns from instead of using a command line option.\n"); +printf(" Trailing white space is removed; blanks lines are ignored.\n"); +printf(" There is a maximum of %d patterns.\n", MAX_PATTERN_COUNT); + +printf("\nWith no FILE, read standard input. If fewer than two FILEs given, assume -h.\n"); +printf("Exit status is 0 if any matches, 1 if no matches, and 2 if trouble.\n"); +} + + + + +/************************************************* +* Handle an option * +*************************************************/ + +static int +handle_option(int letter, int options) +{ +switch(letter) + { + case -1: help(); exit(0); + case 'c': count_only = TRUE; break; + case 'h': filenames = FALSE; break; + case 'i': options |= PCRE_CASELESS; break; + case 'l': filenames_only = TRUE; + case 'n': number = TRUE; break; + case 'r': recurse = TRUE; break; + case 's': silent = TRUE; break; + case 'u': options |= PCRE_UTF8; break; + case 'v': invert = TRUE; break; + case 'x': whole_lines = TRUE; options |= PCRE_ANCHORED; break; + + case 'V': + fprintf(stderr, "pcregrep version %s using ", VERSION); + fprintf(stderr, "PCRE version %s\n", pcre_version()); + exit(0); + break; + + default: + fprintf(stderr, "pcregrep: Unknown option -%c\n", letter); + exit(usage(2)); + } + +return options; +} + + + + +/************************************************* +* Main program * +*************************************************/ + +int +main(int argc, char **argv) +{ +int i, j; +int rc = 1; +int options = 0; +int errptr; +const char *error; +BOOL only_one_at_top; + +/* Process the options */ + +for (i = 1; i < argc; i++) + { + if (argv[i][0] != '-') break; + + /* Missing options */ + + if (argv[i][1] == 0) exit(usage(2)); + + /* Long name options */ + + if (argv[i][1] == '-') + { + option_item *op; + + if (strncmp(argv[i]+2, "file=", 5) == 0) + { + pattern_filename = argv[i] + 7; + continue; + } + + for (op = optionlist; op->one_char != 0; op++) + { + if (strcmp(argv[i]+2, op->long_name) == 0) + { + options = handle_option(op->one_char, options); + break; + } + } + if (op->one_char == 0) + { + fprintf(stderr, "pcregrep: Unknown option %s\n", argv[i]); + exit(usage(2)); + } + } + + /* One-char options */ + + else + { + char *s = argv[i] + 1; + while (*s != 0) + { + if (*s == 'f') + { + pattern_filename = s + 1; + if (pattern_filename[0] == 0) + { + if (i >= argc - 1) + { + fprintf(stderr, "pcregrep: File name missing after -f\n"); + exit(usage(2)); + } + pattern_filename = argv[++i]; + } + break; + } + else options = handle_option(*s++, options); + } + } + } + +pattern_list = malloc(MAX_PATTERN_COUNT * sizeof(pcre *)); +hints_list = malloc(MAX_PATTERN_COUNT * sizeof(pcre_extra *)); + +if (pattern_list == NULL || hints_list == NULL) + { + fprintf(stderr, "pcregrep: malloc failed\n"); + return 2; + } + +/* Compile the regular expression(s). */ + +if (pattern_filename != NULL) + { + FILE *f = fopen(pattern_filename, "r"); + char buffer[BUFSIZ]; + if (f == NULL) + { + fprintf(stderr, "pcregrep: Failed to open %s: %s\n", pattern_filename, + strerror(errno)); + return 2; + } + while (fgets(buffer, sizeof(buffer), f) != NULL) + { + char *s = buffer + (int)strlen(buffer); + if (pattern_count >= MAX_PATTERN_COUNT) + { + fprintf(stderr, "pcregrep: Too many patterns in file (max %d)\n", + MAX_PATTERN_COUNT); + return 2; + } + while (s > buffer && isspace((unsigned char)(s[-1]))) s--; + if (s == buffer) continue; + *s = 0; + pattern_list[pattern_count] = pcre_compile(buffer, options, &error, + &errptr, NULL); + if (pattern_list[pattern_count++] == NULL) + { + fprintf(stderr, "pcregrep: Error in regex number %d at offset %d: %s\n", + pattern_count, errptr, error); + return 2; + } + } + fclose(f); + } + +/* If no file name, a single regex must be given inline */ + +else + { + if (i >= argc) return usage(2); + pattern_list[0] = pcre_compile(argv[i++], options, &error, &errptr, NULL); + if (pattern_list[0] == NULL) + { + fprintf(stderr, "pcregrep: Error in regex at offset %d: %s\n", errptr, + error); + return 2; + } + pattern_count++; + } + +/* Study the regular expressions, as we will be running them may times */ + +for (j = 0; j < pattern_count; j++) + { + hints_list[j] = pcre_study(pattern_list[j], 0, &error); + if (error != NULL) + { + char s[16]; + if (pattern_count == 1) s[0] = 0; else sprintf(s, " number %d", j); + fprintf(stderr, "pcregrep: Error while studying regex%s: %s\n", s, error); + return 2; + } + } + +/* If there are no further arguments, do the business on stdin and exit */ + +if (i >= argc) return pcregrep(stdin, NULL); + +/* Otherwise, work through the remaining arguments as files or directories. +Pass in the fact that there is only one argument at top level - this suppresses +the file name if the argument is not a directory. */ + +only_one_at_top = (i == argc - 1); +if (filenames_only) filenames = TRUE; + +for (; i < argc; i++) + { + int frc = grep_or_recurse(argv[i], recurse, filenames, only_one_at_top); + if (frc == 0 && rc == 1) rc = 0; + } + +return rc; +} + +/* End */ diff --git a/mk4/continuity/pcre/pcreposix.c b/mk4/continuity/pcre/pcreposix.c new file mode 100644 index 0000000..49094f2 --- /dev/null +++ b/mk4/continuity/pcre/pcreposix.c @@ -0,0 +1,301 @@ +/************************************************* +* Perl-Compatible Regular Expressions * +*************************************************/ + +/* +This is a library of functions to support regular expressions whose syntax +and semantics are as close as possible to those of the Perl 5 language. See +the file Tech.Notes for some information on the internals. + +This module is a wrapper that provides a POSIX API to the underlying PCRE +functions. + +Written by: Philip Hazel + + Copyright (c) 1997-2003 University of Cambridge + +----------------------------------------------------------------------------- +Permission is granted to anyone to use this software for any purpose on any +computer system, and to redistribute it freely, subject to the following +restrictions: + +1. This software 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. + +2. The origin of this software must not be misrepresented, either by + explicit claim or by omission. + +3. Altered versions must be plainly marked as such, and must not be + misrepresented as being the original software. + +4. If PCRE is embedded in any software that is released under the GNU + General Purpose Licence (GPL), then the terms of that licence shall + supersede any condition above with which it is incompatible. +----------------------------------------------------------------------------- +*/ + +#include "internal.h" +#include "pcreposix.h" +#include "stdlib.h" + + + +/* Corresponding tables of PCRE error messages and POSIX error codes. */ + +static const char *estring[] = { + ERR1, ERR2, ERR3, ERR4, ERR5, ERR6, ERR7, ERR8, ERR9, ERR10, + ERR11, ERR12, ERR13, ERR14, ERR15, ERR16, ERR17, ERR18, ERR19, ERR20, + ERR21, ERR22, ERR23, ERR24, ERR25, ERR26, ERR27, ERR29, ERR29, ERR30, + ERR31, ERR32, ERR33, ERR34, ERR35, ERR36, ERR37, ERR38, ERR39, ERR40, + ERR41, ERR42, ERR43 }; + +static int eint[] = { + REG_EESCAPE, /* "\\ at end of pattern" */ + REG_EESCAPE, /* "\\c at end of pattern" */ + REG_EESCAPE, /* "unrecognized character follows \\" */ + REG_BADBR, /* "numbers out of order in {} quantifier" */ + REG_BADBR, /* "number too big in {} quantifier" */ + REG_EBRACK, /* "missing terminating ] for character class" */ + REG_ECTYPE, /* "invalid escape sequence in character class" */ + REG_ERANGE, /* "range out of order in character class" */ + REG_BADRPT, /* "nothing to repeat" */ + REG_BADRPT, /* "operand of unlimited repeat could match the empty string" */ + REG_ASSERT, /* "internal error: unexpected repeat" */ + REG_BADPAT, /* "unrecognized character after (?" */ + REG_BADPAT, /* "POSIX named classes are supported only within a class" */ + REG_EPAREN, /* "missing )" */ + REG_ESUBREG, /* "reference to non-existent subpattern" */ + REG_INVARG, /* "erroffset passed as NULL" */ + REG_INVARG, /* "unknown option bit(s) set" */ + REG_EPAREN, /* "missing ) after comment" */ + REG_ESIZE, /* "parentheses nested too deeply" */ + REG_ESIZE, /* "regular expression too large" */ + REG_ESPACE, /* "failed to get memory" */ + REG_EPAREN, /* "unmatched brackets" */ + REG_ASSERT, /* "internal error: code overflow" */ + REG_BADPAT, /* "unrecognized character after (?<" */ + REG_BADPAT, /* "lookbehind assertion is not fixed length" */ + REG_BADPAT, /* "malformed number after (?(" */ + REG_BADPAT, /* "conditional group containe more than two branches" */ + REG_BADPAT, /* "assertion expected after (?(" */ + REG_BADPAT, /* "(?R or (?digits must be followed by )" */ + REG_ECTYPE, /* "unknown POSIX class name" */ + REG_BADPAT, /* "POSIX collating elements are not supported" */ + REG_INVARG, /* "this version of PCRE is not compiled with PCRE_UTF8 support" */ + REG_BADPAT, /* "spare error" */ + REG_BADPAT, /* "character value in \x{...} sequence is too large" */ + REG_BADPAT, /* "invalid condition (?(0)" */ + REG_BADPAT, /* "\\C not allowed in lookbehind assertion" */ + REG_EESCAPE, /* "PCRE does not support \\L, \\l, \\N, \\P, \\p, \\U, \\u, or \\X" */ + REG_BADPAT, /* "number after (?C is > 255" */ + REG_BADPAT, /* "closing ) for (?C expected" */ + REG_BADPAT, /* "recursive call could loop indefinitely" */ + REG_BADPAT, /* "unrecognized character after (?P" */ + REG_BADPAT, /* "syntax error after (?P" */ + REG_BADPAT /* "two named groups have the same name" */ +}; + +/* Table of texts corresponding to POSIX error codes */ + +static const char *pstring[] = { + "", /* Dummy for value 0 */ + "internal error", /* REG_ASSERT */ + "invalid repeat counts in {}", /* BADBR */ + "pattern error", /* BADPAT */ + "? * + invalid", /* BADRPT */ + "unbalanced {}", /* EBRACE */ + "unbalanced []", /* EBRACK */ + "collation error - not relevant", /* ECOLLATE */ + "bad class", /* ECTYPE */ + "bad escape sequence", /* EESCAPE */ + "empty expression", /* EMPTY */ + "unbalanced ()", /* EPAREN */ + "bad range inside []", /* ERANGE */ + "expression too big", /* ESIZE */ + "failed to get memory", /* ESPACE */ + "bad back reference", /* ESUBREG */ + "bad argument", /* INVARG */ + "match failed" /* NOMATCH */ +}; + + + + +/************************************************* +* Translate PCRE text code to int * +*************************************************/ + +/* PCRE compile-time errors are given as strings defined as macros. We can just +look them up in a table to turn them into POSIX-style error codes. */ + +static int +pcre_posix_error_code(const char *s) +{ +size_t i; +for (i = 0; i < sizeof(estring)/sizeof(char *); i++) + if (strcmp(s, estring[i]) == 0) return eint[i]; +return REG_ASSERT; +} + + + +/************************************************* +* Translate error code to string * +*************************************************/ + +size_t +regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size) +{ +const char *message, *addmessage; +size_t length, addlength; + +message = (errcode >= (int)(sizeof(pstring)/sizeof(char *)))? + "unknown error code" : pstring[errcode]; +length = strlen(message) + 1; + +addmessage = " at offset "; +addlength = (preg != NULL && (int)preg->re_erroffset != -1)? + strlen(addmessage) + 6 : 0; + +if (errbuf_size > 0) + { + if (addlength > 0 && errbuf_size >= length + addlength) + sprintf(errbuf, "%s%s%-6d", message, addmessage, (int)preg->re_erroffset); + else + { + strncpy(errbuf, message, errbuf_size - 1); + errbuf[errbuf_size-1] = 0; + } + } + +return length + addlength; +} + + + + +/************************************************* +* Free store held by a regex * +*************************************************/ + +void +regfree(regex_t *preg) +{ +(pcre_free)(preg->re_pcre); +} + + + + +/************************************************* +* Compile a regular expression * +*************************************************/ + +/* +Arguments: + preg points to a structure for recording the compiled expression + pattern the pattern to compile + cflags compilation flags + +Returns: 0 on success + various non-zero codes on failure +*/ + +int +regcomp(regex_t *preg, const char *pattern, int cflags) +{ +const char *errorptr; +int erroffset; +int options = 0; + +if ((cflags & REG_ICASE) != 0) options |= PCRE_CASELESS; +if ((cflags & REG_NEWLINE) != 0) options |= PCRE_MULTILINE; + +preg->re_pcre = pcre_compile(pattern, options, &errorptr, &erroffset, NULL); +preg->re_erroffset = erroffset; + +if (preg->re_pcre == NULL) return pcre_posix_error_code(errorptr); + +preg->re_nsub = pcre_info(preg->re_pcre, NULL, NULL); +return 0; +} + + + + +/************************************************* +* Match a regular expression * +*************************************************/ + +/* Unfortunately, PCRE requires 3 ints of working space for each captured +substring, so we have to get and release working store instead of just using +the POSIX structures as was done in earlier releases when PCRE needed only 2 +ints. However, if the number of possible capturing brackets is small, use a +block of store on the stack, to reduce the use of malloc/free. The threshold is +in a macro that can be changed at configure time. */ + +int +regexec(const regex_t *preg, const char *string, size_t nmatch, + regmatch_t pmatch[], int eflags) +{ +int rc; +int options = 0; +int *ovector = NULL; +int small_ovector[POSIX_MALLOC_THRESHOLD * 3]; +BOOL allocated_ovector = FALSE; + +if ((eflags & REG_NOTBOL) != 0) options |= PCRE_NOTBOL; +if ((eflags & REG_NOTEOL) != 0) options |= PCRE_NOTEOL; + +((regex_t *)preg)->re_erroffset = (size_t)(-1); /* Only has meaning after compile */ + +if (nmatch > 0) + { + if (nmatch <= POSIX_MALLOC_THRESHOLD) + { + ovector = &(small_ovector[0]); + } + else + { + ovector = (int *)malloc(sizeof(int) * nmatch * 3); + if (ovector == NULL) return REG_ESPACE; + allocated_ovector = TRUE; + } + } + +rc = pcre_exec(preg->re_pcre, NULL, string, (int)strlen(string), 0, options, + ovector, nmatch * 3); + +if (rc == 0) rc = nmatch; /* All captured slots were filled in */ + +if (rc >= 0) + { + size_t i; + for (i = 0; i < (size_t)rc; i++) + { + pmatch[i].rm_so = ovector[i*2]; + pmatch[i].rm_eo = ovector[i*2+1]; + } + if (allocated_ovector) free(ovector); + for (; i < nmatch; i++) pmatch[i].rm_so = pmatch[i].rm_eo = -1; + return 0; + } + +else + { + if (allocated_ovector) free(ovector); + switch(rc) + { + case PCRE_ERROR_NOMATCH: return REG_NOMATCH; + case PCRE_ERROR_NULL: return REG_INVARG; + case PCRE_ERROR_BADOPTION: return REG_INVARG; + case PCRE_ERROR_BADMAGIC: return REG_INVARG; + case PCRE_ERROR_UNKNOWN_NODE: return REG_ASSERT; + case PCRE_ERROR_NOMEMORY: return REG_ESPACE; + default: return REG_ASSERT; + } + } +} + +/* End of pcreposix.c */ diff --git a/mk4/continuity/pcre/pcreposix.h b/mk4/continuity/pcre/pcreposix.h new file mode 100644 index 0000000..2b97bf4 --- /dev/null +++ b/mk4/continuity/pcre/pcreposix.h @@ -0,0 +1,88 @@ +/************************************************* +* Perl-Compatible Regular Expressions * +*************************************************/ + +/* Copyright (c) 1997-2003 University of Cambridge */ + +#ifndef _PCREPOSIX_H +#define _PCREPOSIX_H + +/* This is the header for the POSIX wrapper interface to the PCRE Perl- +Compatible Regular Expression library. It defines the things POSIX says should +be there. I hope. */ + +/* Have to include stdlib.h in order to ensure that size_t is defined. */ + +#include + +/* Allow for C++ users */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Options defined by POSIX. */ + +#define REG_ICASE 0x01 +#define REG_NEWLINE 0x02 +#define REG_NOTBOL 0x04 +#define REG_NOTEOL 0x08 + +/* These are not used by PCRE, but by defining them we make it easier +to slot PCRE into existing programs that make POSIX calls. */ + +#define REG_EXTENDED 0 +#define REG_NOSUB 0 + +/* Error values. Not all these are relevant or used by the wrapper. */ + +enum { + REG_ASSERT = 1, /* internal error ? */ + REG_BADBR, /* invalid repeat counts in {} */ + REG_BADPAT, /* pattern error */ + REG_BADRPT, /* ? * + invalid */ + REG_EBRACE, /* unbalanced {} */ + REG_EBRACK, /* unbalanced [] */ + REG_ECOLLATE, /* collation error - not relevant */ + REG_ECTYPE, /* bad class */ + REG_EESCAPE, /* bad escape sequence */ + REG_EMPTY, /* empty expression */ + REG_EPAREN, /* unbalanced () */ + REG_ERANGE, /* bad range inside [] */ + REG_ESIZE, /* expression too big */ + REG_ESPACE, /* failed to get memory */ + REG_ESUBREG, /* bad back reference */ + REG_INVARG, /* bad argument */ + REG_NOMATCH /* match failed */ +}; + + +/* The structure representing a compiled regular expression. */ + +typedef struct { + void *re_pcre; + size_t re_nsub; + size_t re_erroffset; +} regex_t; + +/* The structure in which a captured offset is returned. */ + +typedef int regoff_t; + +typedef struct { + regoff_t rm_so; + regoff_t rm_eo; +} regmatch_t; + +/* The functions */ + +extern int regcomp(regex_t *, const char *, int); +extern int regexec(const regex_t *, const char *, size_t, regmatch_t *, int); +extern size_t regerror(int, const regex_t *, char *, size_t); +extern void regfree(regex_t *); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* End of pcreposix.h */ diff --git a/mk4/continuity/pcre/pcretest.c b/mk4/continuity/pcre/pcretest.c new file mode 100644 index 0000000..ad729b7 --- /dev/null +++ b/mk4/continuity/pcre/pcretest.c @@ -0,0 +1,1421 @@ +/************************************************* +* PCRE testing program * +*************************************************/ + +/* This program was hacked up as a tester for PCRE. I really should have +written it more tidily in the first place. Will I ever learn? It has grown and +been extended and consequently is now rather untidy in places. */ + +#include +#include +#include +#include +#include +#include + +/* We need the internal info for displaying the results of pcre_study(). Also +for getting the opcodes for showing compiled code. */ + +#define PCRE_SPY /* For Win32 build, import data, not export */ +#include "internal.h" + +/* It is possible to compile this test program without including support for +testing the POSIX interface, though this is not available via the standard +Makefile. */ + +#if !defined NOPOSIX +#include "pcreposix.h" +#endif + +#ifndef CLOCKS_PER_SEC +#ifdef CLK_TCK +#define CLOCKS_PER_SEC CLK_TCK +#else +#define CLOCKS_PER_SEC 100 +#endif +#endif + +#define LOOPREPEAT 50000 + +#define BUFFER_SIZE 30000 +#define DBUFFER_SIZE 1024 + + +static FILE *outfile; +static int log_store = 0; +static int callout_count; +static int callout_extra; +static int callout_fail_count; +static int callout_fail_id; +static int first_callout; +static int use_utf8; +static size_t gotten_store; + + + +static const int utf8_table1[] = { + 0x0000007f, 0x000007ff, 0x0000ffff, 0x001fffff, 0x03ffffff, 0x7fffffff}; + +static const int utf8_table2[] = { + 0, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc}; + +static const int utf8_table3[] = { + 0xff, 0x1f, 0x0f, 0x07, 0x03, 0x01}; + + + +/************************************************* +* Print compiled regex * +*************************************************/ + +/* The code for doing this is held in a separate file that is also included in +pcre.c when it is compiled with the debug switch. It defines a function called +print_internals(), which uses a table of opcode lengths defined by the macro +OP_LENGTHS, whose name must be OP_lengths. */ + +static uschar OP_lengths[] = { OP_LENGTHS }; + +#include "printint.c" + + + +/************************************************* +* Read number from string * +*************************************************/ + +/* We don't use strtoul() because SunOS4 doesn't have it. Rather than mess +around with conditional compilation, just do the job by hand. It is only used +for unpicking the -o argument, so just keep it simple. + +Arguments: + str string to be converted + endptr where to put the end pointer + +Returns: the unsigned long +*/ + +static int +get_value(unsigned char *str, unsigned char **endptr) +{ +int result = 0; +while(*str != 0 && isspace(*str)) str++; +while (isdigit(*str)) result = result * 10 + (int)(*str++ - '0'); +*endptr = str; +return(result); +} + + + +/************************************************* +* Convert character value to UTF-8 * +*************************************************/ + +/* This function takes an integer value in the range 0 - 0x7fffffff +and encodes it as a UTF-8 character in 0 to 6 bytes. + +Arguments: + cvalue the character value + buffer pointer to buffer for result - at least 6 bytes long + +Returns: number of characters placed in the buffer + -1 if input character is negative + 0 if input character is positive but too big (only when + int is longer than 32 bits) +*/ + +static int +ord2utf8(int cvalue, unsigned char *buffer) +{ +register int i, j; +for (i = 0; i < sizeof(utf8_table1)/sizeof(int); i++) + if (cvalue <= utf8_table1[i]) break; +if (i >= sizeof(utf8_table1)/sizeof(int)) return 0; +if (cvalue < 0) return -1; + +buffer += i; +for (j = i; j > 0; j--) + { + *buffer-- = 0x80 | (cvalue & 0x3f); + cvalue >>= 6; + } +*buffer = utf8_table2[i] | cvalue; +return i + 1; +} + + +/************************************************* +* Convert UTF-8 string to value * +*************************************************/ + +/* This function takes one or more bytes that represents a UTF-8 character, +and returns the value of the character. + +Argument: + buffer a pointer to the byte vector + vptr a pointer to an int to receive the value + +Returns: > 0 => the number of bytes consumed + -6 to 0 => malformed UTF-8 character at offset = (-return) +*/ + +static int +utf82ord(unsigned char *buffer, int *vptr) +{ +int c = *buffer++; +int d = c; +int i, j, s; + +for (i = -1; i < 6; i++) /* i is number of additional bytes */ + { + if ((d & 0x80) == 0) break; + d <<= 1; + } + +if (i == -1) { *vptr = c; return 1; } /* ascii character */ +if (i == 0 || i == 6) return 0; /* invalid UTF-8 */ + +/* i now has a value in the range 1-5 */ + +s = 6*i; +d = (c & utf8_table3[i]) << s; + +for (j = 0; j < i; j++) + { + c = *buffer++; + if ((c & 0xc0) != 0x80) return -(j+1); + s -= 6; + d |= (c & 0x3f) << s; + } + +/* Check that encoding was the correct unique one */ + +for (j = 0; j < sizeof(utf8_table1)/sizeof(int); j++) + if (d <= utf8_table1[j]) break; +if (j != i) return -(i+1); + +/* Valid value */ + +*vptr = d; +return i+1; +} + + + +/************************************************* +* Print character string * +*************************************************/ + +/* Character string printing function. Must handle UTF-8 strings in utf8 +mode. Yields number of characters printed. If handed a NULL file, just counts +chars without printing. */ + +static int pchars(unsigned char *p, int length, FILE *f) +{ +int c; +int yield = 0; + +while (length-- > 0) + { + if (use_utf8) + { + int rc = utf82ord(p, &c); + + if (rc > 0 && rc <= length + 1) /* Mustn't run over the end */ + { + length -= rc - 1; + p += rc; + if (c < 256 && isprint(c)) + { + if (f != NULL) fprintf(f, "%c", c); + yield++; + } + else + { + int n; + if (f != NULL) fprintf(f, "\\x{%02x}%n", c, &n); + yield += n; + } + continue; + } + } + + /* Not UTF-8, or malformed UTF-8 */ + + if (isprint(c = *(p++))) + { + if (f != NULL) fprintf(f, "%c", c); + yield++; + } + else + { + if (f != NULL) fprintf(f, "\\x%02x", c); + yield += 4; + } + } + +return yield; +} + + + +/************************************************* +* Callout function * +*************************************************/ + +/* Called from PCRE as a result of the (?C) item. We print out where we are in +the match. Yield zero unless more callouts than the fail count, or the callout +data is not zero. */ + +static int callout(pcre_callout_block *cb) +{ +FILE *f = (first_callout | callout_extra)? outfile : NULL; +int i, pre_start, post_start; + +if (callout_extra) + { + fprintf(f, "Callout %d: last capture = %d\n", + cb->callout_number, cb->capture_last); + + for (i = 0; i < cb->capture_top * 2; i += 2) + { + if (cb->offset_vector[i] < 0) + fprintf(f, "%2d: \n", i/2); + else + { + fprintf(f, "%2d: ", i/2); + (void)pchars((unsigned char *)cb->subject + cb->offset_vector[i], + cb->offset_vector[i+1] - cb->offset_vector[i], f); + fprintf(f, "\n"); + } + } + } + +/* Re-print the subject in canonical form, the first time or if giving full +datails. On subsequent calls in the same match, we use pchars just to find the +printed lengths of the substrings. */ + +if (f != NULL) fprintf(f, "--->"); + +pre_start = pchars((unsigned char *)cb->subject, cb->start_match, f); +post_start = pchars((unsigned char *)(cb->subject + cb->start_match), + cb->current_position - cb->start_match, f); + +(void)pchars((unsigned char *)(cb->subject + cb->current_position), + cb->subject_length - cb->current_position, f); + +if (f != NULL) fprintf(f, "\n"); + +/* Always print appropriate indicators, with callout number if not already +shown */ + +if (callout_extra) fprintf(outfile, " "); + else fprintf(outfile, "%3d ", cb->callout_number); + +for (i = 0; i < pre_start; i++) fprintf(outfile, " "); +fprintf(outfile, "^"); + +if (post_start > 0) + { + for (i = 0; i < post_start - 1; i++) fprintf(outfile, " "); + fprintf(outfile, "^"); + } + +fprintf(outfile, "\n"); + +first_callout = 0; + +if ((int)(cb->callout_data) != 0) + { + fprintf(outfile, "Callout data = %d\n", (int)(cb->callout_data)); + return (int)(cb->callout_data); + } + +return (cb->callout_number != callout_fail_id)? 0 : + (++callout_count >= callout_fail_count)? 1 : 0; +} + + +/************************************************* +* Local malloc function * +*************************************************/ + +/* Alternative malloc function, to test functionality and show the size of the +compiled re. */ + +static void *new_malloc(size_t size) +{ +gotten_store = size; +return malloc(size); +} + + + +/************************************************* +* Call pcre_fullinfo() * +*************************************************/ + +/* Get one piece of information from the pcre_fullinfo() function */ + +static void new_info(pcre *re, pcre_extra *study, int option, void *ptr) +{ +int rc; +if ((rc = pcre_fullinfo(re, study, option, ptr)) < 0) + fprintf(outfile, "Error %d from pcre_fullinfo(%d)\n", rc, option); +} + + + +/************************************************* +* Main Program * +*************************************************/ + +/* Read lines from named file or stdin and write to named file or stdout; lines +consist of a regular expression, in delimiters and optionally followed by +options, followed by a set of test data, terminated by an empty line. */ + +int main(int argc, char **argv) +{ +FILE *infile = stdin; +int options = 0; +int study_options = 0; +int op = 1; +int timeit = 0; +int showinfo = 0; +int showstore = 0; +int size_offsets = 45; +int size_offsets_max; +int *offsets; +#if !defined NOPOSIX +int posix = 0; +#endif +int debug = 0; +int done = 0; + +unsigned char *buffer; +unsigned char *dbuffer; + +/* Get buffers from malloc() so that Electric Fence will check their misuse +when I am debugging. */ + +buffer = malloc(BUFFER_SIZE); +dbuffer = malloc(DBUFFER_SIZE); + +/* Static so that new_malloc can use it. */ + +outfile = stdout; + +/* Scan options */ + +while (argc > 1 && argv[op][0] == '-') + { + unsigned char *endptr; + + if (strcmp(argv[op], "-s") == 0 || strcmp(argv[op], "-m") == 0) + showstore = 1; + else if (strcmp(argv[op], "-t") == 0) timeit = 1; + else if (strcmp(argv[op], "-i") == 0) showinfo = 1; + else if (strcmp(argv[op], "-d") == 0) showinfo = debug = 1; + else if (strcmp(argv[op], "-o") == 0 && argc > 2 && + ((size_offsets = get_value((unsigned char *)argv[op+1], &endptr)), + *endptr == 0)) + { + op++; + argc--; + } +#if !defined NOPOSIX + else if (strcmp(argv[op], "-p") == 0) posix = 1; +#endif + else if (strcmp(argv[op], "-C") == 0) + { + int rc; + printf("PCRE version %s\n", pcre_version()); + printf("Compiled with\n"); + (void)pcre_config(PCRE_CONFIG_UTF8, &rc); + printf(" %sUTF-8 support\n", rc? "" : "No "); + (void)pcre_config(PCRE_CONFIG_NEWLINE, &rc); + printf(" Newline character is %s\n", (rc == '\r')? "CR" : "LF"); + (void)pcre_config(PCRE_CONFIG_LINK_SIZE, &rc); + printf(" Internal link size = %d\n", rc); + (void)pcre_config(PCRE_CONFIG_POSIX_MALLOC_THRESHOLD, &rc); + printf(" POSIX malloc threshold = %d\n", rc); + (void)pcre_config(PCRE_CONFIG_MATCH_LIMIT, &rc); + printf(" Default match limit = %d\n", rc); + exit(0); + } + else + { + printf("** Unknown or malformed option %s\n", argv[op]); + printf("Usage: pcretest [-d] [-i] [-o ] [-p] [-s] [-t] [ []]\n"); + printf(" -C show PCRE compile-time options and exit\n"); + printf(" -d debug: show compiled code; implies -i\n" + " -i show information about compiled pattern\n" + " -o set size of offsets vector to \n"); +#if !defined NOPOSIX + printf(" -p use POSIX interface\n"); +#endif + printf(" -s output store information\n" + " -t time compilation and execution\n"); + return 1; + } + op++; + argc--; + } + +/* Get the store for the offsets vector, and remember what it was */ + +size_offsets_max = size_offsets; +offsets = malloc(size_offsets_max * sizeof(int)); +if (offsets == NULL) + { + printf("** Failed to get %d bytes of memory for offsets vector\n", + size_offsets_max * sizeof(int)); + return 1; + } + +/* Sort out the input and output files */ + +if (argc > 1) + { + infile = fopen(argv[op], "r"); + if (infile == NULL) + { + printf("** Failed to open %s\n", argv[op]); + return 1; + } + } + +if (argc > 2) + { + outfile = fopen(argv[op+1], "w"); + if (outfile == NULL) + { + printf("** Failed to open %s\n", argv[op+1]); + return 1; + } + } + +/* Set alternative malloc function */ + +pcre_malloc = new_malloc; + +/* Heading line, then prompt for first regex if stdin */ + +fprintf(outfile, "PCRE version %s\n\n", pcre_version()); + +/* Main loop */ + +while (!done) + { + pcre *re = NULL; + pcre_extra *extra = NULL; + +#if !defined NOPOSIX /* There are still compilers that require no indent */ + regex_t preg; + int do_posix = 0; +#endif + + const char *error; + unsigned char *p, *pp, *ppp; + const unsigned char *tables = NULL; + int do_study = 0; + int do_debug = debug; + int do_G = 0; + int do_g = 0; + int do_showinfo = showinfo; + int do_showrest = 0; + int erroroffset, len, delimiter; + + use_utf8 = 0; + + if (infile == stdin) printf(" re> "); + if (fgets((char *)buffer, BUFFER_SIZE, infile) == NULL) break; + if (infile != stdin) fprintf(outfile, "%s", (char *)buffer); + fflush(outfile); + + p = buffer; + while (isspace(*p)) p++; + if (*p == 0) continue; + + /* Get the delimiter and seek the end of the pattern; if is isn't + complete, read more. */ + + delimiter = *p++; + + if (isalnum(delimiter) || delimiter == '\\') + { + fprintf(outfile, "** Delimiter must not be alphameric or \\\n"); + goto SKIP_DATA; + } + + pp = p; + + for(;;) + { + while (*pp != 0) + { + if (*pp == '\\' && pp[1] != 0) pp++; + else if (*pp == delimiter) break; + pp++; + } + if (*pp != 0) break; + + len = BUFFER_SIZE - (pp - buffer); + if (len < 256) + { + fprintf(outfile, "** Expression too long - missing delimiter?\n"); + goto SKIP_DATA; + } + + if (infile == stdin) printf(" > "); + if (fgets((char *)pp, len, infile) == NULL) + { + fprintf(outfile, "** Unexpected EOF\n"); + done = 1; + goto CONTINUE; + } + if (infile != stdin) fprintf(outfile, "%s", (char *)pp); + } + + /* If the first character after the delimiter is backslash, make + the pattern end with backslash. This is purely to provide a way + of testing for the error message when a pattern ends with backslash. */ + + if (pp[1] == '\\') *pp++ = '\\'; + + /* Terminate the pattern at the delimiter */ + + *pp++ = 0; + + /* Look for options after final delimiter */ + + options = 0; + study_options = 0; + log_store = showstore; /* default from command line */ + + while (*pp != 0) + { + switch (*pp++) + { + case 'g': do_g = 1; break; + case 'i': options |= PCRE_CASELESS; break; + case 'm': options |= PCRE_MULTILINE; break; + case 's': options |= PCRE_DOTALL; break; + case 'x': options |= PCRE_EXTENDED; break; + + case '+': do_showrest = 1; break; + case 'A': options |= PCRE_ANCHORED; break; + case 'D': do_debug = do_showinfo = 1; break; + case 'E': options |= PCRE_DOLLAR_ENDONLY; break; + case 'G': do_G = 1; break; + case 'I': do_showinfo = 1; break; + case 'M': log_store = 1; break; + case 'N': options |= PCRE_NO_AUTO_CAPTURE; break; + +#if !defined NOPOSIX + case 'P': do_posix = 1; break; +#endif + + case 'S': do_study = 1; break; + case 'U': options |= PCRE_UNGREEDY; break; + case 'X': options |= PCRE_EXTRA; break; + case '8': options |= PCRE_UTF8; use_utf8 = 1; break; + + case 'L': + ppp = pp; + while (*ppp != '\n' && *ppp != ' ') ppp++; + *ppp = 0; + if (setlocale(LC_CTYPE, (const char *)pp) == NULL) + { + fprintf(outfile, "** Failed to set locale \"%s\"\n", pp); + goto SKIP_DATA; + } + tables = pcre_maketables(); + pp = ppp; + break; + + case '\n': case ' ': break; + default: + fprintf(outfile, "** Unknown option '%c'\n", pp[-1]); + goto SKIP_DATA; + } + } + + /* Handle compiling via the POSIX interface, which doesn't support the + timing, showing, or debugging options, nor the ability to pass over + local character tables. */ + +#if !defined NOPOSIX + if (posix || do_posix) + { + int rc; + int cflags = 0; + if ((options & PCRE_CASELESS) != 0) cflags |= REG_ICASE; + if ((options & PCRE_MULTILINE) != 0) cflags |= REG_NEWLINE; + rc = regcomp(&preg, (char *)p, cflags); + + /* Compilation failed; go back for another re, skipping to blank line + if non-interactive. */ + + if (rc != 0) + { + (void)regerror(rc, &preg, (char *)buffer, BUFFER_SIZE); + fprintf(outfile, "Failed: POSIX code %d: %s\n", rc, buffer); + goto SKIP_DATA; + } + } + + /* Handle compiling via the native interface */ + + else +#endif /* !defined NOPOSIX */ + + { + if (timeit) + { + register int i; + clock_t time_taken; + clock_t start_time = clock(); + for (i = 0; i < LOOPREPEAT; i++) + { + re = pcre_compile((char *)p, options, &error, &erroroffset, tables); + if (re != NULL) free(re); + } + time_taken = clock() - start_time; + fprintf(outfile, "Compile time %.3f milliseconds\n", + (((double)time_taken * 1000.0) / (double)LOOPREPEAT) / + (double)CLOCKS_PER_SEC); + } + + re = pcre_compile((char *)p, options, &error, &erroroffset, tables); + + /* Compilation failed; go back for another re, skipping to blank line + if non-interactive. */ + + if (re == NULL) + { + fprintf(outfile, "Failed: %s at offset %d\n", error, erroroffset); + SKIP_DATA: + if (infile != stdin) + { + for (;;) + { + if (fgets((char *)buffer, BUFFER_SIZE, infile) == NULL) + { + done = 1; + goto CONTINUE; + } + len = (int)strlen((char *)buffer); + while (len > 0 && isspace(buffer[len-1])) len--; + if (len == 0) break; + } + fprintf(outfile, "\n"); + } + goto CONTINUE; + } + + /* Compilation succeeded; print data if required. There are now two + info-returning functions. The old one has a limited interface and + returns only limited data. Check that it agrees with the newer one. */ + + if (log_store) + fprintf(outfile, "Memory allocation (code space): %d\n", + (int)(gotten_store - + sizeof(real_pcre) - + ((real_pcre *)re)->name_count * ((real_pcre *)re)->name_entry_size)); + + if (do_showinfo) + { + unsigned long int get_options; + int old_first_char, old_options, old_count; + int count, backrefmax, first_char, need_char; + int nameentrysize, namecount; + const uschar *nametable; + size_t size; + + if (do_debug) + { + fprintf(outfile, "------------------------------------------------------------------\n"); + print_internals(re, outfile); + } + + new_info(re, NULL, PCRE_INFO_OPTIONS, &get_options); + new_info(re, NULL, PCRE_INFO_SIZE, &size); + new_info(re, NULL, PCRE_INFO_CAPTURECOUNT, &count); + new_info(re, NULL, PCRE_INFO_BACKREFMAX, &backrefmax); + new_info(re, NULL, PCRE_INFO_FIRSTBYTE, &first_char); + new_info(re, NULL, PCRE_INFO_LASTLITERAL, &need_char); + new_info(re, NULL, PCRE_INFO_NAMEENTRYSIZE, &nameentrysize); + new_info(re, NULL, PCRE_INFO_NAMECOUNT, &namecount); + new_info(re, NULL, PCRE_INFO_NAMETABLE, (void *)&nametable); + + old_count = pcre_info(re, &old_options, &old_first_char); + if (count < 0) fprintf(outfile, + "Error %d from pcre_info()\n", count); + else + { + if (old_count != count) fprintf(outfile, + "Count disagreement: pcre_fullinfo=%d pcre_info=%d\n", count, + old_count); + + if (old_first_char != first_char) fprintf(outfile, + "First char disagreement: pcre_fullinfo=%d pcre_info=%d\n", + first_char, old_first_char); + + if (old_options != (int)get_options) fprintf(outfile, + "Options disagreement: pcre_fullinfo=%ld pcre_info=%d\n", + get_options, old_options); + } + + if (size != gotten_store) fprintf(outfile, + "Size disagreement: pcre_fullinfo=%d call to malloc for %d\n", + size, gotten_store); + + fprintf(outfile, "Capturing subpattern count = %d\n", count); + if (backrefmax > 0) + fprintf(outfile, "Max back reference = %d\n", backrefmax); + + if (namecount > 0) + { + fprintf(outfile, "Named capturing subpatterns:\n"); + while (namecount-- > 0) + { + fprintf(outfile, " %s %*s%3d\n", nametable + 2, + nameentrysize - 3 - (int)strlen((char *)nametable + 2), "", + GET2(nametable, 0)); + nametable += nameentrysize; + } + } + + if (get_options == 0) fprintf(outfile, "No options\n"); + else fprintf(outfile, "Options:%s%s%s%s%s%s%s%s%s\n", + ((get_options & PCRE_ANCHORED) != 0)? " anchored" : "", + ((get_options & PCRE_CASELESS) != 0)? " caseless" : "", + ((get_options & PCRE_EXTENDED) != 0)? " extended" : "", + ((get_options & PCRE_MULTILINE) != 0)? " multiline" : "", + ((get_options & PCRE_DOTALL) != 0)? " dotall" : "", + ((get_options & PCRE_DOLLAR_ENDONLY) != 0)? " dollar_endonly" : "", + ((get_options & PCRE_EXTRA) != 0)? " extra" : "", + ((get_options & PCRE_UNGREEDY) != 0)? " ungreedy" : "", + ((get_options & PCRE_UTF8) != 0)? " utf8" : ""); + + if (((((real_pcre *)re)->options) & PCRE_ICHANGED) != 0) + fprintf(outfile, "Case state changes\n"); + + if (first_char == -1) + { + fprintf(outfile, "First char at start or follows \\n\n"); + } + else if (first_char < 0) + { + fprintf(outfile, "No first char\n"); + } + else + { + int ch = first_char & 255; + const char *caseless = ((first_char & REQ_CASELESS) == 0)? + "" : " (caseless)"; + if (isprint(ch)) + fprintf(outfile, "First char = \'%c\'%s\n", ch, caseless); + else + fprintf(outfile, "First char = %d%s\n", ch, caseless); + } + + if (need_char < 0) + { + fprintf(outfile, "No need char\n"); + } + else + { + int ch = need_char & 255; + const char *caseless = ((need_char & REQ_CASELESS) == 0)? + "" : " (caseless)"; + if (isprint(ch)) + fprintf(outfile, "Need char = \'%c\'%s\n", ch, caseless); + else + fprintf(outfile, "Need char = %d%s\n", ch, caseless); + } + } + + /* If /S was present, study the regexp to generate additional info to + help with the matching. */ + + if (do_study) + { + if (timeit) + { + register int i; + clock_t time_taken; + clock_t start_time = clock(); + for (i = 0; i < LOOPREPEAT; i++) + extra = pcre_study(re, study_options, &error); + time_taken = clock() - start_time; + if (extra != NULL) free(extra); + fprintf(outfile, " Study time %.3f milliseconds\n", + (((double)time_taken * 1000.0) / (double)LOOPREPEAT) / + (double)CLOCKS_PER_SEC); + } + + extra = pcre_study(re, study_options, &error); + if (error != NULL) + fprintf(outfile, "Failed to study: %s\n", error); + else if (extra == NULL) + fprintf(outfile, "Study returned NULL\n"); + + else if (do_showinfo) + { + size_t size; + uschar *start_bits = NULL; + new_info(re, extra, PCRE_INFO_STUDYSIZE, &size); + new_info(re, extra, PCRE_INFO_FIRSTTABLE, &start_bits); + fprintf(outfile, "Study size = %d\n", size); + if (start_bits == NULL) + fprintf(outfile, "No starting character set\n"); + else + { + int i; + int c = 24; + fprintf(outfile, "Starting character set: "); + for (i = 0; i < 256; i++) + { + if ((start_bits[i/8] & (1<<(i%8))) != 0) + { + if (c > 75) + { + fprintf(outfile, "\n "); + c = 2; + } + if (isprint(i) && i != ' ') + { + fprintf(outfile, "%c ", i); + c += 2; + } + else + { + fprintf(outfile, "\\x%02x ", i); + c += 5; + } + } + } + fprintf(outfile, "\n"); + } + } + } + } + + /* Read data lines and test them */ + + for (;;) + { + unsigned char *q; + unsigned char *bptr = dbuffer; + int *use_offsets = offsets; + int use_size_offsets = size_offsets; + int callout_data = 0; + int callout_data_set = 0; + int count, c; + int copystrings = 0; + int find_match_limit = 0; + int getstrings = 0; + int getlist = 0; + int gmatched = 0; + int start_offset = 0; + int g_notempty = 0; + + options = 0; + + pcre_callout = callout; + first_callout = 1; + callout_extra = 0; + callout_count = 0; + callout_fail_count = 999999; + callout_fail_id = -1; + + if (infile == stdin) printf("data> "); + if (fgets((char *)buffer, BUFFER_SIZE, infile) == NULL) + { + done = 1; + goto CONTINUE; + } + if (infile != stdin) fprintf(outfile, "%s", (char *)buffer); + + len = (int)strlen((char *)buffer); + while (len > 0 && isspace(buffer[len-1])) len--; + buffer[len] = 0; + if (len == 0) break; + + p = buffer; + while (isspace(*p)) p++; + + q = dbuffer; + while ((c = *p++) != 0) + { + int i = 0; + int n = 0; + + if (c == '\\') switch ((c = *p++)) + { + case 'a': c = 7; break; + case 'b': c = '\b'; break; + case 'e': c = 27; break; + case 'f': c = '\f'; break; + case 'n': c = '\n'; break; + case 'r': c = '\r'; break; + case 't': c = '\t'; break; + case 'v': c = '\v'; break; + + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + c -= '0'; + while (i++ < 2 && isdigit(*p) && *p != '8' && *p != '9') + c = c * 8 + *p++ - '0'; + break; + + case 'x': + + /* Handle \x{..} specially - new Perl thing for utf8 */ + + if (*p == '{') + { + unsigned char *pt = p; + c = 0; + while (isxdigit(*(++pt))) + c = c * 16 + tolower(*pt) - ((isdigit(*pt))? '0' : 'W'); + if (*pt == '}') + { + unsigned char buff8[8]; + int ii, utn; + utn = ord2utf8(c, buff8); + for (ii = 0; ii < utn - 1; ii++) *q++ = buff8[ii]; + c = buff8[ii]; /* Last byte */ + p = pt + 1; + break; + } + /* Not correct form; fall through */ + } + + /* Ordinary \x */ + + c = 0; + while (i++ < 2 && isxdigit(*p)) + { + c = c * 16 + tolower(*p) - ((isdigit(*p))? '0' : 'W'); + p++; + } + break; + + case 0: /* Allows for an empty line */ + p--; + continue; + + case 'A': /* Option setting */ + options |= PCRE_ANCHORED; + continue; + + case 'B': + options |= PCRE_NOTBOL; + continue; + + case 'C': + if (isdigit(*p)) /* Set copy string */ + { + while(isdigit(*p)) n = n * 10 + *p++ - '0'; + copystrings |= 1 << n; + } + else if (isalnum(*p)) + { + uschar name[256]; + uschar *npp = name; + while (isalnum(*p)) *npp++ = *p++; + *npp = 0; + n = pcre_get_stringnumber(re, (char *)name); + if (n < 0) + fprintf(outfile, "no parentheses with name \"%s\"\n", name); + else copystrings |= 1 << n; + } + else if (*p == '+') + { + callout_extra = 1; + p++; + } + else if (*p == '-') + { + pcre_callout = NULL; + p++; + } + else if (*p == '!') + { + callout_fail_id = 0; + p++; + while(isdigit(*p)) + callout_fail_id = callout_fail_id * 10 + *p++ - '0'; + callout_fail_count = 0; + if (*p == '!') + { + p++; + while(isdigit(*p)) + callout_fail_count = callout_fail_count * 10 + *p++ - '0'; + } + } + else if (*p == '*') + { + int sign = 1; + callout_data = 0; + if (*(++p) == '-') { sign = -1; p++; } + while(isdigit(*p)) + callout_data = callout_data * 10 + *p++ - '0'; + callout_data *= sign; + callout_data_set = 1; + } + continue; + + case 'G': + if (isdigit(*p)) + { + while(isdigit(*p)) n = n * 10 + *p++ - '0'; + getstrings |= 1 << n; + } + else if (isalnum(*p)) + { + uschar name[256]; + uschar *npp = name; + while (isalnum(*p)) *npp++ = *p++; + *npp = 0; + n = pcre_get_stringnumber(re, (char *)name); + if (n < 0) + fprintf(outfile, "no parentheses with name \"%s\"\n", name); + else getstrings |= 1 << n; + } + continue; + + case 'L': + getlist = 1; + continue; + + case 'M': + find_match_limit = 1; + continue; + + case 'N': + options |= PCRE_NOTEMPTY; + continue; + + case 'O': + while(isdigit(*p)) n = n * 10 + *p++ - '0'; + if (n > size_offsets_max) + { + size_offsets_max = n; + free(offsets); + use_offsets = offsets = malloc(size_offsets_max * sizeof(int)); + if (offsets == NULL) + { + printf("** Failed to get %d bytes of memory for offsets vector\n", + size_offsets_max * sizeof(int)); + return 1; + } + } + use_size_offsets = n; + if (n == 0) use_offsets = NULL; /* Ensures it can't write to it */ + continue; + + case 'Z': + options |= PCRE_NOTEOL; + continue; + } + *q++ = c; + } + *q = 0; + len = q - dbuffer; + + /* Handle matching via the POSIX interface, which does not + support timing or playing with the match limit or callout data. */ + +#if !defined NOPOSIX + if (posix || do_posix) + { + int rc; + int eflags = 0; + regmatch_t *pmatch = NULL; + if (use_size_offsets > 0) + pmatch = malloc(sizeof(regmatch_t) * use_size_offsets); + if ((options & PCRE_NOTBOL) != 0) eflags |= REG_NOTBOL; + if ((options & PCRE_NOTEOL) != 0) eflags |= REG_NOTEOL; + + rc = regexec(&preg, (const char *)bptr, use_size_offsets, pmatch, eflags); + + if (rc != 0) + { + (void)regerror(rc, &preg, (char *)buffer, BUFFER_SIZE); + fprintf(outfile, "No match: POSIX code %d: %s\n", rc, buffer); + } + else + { + size_t i; + for (i = 0; i < (size_t)use_size_offsets; i++) + { + if (pmatch[i].rm_so >= 0) + { + fprintf(outfile, "%2d: ", (int)i); + (void)pchars(dbuffer + pmatch[i].rm_so, + pmatch[i].rm_eo - pmatch[i].rm_so, outfile); + fprintf(outfile, "\n"); + if (i == 0 && do_showrest) + { + fprintf(outfile, " 0+ "); + (void)pchars(dbuffer + pmatch[i].rm_eo, len - pmatch[i].rm_eo, + outfile); + fprintf(outfile, "\n"); + } + } + } + } + free(pmatch); + } + + /* Handle matching via the native interface - repeats for /g and /G */ + + else +#endif /* !defined NOPOSIX */ + + for (;; gmatched++) /* Loop for /g or /G */ + { + if (timeit) + { + register int i; + clock_t time_taken; + clock_t start_time = clock(); + for (i = 0; i < LOOPREPEAT; i++) + count = pcre_exec(re, extra, (char *)bptr, len, + start_offset, options | g_notempty, use_offsets, use_size_offsets); + time_taken = clock() - start_time; + fprintf(outfile, "Execute time %.3f milliseconds\n", + (((double)time_taken * 1000.0) / (double)LOOPREPEAT) / + (double)CLOCKS_PER_SEC); + } + + /* If find_match_limit is set, we want to do repeated matches with + varying limits in order to find the minimum value. */ + + if (find_match_limit) + { + int min = 0; + int mid = 64; + int max = -1; + + if (extra == NULL) + { + extra = malloc(sizeof(pcre_extra)); + extra->flags = 0; + } + extra->flags |= PCRE_EXTRA_MATCH_LIMIT; + + for (;;) + { + extra->match_limit = mid; + count = pcre_exec(re, extra, (char *)bptr, len, start_offset, + options | g_notempty, use_offsets, use_size_offsets); + if (count == PCRE_ERROR_MATCHLIMIT) + { + /* fprintf(outfile, "Testing match limit = %d\n", mid); */ + min = mid; + mid = (mid == max - 1)? max : (max > 0)? (min + max)/2 : mid*2; + } + else if (count >= 0 || count == PCRE_ERROR_NOMATCH) + { + if (mid == min + 1) + { + fprintf(outfile, "Minimum match limit = %d\n", mid); + break; + } + /* fprintf(outfile, "Testing match limit = %d\n", mid); */ + max = mid; + mid = (min + mid)/2; + } + else break; /* Some other error */ + } + + extra->flags &= ~PCRE_EXTRA_MATCH_LIMIT; + } + + /* If callout_data is set, use the interface with additional data */ + + else if (callout_data_set) + { + if (extra == NULL) + { + extra = malloc(sizeof(pcre_extra)); + extra->flags = 0; + } + extra->flags |= PCRE_EXTRA_CALLOUT_DATA; + extra->callout_data = (void *)callout_data; + count = pcre_exec(re, extra, (char *)bptr, len, start_offset, + options | g_notempty, use_offsets, use_size_offsets); + extra->flags &= ~PCRE_EXTRA_CALLOUT_DATA; + } + + /* The normal case is just to do the match once, with the default + value of match_limit. */ + + else count = pcre_exec(re, extra, (char *)bptr, len, + start_offset, options | g_notempty, use_offsets, use_size_offsets); + + if (count == 0) + { + fprintf(outfile, "Matched, but too many substrings\n"); + count = use_size_offsets/3; + } + + /* Matched */ + + if (count >= 0) + { + int i; + for (i = 0; i < count * 2; i += 2) + { + if (use_offsets[i] < 0) + fprintf(outfile, "%2d: \n", i/2); + else + { + fprintf(outfile, "%2d: ", i/2); + (void)pchars(bptr + use_offsets[i], + use_offsets[i+1] - use_offsets[i], outfile); + fprintf(outfile, "\n"); + if (i == 0) + { + if (do_showrest) + { + fprintf(outfile, " 0+ "); + (void)pchars(bptr + use_offsets[i+1], len - use_offsets[i+1], + outfile); + fprintf(outfile, "\n"); + } + } + } + } + + for (i = 0; i < 32; i++) + { + if ((copystrings & (1 << i)) != 0) + { + char copybuffer[16]; + int rc = pcre_copy_substring((char *)bptr, use_offsets, count, + i, copybuffer, sizeof(copybuffer)); + if (rc < 0) + fprintf(outfile, "copy substring %d failed %d\n", i, rc); + else + fprintf(outfile, "%2dC %s (%d)\n", i, copybuffer, rc); + } + } + + for (i = 0; i < 32; i++) + { + if ((getstrings & (1 << i)) != 0) + { + const char *substring; + int rc = pcre_get_substring((char *)bptr, use_offsets, count, + i, &substring); + if (rc < 0) + fprintf(outfile, "get substring %d failed %d\n", i, rc); + else + { + fprintf(outfile, "%2dG %s (%d)\n", i, substring, rc); + /* free((void *)substring); */ + pcre_free_substring(substring); + } + } + } + + if (getlist) + { + const char **stringlist; + int rc = pcre_get_substring_list((char *)bptr, use_offsets, count, + &stringlist); + if (rc < 0) + fprintf(outfile, "get substring list failed %d\n", rc); + else + { + for (i = 0; i < count; i++) + fprintf(outfile, "%2dL %s\n", i, stringlist[i]); + if (stringlist[i] != NULL) + fprintf(outfile, "string list not terminated by NULL\n"); + /* free((void *)stringlist); */ + pcre_free_substring_list(stringlist); + } + } + } + + /* Failed to match. If this is a /g or /G loop and we previously set + g_notempty after a null match, this is not necessarily the end. + We want to advance the start offset, and continue. Fudge the offset + values to achieve this. We won't be at the end of the string - that + was checked before setting g_notempty. */ + + else + { + if (g_notempty != 0) + { + use_offsets[0] = start_offset; + use_offsets[1] = start_offset + 1; + } + else + { + if (gmatched == 0) /* Error if no previous matches */ + { + if (count == -1) fprintf(outfile, "No match\n"); + else fprintf(outfile, "Error %d\n", count); + } + break; /* Out of the /g loop */ + } + } + + /* If not /g or /G we are done */ + + if (!do_g && !do_G) break; + + /* If we have matched an empty string, first check to see if we are at + the end of the subject. If so, the /g loop is over. Otherwise, mimic + what Perl's /g options does. This turns out to be rather cunning. First + we set PCRE_NOTEMPTY and PCRE_ANCHORED and try the match again at the + same point. If this fails (picked up above) we advance to the next + character. */ + + g_notempty = 0; + if (use_offsets[0] == use_offsets[1]) + { + if (use_offsets[0] == len) break; + g_notempty = PCRE_NOTEMPTY | PCRE_ANCHORED; + } + + /* For /g, update the start offset, leaving the rest alone */ + + if (do_g) start_offset = use_offsets[1]; + + /* For /G, update the pointer and length */ + + else + { + bptr += use_offsets[1]; + len -= use_offsets[1]; + } + } /* End of loop for /g and /G */ + } /* End of loop for data lines */ + + CONTINUE: + +#if !defined NOPOSIX + if (posix || do_posix) regfree(&preg); +#endif + + if (re != NULL) free(re); + if (extra != NULL) free(extra); + if (tables != NULL) + { + free((void *)tables); + setlocale(LC_CTYPE, "C"); + } + } + +fprintf(outfile, "\n"); +return 0; +} + +/* End */ diff --git a/mk4/continuity/pcre/perltest b/mk4/continuity/pcre/perltest new file mode 100644 index 0000000..bb34cc8 --- /dev/null +++ b/mk4/continuity/pcre/perltest @@ -0,0 +1,211 @@ +#! /usr/bin/perl + +# Program for testing regular expressions with perl to check that PCRE handles +# them the same. This is the version that supports /8 for UTF-8 testing. As it +# stands, it requires at least Perl 5.8 for UTF-8 support. For Perl 5.6, it +# can be used as is for non-UTF-8 testing, but you have to uncomment the +# "use utf8" lines in order to to UTF-8 stuff (and you mustn't uncomment them +# for non-UTF-8 use). + + +# Function for turning a string into a string of printing chars. There are +# currently problems with UTF-8 strings; this fudges round them. + +sub pchars { +my($t) = ""; + +if ($utf8) + { +# use utf8; <=============== For UTF-8 in Perl 5.6 + @p = unpack('U*', $_[0]); + foreach $c (@p) + { + if ($c >= 32 && $c < 127) { $t .= chr $c; } + else { $t .= sprintf("\\x{%02x}", $c); } + } + } + +else + { + foreach $c (split(//, $_[0])) + { + if (ord $c >= 32 && ord $c < 127) { $t .= $c; } + else { $t .= sprintf("\\x%02x", ord $c); } + } + } + +$t; +} + + + +# Read lines from named file or stdin and write to named file or stdout; lines +# consist of a regular expression, in delimiters and optionally followed by +# options, followed by a set of test data, terminated by an empty line. + +# Sort out the input and output files + +if (@ARGV > 0) + { + open(INFILE, "<$ARGV[0]") || die "Failed to open $ARGV[0]\n"; + $infile = "INFILE"; + } +else { $infile = "STDIN"; } + +if (@ARGV > 1) + { + open(OUTFILE, ">$ARGV[1]") || die "Failed to open $ARGV[1]\n"; + $outfile = "OUTFILE"; + } +else { $outfile = "STDOUT"; } + +printf($outfile "Perl $] Regular Expressions\n\n"); + +# Main loop + +NEXT_RE: +for (;;) + { + printf " re> " if $infile eq "STDIN"; + last if ! ($_ = <$infile>); + printf $outfile "$_" if $infile ne "STDIN"; + next if ($_ eq ""); + + $pattern = $_; + + while ($pattern !~ /^\s*(.).*\1/s) + { + printf " > " if $infile eq "STDIN"; + last if ! ($_ = <$infile>); + printf $outfile "$_" if $infile ne "STDIN"; + $pattern .= $_; + } + + chomp($pattern); + $pattern =~ s/\s+$//; + + # The private /+ modifier means "print $' afterwards". + + $showrest = ($pattern =~ s/\+(?=[a-z]*$)//); + + # The private /8 modifier means "operate in UTF-8". Currently, Perl + # has bugs that we try to work around using this flag. + + $utf8 = ($pattern =~ s/8(?=[a-z]*$)//); + + # Check that the pattern is valid + + if ($utf8) + { +# use utf8; <=============== For UTF-8 in Perl 5.6 + eval "\$_ =~ ${pattern}"; + } + else + { + eval "\$_ =~ ${pattern}"; + } + + if ($@) + { + printf $outfile "Error: $@"; + next NEXT_RE; + } + + # If the /g modifier is present, we want to put a loop round the matching; + # otherwise just a single "if". + + $cmd = ($pattern =~ /g[a-z]*$/)? "while" : "if"; + + # If the pattern is actually the null string, Perl uses the most recently + # executed (and successfully compiled) regex is used instead. This is a + # nasty trap for the unwary! The PCRE test suite does contain null strings + # in places - if they are allowed through here all sorts of weird and + # unexpected effects happen. To avoid this, we replace such patterns with + # a non-null pattern that has the same effect. + + $pattern = "/(?#)/$2" if ($pattern =~ /^(.)\1(.*)$/); + + # Read data lines and test them + + for (;;) + { + printf "data> " if $infile eq "STDIN"; + last NEXT_RE if ! ($_ = <$infile>); + chomp; + printf $outfile "$_\n" if $infile ne "STDIN"; + + s/\s+$//; + s/^\s+//; + + last if ($_ eq ""); + + $x = eval "\"$_\""; # To get escapes processed + + # Empty array for holding results, then do the matching. + + @subs = (); + + $pushes = "push \@subs,\$&;" . + "push \@subs,\$1;" . + "push \@subs,\$2;" . + "push \@subs,\$3;" . + "push \@subs,\$4;" . + "push \@subs,\$5;" . + "push \@subs,\$6;" . + "push \@subs,\$7;" . + "push \@subs,\$8;" . + "push \@subs,\$9;" . + "push \@subs,\$10;" . + "push \@subs,\$11;" . + "push \@subs,\$12;" . + "push \@subs,\$13;" . + "push \@subs,\$14;" . + "push \@subs,\$15;" . + "push \@subs,\$16;" . + "push \@subs,\$'; }"; + + if ($utf8) + { +# use utf8; <=============== For UTF-8 in Perl 5.6 + eval "${cmd} (\$x =~ ${pattern}) {" . $pushes; + } + else + { + eval "${cmd} (\$x =~ ${pattern}) {" . $pushes; + } + + if ($@) + { + printf $outfile "Error: $@\n"; + next NEXT_RE; + } + elsif (scalar(@subs) == 0) + { + printf $outfile "No match\n"; + } + else + { + while (scalar(@subs) != 0) + { + printf $outfile (" 0: %s\n", &pchars($subs[0])); + printf $outfile (" 0+ %s\n", &pchars($subs[17])) if $showrest; + $last_printed = 0; + for ($i = 1; $i <= 16; $i++) + { + if (defined $subs[$i]) + { + while ($last_printed++ < $i-1) + { printf $outfile ("%2d: \n", $last_printed); } + printf $outfile ("%2d: %s\n", $i, &pchars($subs[$i])); + $last_printed = $i; + } + } + splice(@subs, 0, 18); + } + } + } + } + +printf $outfile "\n"; + +# End diff --git a/mk4/continuity/pcre/printint.c b/mk4/continuity/pcre/printint.c new file mode 100644 index 0000000..cd01f05 --- /dev/null +++ b/mk4/continuity/pcre/printint.c @@ -0,0 +1,360 @@ +/************************************************* +* Perl-Compatible Regular Expressions * +*************************************************/ + +/* +This is a library of functions to support regular expressions whose syntax +and semantics are as close as possible to those of the Perl 5 language. See +the file Tech.Notes for some information on the internals. + +Written by: Philip Hazel + + Copyright (c) 1997-2003 University of Cambridge + +----------------------------------------------------------------------------- +Permission is granted to anyone to use this software for any purpose on any +computer system, and to redistribute it freely, subject to the following +restrictions: + +1. This software 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. + +2. The origin of this software must not be misrepresented, either by + explicit claim or by omission. + +3. Altered versions must be plainly marked as such, and must not be + misrepresented as being the original software. + +4. If PCRE is embedded in any software that is released under the GNU + General Purpose Licence (GPL), then the terms of that licence shall + supersede any condition above with which it is incompatible. +----------------------------------------------------------------------------- +*/ + + +/* This module contains a debugging function for printing out the internal form +of a compiled regular expression. It is kept in a separate file so that it can +be #included both in the pcretest program, and in the library itself when +compiled with the debugging switch. */ + + +static const char *OP_names[] = { OP_NAME_LIST }; + + +/************************************************* +* Print single- or multi-byte character * +*************************************************/ + +/* These tables are actually copies of ones in pcre.c. If we compile the +library with debugging, they are included twice, but that isn't really a +problem - compiling with debugging is pretty rare and these are very small. */ + +static int utf8_t3[] = { 0xff, 0x1f, 0x0f, 0x07, 0x03, 0x01}; + +static uschar utf8_t4[] = { + 1,1,1,1,1,1,1,1,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,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 }; + +static int +print_char(FILE *f, uschar *ptr, BOOL utf8) +{ +int c = *ptr; + +if (!utf8 || (c & 0xc0) != 0xc0) + { + if (isprint(c)) fprintf(f, "%c", c); else fprintf(f, "\\x%02x", c); + return 0; + } +else + { + int i; + int a = utf8_t4[c & 0x3f]; /* Number of additional bytes */ + int s = 6*a; + c = (c & utf8_t3[a]) << s; + for (i = 1; i <= a; i++) + { + s -= 6; + c |= (ptr[i] & 0x3f) << s; + } + if (c < 128) fprintf(f, "\\x%02x", c); else fprintf(f, "\\x{%x}", c); + return a; + } +} + + + + +/************************************************* +* Print compiled regex * +*************************************************/ + +static void +print_internals(pcre *external_re, FILE *f) +{ +real_pcre *re = (real_pcre *)external_re; +uschar *codestart = + (uschar *)re + sizeof(real_pcre) + re->name_count * re->name_entry_size; +uschar *code = codestart; +BOOL utf8 = (re->options & PCRE_UTF8) != 0; + +for(;;) + { + uschar *ccode; + int c; + int extra = 0; + + fprintf(f, "%3d ", code - codestart); + + if (*code >= OP_BRA) + { + if (*code - OP_BRA > EXTRACT_BASIC_MAX) + fprintf(f, "%3d Bra extra\n", GET(code, 1)); + else + fprintf(f, "%3d Bra %d\n", GET(code, 1), *code - OP_BRA); + code += OP_lengths[OP_BRA]; + continue; + } + + switch(*code) + { + case OP_END: + fprintf(f, " %s\n", OP_names[*code]); + fprintf(f, "------------------------------------------------------------------\n"); + return; + + case OP_OPT: + fprintf(f, " %.2x %s", code[1], OP_names[*code]); + break; + + case OP_CHARS: + { + int charlength = code[1]; + ccode = code + 2; + extra = charlength; + fprintf(f, "%3d ", charlength); + while (charlength > 0) + { + int extrabytes = print_char(f, ccode, utf8); + ccode += 1 + extrabytes; + charlength -= 1 + extrabytes; + } + } + break; + + case OP_KETRMAX: + case OP_KETRMIN: + case OP_ALT: + case OP_KET: + case OP_ASSERT: + case OP_ASSERT_NOT: + case OP_ASSERTBACK: + case OP_ASSERTBACK_NOT: + case OP_ONCE: + case OP_COND: + case OP_REVERSE: + fprintf(f, "%3d %s", GET(code, 1), OP_names[*code]); + break; + + case OP_BRANUMBER: + printf("%3d %s", GET2(code, 1), OP_names[*code]); + break; + + case OP_CREF: + if (GET2(code, 1) == CREF_RECURSE) + fprintf(f, " Cond recurse"); + else + fprintf(f, "%3d %s", GET2(code,1), OP_names[*code]); + break; + + case OP_STAR: + case OP_MINSTAR: + case OP_PLUS: + case OP_MINPLUS: + case OP_QUERY: + case OP_MINQUERY: + case OP_TYPESTAR: + case OP_TYPEMINSTAR: + case OP_TYPEPLUS: + case OP_TYPEMINPLUS: + case OP_TYPEQUERY: + case OP_TYPEMINQUERY: + fprintf(f, " "); + if (*code >= OP_TYPESTAR) fprintf(f, "%s", OP_names[code[1]]); + else extra = print_char(f, code+1, utf8); + fprintf(f, "%s", OP_names[*code]); + break; + + case OP_EXACT: + case OP_UPTO: + case OP_MINUPTO: + fprintf(f, " "); + extra = print_char(f, code+3, utf8); + fprintf(f, "{"); + if (*code != OP_EXACT) fprintf(f, ","); + fprintf(f, "%d}", GET2(code,1)); + if (*code == OP_MINUPTO) fprintf(f, "?"); + break; + + case OP_TYPEEXACT: + case OP_TYPEUPTO: + case OP_TYPEMINUPTO: + fprintf(f, " %s{", OP_names[code[3]]); + if (*code != OP_TYPEEXACT) fprintf(f, "0,"); + fprintf(f, "%d}", GET2(code,1)); + if (*code == OP_TYPEMINUPTO) fprintf(f, "?"); + break; + + case OP_NOT: + if (isprint(c = code[1])) fprintf(f, " [^%c]", c); + else fprintf(f, " [^\\x%02x]", c); + break; + + case OP_NOTSTAR: + case OP_NOTMINSTAR: + case OP_NOTPLUS: + case OP_NOTMINPLUS: + case OP_NOTQUERY: + case OP_NOTMINQUERY: + if (isprint(c = code[1])) fprintf(f, " [^%c]", c); + else fprintf(f, " [^\\x%02x]", c); + fprintf(f, "%s", OP_names[*code]); + break; + + case OP_NOTEXACT: + case OP_NOTUPTO: + case OP_NOTMINUPTO: + if (isprint(c = code[3])) fprintf(f, " [^%c]{", c); + else fprintf(f, " [^\\x%02x]{", c); + if (*code != OP_NOTEXACT) fprintf(f, ","); + fprintf(f, "%d}", GET2(code,1)); + if (*code == OP_NOTMINUPTO) fprintf(f, "?"); + break; + + case OP_RECURSE: + fprintf(f, "%3d %s", GET(code, 1), OP_names[*code]); + break; + + case OP_REF: + fprintf(f, " \\%d", GET2(code,1)); + ccode = code + OP_lengths[*code]; + goto CLASS_REF_REPEAT; + + case OP_CALLOUT: + fprintf(f, " %s %d", OP_names[*code], code[1]); + break; + + /* OP_XCLASS can only occur in UTF-8 mode. However, there's no harm in + having this code always here, and it makes it less messy without all those + #ifdefs. */ + + case OP_CLASS: + case OP_NCLASS: + case OP_XCLASS: + { + int i, min, max; + BOOL printmap; + + fprintf(f, " ["); + + if (*code == OP_XCLASS) + { + extra = GET(code, 1); + ccode = code + LINK_SIZE + 1; + printmap = (*ccode & XCL_MAP) != 0; + if ((*ccode++ & XCL_NOT) != 0) fprintf(f, "^"); + } + else + { + printmap = TRUE; + ccode = code + 1; + } + + /* Print a bit map */ + + if (printmap) + { + for (i = 0; i < 256; i++) + { + if ((ccode[i/8] & (1 << (i&7))) != 0) + { + int j; + for (j = i+1; j < 256; j++) + if ((ccode[j/8] & (1 << (j&7))) == 0) break; + if (i == '-' || i == ']') fprintf(f, "\\"); + if (isprint(i)) fprintf(f, "%c", i); else fprintf(f, "\\x%02x", i); + if (--j > i) + { + fprintf(f, "-"); + if (j == '-' || j == ']') fprintf(f, "\\"); + if (isprint(j)) fprintf(f, "%c", j); else fprintf(f, "\\x%02x", j); + } + i = j; + } + } + ccode += 32; + } + + /* For an XCLASS there is always some additional data */ + + if (*code == OP_XCLASS) + { + int ch; + while ((ch = *ccode++) != XCL_END) + { + ccode += 1 + print_char(f, ccode, TRUE); + if (ch == XCL_RANGE) + { + fprintf(f, "-"); + ccode += 1 + print_char(f, ccode, TRUE); + } + } + } + + /* Indicate a non-UTF8 class which was created by negation */ + + fprintf(f, "]%s", (*code == OP_NCLASS)? " (neg)" : ""); + + /* Handle repeats after a class or a back reference */ + + CLASS_REF_REPEAT: + switch(*ccode) + { + case OP_CRSTAR: + case OP_CRMINSTAR: + case OP_CRPLUS: + case OP_CRMINPLUS: + case OP_CRQUERY: + case OP_CRMINQUERY: + fprintf(f, "%s", OP_names[*ccode]); + extra = OP_lengths[*ccode]; + break; + + case OP_CRRANGE: + case OP_CRMINRANGE: + min = GET2(ccode,1); + max = GET2(ccode,3); + if (max == 0) fprintf(f, "{%d,}", min); + else fprintf(f, "{%d,%d}", min, max); + if (*ccode == OP_CRMINRANGE) fprintf(f, "?"); + extra = OP_lengths[*ccode]; + break; + } + } + break; + + /* Anything else is just an item with no data*/ + + default: + fprintf(f, " %s", OP_names[*code]); + break; + } + + code += OP_lengths[*code] + extra; + fprintf(f, "\n"); + } +} + +/* End of printint.c */ diff --git a/mk4/continuity/pcre/study.c b/mk4/continuity/pcre/study.c new file mode 100644 index 0000000..4320bd2 --- /dev/null +++ b/mk4/continuity/pcre/study.c @@ -0,0 +1,438 @@ +/************************************************* +* Perl-Compatible Regular Expressions * +*************************************************/ + +/* +This is a library of functions to support regular expressions whose syntax +and semantics are as close as possible to those of the Perl 5 language. See +the file Tech.Notes for some information on the internals. + +Written by: Philip Hazel + + Copyright (c) 1997-2002 University of Cambridge + +----------------------------------------------------------------------------- +Permission is granted to anyone to use this software for any purpose on any +computer system, and to redistribute it freely, subject to the following +restrictions: + +1. This software 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. + +2. The origin of this software must not be misrepresented, either by + explicit claim or by omission. + +3. Altered versions must be plainly marked as such, and must not be + misrepresented as being the original software. + +4. If PCRE is embedded in any software that is released under the GNU + General Purpose Licence (GPL), then the terms of that licence shall + supersede any condition above with which it is incompatible. +----------------------------------------------------------------------------- +*/ + + +/* Include the internals header, which itself includes Standard C headers plus +the external pcre header. */ + +#include "internal.h" + + + +/************************************************* +* Set a bit and maybe its alternate case * +*************************************************/ + +/* Given a character, set its bit in the table, and also the bit for the other +version of a letter if we are caseless. + +Arguments: + start_bits points to the bit map + c is the character + caseless the caseless flag + cd the block with char table pointers + +Returns: nothing +*/ + +static void +set_bit(uschar *start_bits, int c, BOOL caseless, compile_data *cd) +{ +start_bits[c/8] |= (1 << (c&7)); +if (caseless && (cd->ctypes[c] & ctype_letter) != 0) + start_bits[cd->fcc[c]/8] |= (1 << (cd->fcc[c]&7)); +} + + + +/************************************************* +* Create bitmap of starting chars * +*************************************************/ + +/* This function scans a compiled unanchored expression and attempts to build a +bitmap of the set of initial characters. If it can't, it returns FALSE. As time +goes by, we may be able to get more clever at doing this. + +Arguments: + code points to an expression + start_bits points to a 32-byte table, initialized to 0 + caseless the current state of the caseless flag + utf8 TRUE if in UTF-8 mode + cd the block with char table pointers + +Returns: TRUE if table built, FALSE otherwise +*/ + +static BOOL +set_start_bits(const uschar *code, uschar *start_bits, BOOL caseless, + BOOL utf8, compile_data *cd) +{ +register int c; + +/* This next statement and the later reference to dummy are here in order to +trick the optimizer of the IBM C compiler for OS/2 into generating correct +code. Apparently IBM isn't going to fix the problem, and we would rather not +disable optimization (in this module it actually makes a big difference, and +the pcre module can use all the optimization it can get). */ + +volatile int dummy; + +do + { + const uschar *tcode = code + 1 + LINK_SIZE; + BOOL try_next = TRUE; + + while (try_next) + { + /* If a branch starts with a bracket or a positive lookahead assertion, + recurse to set bits from within them. That's all for this branch. */ + + if ((int)*tcode >= OP_BRA || *tcode == OP_ASSERT) + { + if (!set_start_bits(tcode, start_bits, caseless, utf8, cd)) + return FALSE; + try_next = FALSE; + } + + else switch(*tcode) + { + default: + return FALSE; + + /* Skip over callout */ + + case OP_CALLOUT: + tcode += 2; + break; + + /* Skip over extended extraction bracket number */ + + case OP_BRANUMBER: + tcode += 3; + break; + + /* Skip over lookbehind and negative lookahead assertions */ + + case OP_ASSERT_NOT: + case OP_ASSERTBACK: + case OP_ASSERTBACK_NOT: + do tcode += GET(tcode, 1); while (*tcode == OP_ALT); + tcode += 1+LINK_SIZE; + break; + + /* Skip over an option setting, changing the caseless flag */ + + case OP_OPT: + caseless = (tcode[1] & PCRE_CASELESS) != 0; + tcode += 2; + break; + + /* BRAZERO does the bracket, but carries on. */ + + case OP_BRAZERO: + case OP_BRAMINZERO: + if (!set_start_bits(++tcode, start_bits, caseless, utf8, cd)) + return FALSE; + dummy = 1; + do tcode += GET(tcode,1); while (*tcode == OP_ALT); + tcode += 1+LINK_SIZE; + break; + + /* Single-char * or ? sets the bit and tries the next item */ + + case OP_STAR: + case OP_MINSTAR: + case OP_QUERY: + case OP_MINQUERY: + set_bit(start_bits, tcode[1], caseless, cd); + tcode += 2; +#ifdef SUPPORT_UTF8 + if (utf8) while ((*tcode & 0xc0) == 0x80) tcode++; +#endif + break; + + /* Single-char upto sets the bit and tries the next */ + + case OP_UPTO: + case OP_MINUPTO: + set_bit(start_bits, tcode[3], caseless, cd); + tcode += 4; +#ifdef SUPPORT_UTF8 + if (utf8) while ((*tcode & 0xc0) == 0x80) tcode++; +#endif + break; + + /* At least one single char sets the bit and stops */ + + case OP_EXACT: /* Fall through */ + tcode++; + + case OP_CHARS: /* Fall through */ + tcode++; + + case OP_PLUS: + case OP_MINPLUS: + set_bit(start_bits, tcode[1], caseless, cd); + try_next = FALSE; + break; + + /* Single character type sets the bits and stops */ + + case OP_NOT_DIGIT: + for (c = 0; c < 32; c++) + start_bits[c] |= ~cd->cbits[c+cbit_digit]; + try_next = FALSE; + break; + + case OP_DIGIT: + for (c = 0; c < 32; c++) + start_bits[c] |= cd->cbits[c+cbit_digit]; + try_next = FALSE; + break; + + case OP_NOT_WHITESPACE: + for (c = 0; c < 32; c++) + start_bits[c] |= ~cd->cbits[c+cbit_space]; + try_next = FALSE; + break; + + case OP_WHITESPACE: + for (c = 0; c < 32; c++) + start_bits[c] |= cd->cbits[c+cbit_space]; + try_next = FALSE; + break; + + case OP_NOT_WORDCHAR: + for (c = 0; c < 32; c++) + start_bits[c] |= ~cd->cbits[c+cbit_word]; + try_next = FALSE; + break; + + case OP_WORDCHAR: + for (c = 0; c < 32; c++) + start_bits[c] |= cd->cbits[c+cbit_word]; + try_next = FALSE; + break; + + /* One or more character type fudges the pointer and restarts, knowing + it will hit a single character type and stop there. */ + + case OP_TYPEPLUS: + case OP_TYPEMINPLUS: + tcode++; + break; + + case OP_TYPEEXACT: + tcode += 3; + break; + + /* Zero or more repeats of character types set the bits and then + try again. */ + + case OP_TYPEUPTO: + case OP_TYPEMINUPTO: + tcode += 2; /* Fall through */ + + case OP_TYPESTAR: + case OP_TYPEMINSTAR: + case OP_TYPEQUERY: + case OP_TYPEMINQUERY: + switch(tcode[1]) + { + case OP_NOT_DIGIT: + for (c = 0; c < 32; c++) + start_bits[c] |= ~cd->cbits[c+cbit_digit]; + break; + + case OP_DIGIT: + for (c = 0; c < 32; c++) + start_bits[c] |= cd->cbits[c+cbit_digit]; + break; + + case OP_NOT_WHITESPACE: + for (c = 0; c < 32; c++) + start_bits[c] |= ~cd->cbits[c+cbit_space]; + break; + + case OP_WHITESPACE: + for (c = 0; c < 32; c++) + start_bits[c] |= cd->cbits[c+cbit_space]; + break; + + case OP_NOT_WORDCHAR: + for (c = 0; c < 32; c++) + start_bits[c] |= ~cd->cbits[c+cbit_word]; + break; + + case OP_WORDCHAR: + for (c = 0; c < 32; c++) + start_bits[c] |= cd->cbits[c+cbit_word]; + break; + } + + tcode += 2; + break; + + /* Character class where all the information is in a bit map: set the + bits and either carry on or not, according to the repeat count. If it was + a negative class, and we are operating with UTF-8 characters, any byte + with the top-bit set is a potentially valid starter because it may start + a character with a value > 255. (This is sub-optimal in that the + character may be in the range 128-255, and those characters might be + unwanted, but that's as far as we go for the moment.) */ + + case OP_NCLASS: + if (utf8) memset(start_bits+16, 0xff, 16); + /* Fall through */ + + case OP_CLASS: + { + tcode++; + for (c = 0; c < 32; c++) start_bits[c] |= tcode[c]; + tcode += 32; + switch (*tcode) + { + case OP_CRSTAR: + case OP_CRMINSTAR: + case OP_CRQUERY: + case OP_CRMINQUERY: + tcode++; + break; + + case OP_CRRANGE: + case OP_CRMINRANGE: + if (((tcode[1] << 8) + tcode[2]) == 0) tcode += 5; + else try_next = FALSE; + break; + + default: + try_next = FALSE; + break; + } + } + break; /* End of bitmap class handling */ + + } /* End of switch */ + } /* End of try_next loop */ + + code += GET(code, 1); /* Advance to next branch */ + } +while (*code == OP_ALT); +return TRUE; +} + + + +/************************************************* +* Study a compiled expression * +*************************************************/ + +/* This function is handed a compiled expression that it must study to produce +information that will speed up the matching. It returns a pcre_extra block +which then gets handed back to pcre_exec(). + +Arguments: + re points to the compiled expression + options contains option bits + errorptr points to where to place error messages; + set NULL unless error + +Returns: pointer to a pcre_extra block, with study_data filled in and the + appropriate flag set; + NULL on error or if no optimization possible +*/ + +pcre_extra * +pcre_study(const pcre *external_re, int options, const char **errorptr) +{ +uschar start_bits[32]; +pcre_extra *extra; +pcre_study_data *study; +const real_pcre *re = (const real_pcre *)external_re; +uschar *code = (uschar *)re + sizeof(real_pcre) + + (re->name_count * re->name_entry_size); +compile_data compile_block; + +*errorptr = NULL; + +if (re == NULL || re->magic_number != MAGIC_NUMBER) + { + *errorptr = "argument is not a compiled regular expression"; + return NULL; + } + +if ((options & ~PUBLIC_STUDY_OPTIONS) != 0) + { + *errorptr = "unknown or incorrect option bit(s) set"; + return NULL; + } + +/* For an anchored pattern, or an unanchored pattern that has a first char, or +a multiline pattern that matches only at "line starts", no further processing +at present. */ + +if ((re->options & (PCRE_ANCHORED|PCRE_FIRSTSET|PCRE_STARTLINE)) != 0) + return NULL; + +/* Set the character tables in the block which is passed around */ + +compile_block.lcc = re->tables + lcc_offset; +compile_block.fcc = re->tables + fcc_offset; +compile_block.cbits = re->tables + cbits_offset; +compile_block.ctypes = re->tables + ctypes_offset; + +/* See if we can find a fixed set of initial characters for the pattern. */ + +memset(start_bits, 0, 32 * sizeof(uschar)); +if (!set_start_bits(code, start_bits, (re->options & PCRE_CASELESS) != 0, + (re->options & PCRE_UTF8) != 0, &compile_block)) return NULL; + +/* Get a pcre_extra block and a pcre_study_data block. The study data is put in +the latter, which is pointed to by the former, which may also get additional +data set later by the calling program. At the moment, the size of +pcre_study_data is fixed. We nevertheless save it in a field for returning via +the pcre_fullinfo() function so that if it becomes variable in the future, we +don't have to change that code. */ + +extra = (pcre_extra *)(pcre_malloc) + (sizeof(pcre_extra) + sizeof(pcre_study_data)); + +if (extra == NULL) + { + *errorptr = "failed to get memory"; + return NULL; + } + +study = (pcre_study_data *)((char *)extra + sizeof(pcre_extra)); +extra->flags = PCRE_EXTRA_STUDY_DATA; +extra->study_data = study; + +study->size = sizeof(pcre_study_data); +study->options = PCRE_STUDY_MAPPED; +memcpy(study->start_bits, start_bits, sizeof(start_bits)); + +return extra; +} + +/* End of study.c */ diff --git a/mk4/continuity/todoc b/mk4/continuity/todoc new file mode 100644 index 0000000..a85010f --- /dev/null +++ b/mk4/continuity/todoc @@ -0,0 +1,48 @@ +void httpFset_state (httpTtrans *t, int state); + +int httpFset_nph (httpTtrans *t); + +phpF* + +int siteFsite_data_set(const char *siteid, const char *name, void *data); +void *siteFsite_data_get(const char *siteid, const char *name); + +int hshFvoid_size(hshTvoid_list * list); + +void hshFvoid_int_replace(hshTvoid_list * list, const int key, void *data); +void hshFvoid_replace(hshTvoid_list * list, const char *name, void *data); + +/* remove but not destroy/deallocate */ +void *hshFvoid_remove(hshTvoid_list * list, const char *name); +void *hshFvoid_int_remove(hshTvoid_list * list, int key); +void *hshFvoid_raw_remove(hshTvoid_list * list, const char *name, size_t name_len); + +void logFoutputfh_set(FILE *fh, int close); +FILE *logFoutputfh_get(void); +void fleFrotate(int count, const char *fn) + +conFget_config -> conFget_config_basetag + +hshFvoid_destroy -> hshFvoid_free + +hsh replace functions -> update + +void hshFvalue_destructor_set(hshTvoid_list *list, void (*destructor)(void *)) + +void dicFuserdata_destructor_set(dicTdictionary *d, void (*destructor)(void *)) +void *dicFuserdata_find(dicTdictionary *d, int idx) +void dicFuserdata_update(dicTdictionary *d, int idx, void *data) + +unsigned int utlFatoui(const char *s) +int utlFatoi(const char *s) + +int sysFfs_info(lstTset * set); +int sysFnet_usage(uint32_t *obytes, uint32_t *ibytes, + uint32_t *opkts, uint32_t *ipkts) + + +const char *xmlFfirst_child_value_str (const xmlTtag *tag, const char *name); + +const xmlTtag *siteFget_config_by_siteid (const char *siteid); +static void utlFhexdump(void *data, size_t size) + diff --git a/mk4/doc/CVS/Entries b/mk4/doc/CVS/Entries new file mode 100644 index 0000000..9a22b00 --- /dev/null +++ b/mk4/doc/CVS/Entries @@ -0,0 +1,2 @@ +/standards.txt/1.3/Wed Mar 31 19:59:51 2004//Tmk4_mod6_rc2 +D diff --git a/mk4/doc/CVS/Repository b/mk4/doc/CVS/Repository new file mode 100644 index 0000000..ee97d92 --- /dev/null +++ b/mk4/doc/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/doc diff --git a/mk4/doc/CVS/Root b/mk4/doc/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/doc/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/doc/CVS/Tag b/mk4/doc/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/doc/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/doc/standards.txt b/mk4/doc/standards.txt new file mode 100644 index 0000000..937f0ba --- /dev/null +++ b/mk4/doc/standards.txt @@ -0,0 +1,77 @@ +$Header: /san01/cvs/ashpool/csrc/doc/Attic/standards.txt,v 1.3 2004/03/31 19:59:51 aleigh Exp $ + +-= API & Code Terms =- + +This is an attempt to create a small glossary of "approved" terms, +mostly for use when naming function calls and objects. There has been +some drift over the months and even within my own code I use confusing +or inconsistent nomenclature. + +The following are "approved" terms which should be use exclusively; +for example "create" should not be used in lieu of "init". + +init: Create / Allocate a thing + +free: Destroy / De-Allocate a thing + +add: Exclusivly add a thing to storage thing. +Only add if the thing was not already in the storage +thing unless the storage thing does not enforce +uniqueness. + +replace: Replace one thing with another. Do not +add the thing if it was not already there. + +update: Add/Replace the value of a thing in +a container. + +delete: Delete a thing and destroy it. + +remove: Remove a thing but return it instead of +destroying it. + +find: Lookup a thing, search for a thing, get a specific thing. + +-= Source Code =- + +4 space tabs. Do not use the tab character. + +One-True Brace Style. + +No implicit blocks: + + if (a==1) { + return 1; + } + +instead of + + if(a==1) + return 1; + +No implicit conditionals: + + if(a==0) + +instead of + + if(!a); + +-= Return Status =- + +Functions may have one of several return profiles depending on +their individual function. + +Standard Boolean: +-1 Error + 0 success + +Standard State: +-1 Error + 0 did nothing + 1 did something + +Standard I/O: +-1 Error + n bytes read/written + diff --git a/mk4/httpclient/CVS/Entries b/mk4/httpclient/CVS/Entries new file mode 100644 index 0000000..9af8591 --- /dev/null +++ b/mk4/httpclient/CVS/Entries @@ -0,0 +1,3 @@ +/Makefile/1.1/Thu May 27 13:50:58 2004//Tmk4_mod6_rc2 +/httpclient.c/1.4/Tue Jun 1 12:55:59 2004//Tmk4_mod6_rc2 +D diff --git a/mk4/httpclient/CVS/Repository b/mk4/httpclient/CVS/Repository new file mode 100644 index 0000000..d5405ae --- /dev/null +++ b/mk4/httpclient/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/httpclient diff --git a/mk4/httpclient/CVS/Root b/mk4/httpclient/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/httpclient/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/httpclient/CVS/Tag b/mk4/httpclient/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/httpclient/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/httpclient/Makefile b/mk4/httpclient/Makefile new file mode 100644 index 0000000..5af4597 --- /dev/null +++ b/mk4/httpclient/Makefile @@ -0,0 +1,11 @@ +include ../continuity/lib/env.mk + +SRCS=httpclient.c +OBJS=httpclient.o + +CFLAGS+=-I../continuity/include + +httpclient: $(OBJS) + $(CC) httpclient.o ../continuity/lib/mechanism.a -o httpclient $(LIBS) +clean: + $(RM) $(OBJS) httpclient diff --git a/mk4/httpclient/httpclient.c b/mk4/httpclient/httpclient.c new file mode 100644 index 0000000..da5fd46 --- /dev/null +++ b/mk4/httpclient/httpclient.c @@ -0,0 +1,115 @@ +#include + +int request(const char *uri, const char *hostname, const char *port, const char *host_tuple) { + int sd; + netTconn *conn; + netTreader *reader; + char buf[1024]; + + logFmsg(3,"Connecting to %s:%s for %s", hostname, port, uri); + + + sd=netFtcp_connect(hostname,atoi(port)); + + if(sd<0) { + logFmsg(2,"Connect failed: e: %d", errno); + return -1; + } + + conn=netFconn_make(sd); + + assert(conn!=NULL); + + if(host_tuple!=NULL) { + netFconn_writef(conn,"GET %s HTTP/1.0\r\nHost: %s\r\nUser-agent: Continuity httpclient\r\n\r\n", + uri, host_tuple); + } else { + netFconn_writef(conn,"GET %s HTTP/1.0\r\nUser-agent: Continuity httpclient\r\n\r\n", + uri); + } + reader=netFreader_init(); + + assert(reader!=NULL); + + while(netFconn_read(conn,reader,buf,sizeof(buf))>0) { + printf("%s", buf); + } + fflush(stdout); + + netFreader_free(reader); + netFconn_close(conn); + netFconn_free(conn); +} + +int main(int argc, char **argv) { + + mecha_init(); + + logFmsg(0,"httpclient v1.00"); + logFmsg(0,"Copyright (c) 2004, Alex Leigh"); + + extern char *optarg; + int ret; + int u=0, p=0, s=0, h=0; + char *u_arg=NULL, *p_arg=NULL, *s_arg=NULL, *h_arg=NULL; + int err=0; + + while((ret=getopt(argc, argv, "u:p:s:h:"))!=EOF) { + switch(ret) { + case 'u': + if(u==1) { + err++; + } else { + u++; + } + u_arg=optarg; + break; + case 'p': + if(p==1) { + err++; + } else { + p++; + } + p_arg=optarg; + break; + case 's': + if(s==1) { + err++; + } else { + s++; + } + s_arg=optarg; + break; + case 'h': + if(h==1) { + err++; + } else { + h++; + } + h_arg=optarg; + break; + default: + err++; + } + } + + if(s==0 || p==0 || u==0) { + err++; + } + + if(s_arg==NULL || p_arg==NULL || u_arg==NULL) { + err++; + } + + if(err>0) { + printf("Usage: httpclient -s server -p port -u uri [-h http_host]\n"); + exit(0); + } + + request(u_arg, s_arg, p_arg, h_arg); + + exit(0); +} + + + diff --git a/mk4/install-sh b/mk4/install-sh new file mode 100644 index 0000000..e9de238 --- /dev/null +++ b/mk4/install-sh @@ -0,0 +1,251 @@ +#!/bin/sh +# +# install - install a program, script, or datafile +# This comes from X11R5 (mit/util/scripts/install.sh). +# +# Copyright 1991 by the Massachusetts Institute of Technology +# +# Permission to use, copy, modify, distribute, and sell this software and its +# documentation for any purpose is hereby granted without fee, 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 M.I.T. not be used in advertising or +# publicity pertaining to distribution of the software without specific, +# written prior permission. M.I.T. makes no representations about the +# suitability of this software for any purpose. It is provided "as is" +# without express or implied warranty. +# +# 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 "install: no input file specified" + exit 1 +else + true +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d $dst ]; then + instcmd=: + chmodcmd="" + else + instcmd=mkdir + 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 -o -d $src ] + then + true + else + echo "install: $src does not exist" + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "install: no destination specified" + exit 1 + else + true + 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 + true + 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 + true + fi + + pathcomp="${pathcomp}/" +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd $dst && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; 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 + true + fi + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + + $doit $instcmd $src $dsttmp && + + trap "rm -f ${dsttmp}" 0 && + +# 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 true;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && + +# Now rename the file to the real destination. + + $doit $rmcmd -f $dstdir/$dstfile && + $doit $mvcmd $dsttmp $dstdir/$dstfile + +fi && + + +exit 0 diff --git a/mk4/lib/CVS/Entries b/mk4/lib/CVS/Entries new file mode 100644 index 0000000..05d7329 --- /dev/null +++ b/mk4/lib/CVS/Entries @@ -0,0 +1,3 @@ +D/aura//// +D/causality//// +D/causality-client//// diff --git a/mk4/lib/CVS/Repository b/mk4/lib/CVS/Repository new file mode 100644 index 0000000..65dbf85 --- /dev/null +++ b/mk4/lib/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/lib diff --git a/mk4/lib/CVS/Root b/mk4/lib/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/lib/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/lib/CVS/Tag b/mk4/lib/CVS/Tag new file mode 100644 index 0000000..3677f37 --- /dev/null +++ b/mk4/lib/CVS/Tag @@ -0,0 +1 @@ +Tmk4_mod6_rc2 diff --git a/mk4/lib/aura/CVS/Entries b/mk4/lib/aura/CVS/Entries new file mode 100644 index 0000000..ecabe18 --- /dev/null +++ b/mk4/lib/aura/CVS/Entries @@ -0,0 +1,4 @@ +/Makefile/1.4/Thu May 13 07:48:44 2004//Tmk4_mod6_rc2 +D/include//// +D/scripts//// +D/src//// diff --git a/mk4/lib/aura/CVS/Repository b/mk4/lib/aura/CVS/Repository new file mode 100644 index 0000000..34f8ab2 --- /dev/null +++ b/mk4/lib/aura/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/lib/aura diff --git a/mk4/lib/aura/CVS/Root b/mk4/lib/aura/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/lib/aura/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/lib/aura/CVS/Tag b/mk4/lib/aura/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/lib/aura/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/lib/aura/Makefile b/mk4/lib/aura/Makefile new file mode 100644 index 0000000..126f064 --- /dev/null +++ b/mk4/lib/aura/Makefile @@ -0,0 +1,13 @@ +CONTINUITY = ../../continuity + +TARGET = aura +TARGETTYPE = shared static + +SOURCES = src/serialization.c src/typelocator.c src/basictypes.c \ + src/serializationinfo.c src/iterator.c src/memutil.c \ + src/stringdictionary.c src/list_iterator.c + +INCLUDES += -Iinclude +#LOCAL_CFLAGS += + +include $(CONTINUITY)/lib/build.mk diff --git a/mk4/lib/aura/include/CVS/Entries b/mk4/lib/aura/include/CVS/Entries new file mode 100644 index 0000000..a3adbf8 --- /dev/null +++ b/mk4/lib/aura/include/CVS/Entries @@ -0,0 +1,10 @@ +/basictypes.h/1.1/Wed Apr 28 06:12:24 2004//Tmk4_mod6_rc2 +/iterator.h/1.5/Thu May 13 00:04:41 2004//Tmk4_mod6_rc2 +/list_iterator.h/1.1/Wed Apr 28 07:07:20 2004//Tmk4_mod6_rc2 +/memutil.h/1.1/Wed Apr 28 06:12:24 2004//Tmk4_mod6_rc2 +/serialization.h/1.2/Fri Apr 30 19:14:07 2004//Tmk4_mod6_rc2 +/serializationinfo.h/1.1/Wed Apr 28 06:12:24 2004//Tmk4_mod6_rc2 +/stringdictionary.h/1.3/Fri May 14 06:20:32 2004//Tmk4_mod6_rc2 +/type.h/1.3/Fri May 14 06:20:32 2004//Tmk4_mod6_rc2 +/typelocator.h/1.1/Wed Apr 28 06:12:24 2004//Tmk4_mod6_rc2 +D diff --git a/mk4/lib/aura/include/CVS/Repository b/mk4/lib/aura/include/CVS/Repository new file mode 100644 index 0000000..0bb85eb --- /dev/null +++ b/mk4/lib/aura/include/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/lib/aura/include diff --git a/mk4/lib/aura/include/CVS/Root b/mk4/lib/aura/include/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/lib/aura/include/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/lib/aura/include/CVS/Tag b/mk4/lib/aura/include/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/lib/aura/include/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/aura/basictypes.h b/mk4/lib/aura/include/basictypes.h similarity index 100% rename from aura/basictypes.h rename to mk4/lib/aura/include/basictypes.h diff --git a/aura/iterator.h b/mk4/lib/aura/include/iterator.h similarity index 100% rename from aura/iterator.h rename to mk4/lib/aura/include/iterator.h diff --git a/aura/list_iterator.h b/mk4/lib/aura/include/list_iterator.h similarity index 100% rename from aura/list_iterator.h rename to mk4/lib/aura/include/list_iterator.h diff --git a/aura/memutil.h b/mk4/lib/aura/include/memutil.h similarity index 100% rename from aura/memutil.h rename to mk4/lib/aura/include/memutil.h diff --git a/mk4/lib/aura/include/serialization.h b/mk4/lib/aura/include/serialization.h new file mode 100644 index 0000000..54e83da --- /dev/null +++ b/mk4/lib/aura/include/serialization.h @@ -0,0 +1,30 @@ +#ifndef __SERIALIZATION_H_ +#define __SERIALIZATION_H_ + +#include + +#include "type.h" +#include "serializationinfo.h" +#include "iterator.h" + + +dynTstring * serialization_serializeType (const char *typeName, void *field); +bool serialization_deserializeType (const char *typeName, void *field, dynTstring *serializationData); + +dynTstring * serialization_serialize (SerializationInfo *info); +SerializationInfo * serialization_deserialize (dynTstring *string); + +dynTstring * serialization_serializeList (lstTlist *list); +lstTlist * serialization_deserializeList (dynTstring *string); + + +// -aleigh +//typedef __typeof__ (void (*) (void *context, void *element)) DeserializationCallback; + +typedef void *(*DeserializationCallback)(void *context, void *element); + +dynTstring * serialization_serializeTypeList (const char *typeName, Iterator *iterator); +bool serialization_deserializeTypeList (const char *typeName, dynTstring *serializationData, + DeserializationCallback callback, void *context); + +#endif diff --git a/mk4/lib/aura/include/serializationinfo.h b/mk4/lib/aura/include/serializationinfo.h new file mode 100644 index 0000000..febc0ba --- /dev/null +++ b/mk4/lib/aura/include/serializationinfo.h @@ -0,0 +1,18 @@ +#ifndef __SERIALIZATIONINFO_H_ +#define __SERIALIZATIONINFO_H_ + +#include + +typedef struct s_SerializationInfo SerializationInfo; + +SerializationInfo *serializationinfo_new (void); +void serializationinfo_addValue (SerializationInfo *info, const char *key, dynTstring *value); +dynTstring * serializationinfo_getValue (SerializationInfo *info, const char *key); +void serializationinfo_destroy (void *ptr); + +void serializationinfo_addValueData (SerializationInfo *info, const char *key, int keyLen, dynTstring *value); + +hshTiterator * serializationinfo_getIterator (SerializationInfo *info); +void serializationinfo_destroyIterator (hshTiterator *iter); + +#endif diff --git a/mk4/lib/aura/include/stringdictionary.h b/mk4/lib/aura/include/stringdictionary.h new file mode 100644 index 0000000..8fbe898 --- /dev/null +++ b/mk4/lib/aura/include/stringdictionary.h @@ -0,0 +1,18 @@ +#ifndef __STRINGDICTIONARY_H_ +#define __STRINGDICTIONARY_H_ + +#include "mecha.h" + +typedef struct s_StringDictionary StringDictionary; + +StringDictionary * stringdictionary_new (void); +void stringdictionary_destroy (void *ptr); + +void stringdictionary_setValue (StringDictionary *info, const char *key, dynTstring *value); +bool stringdictionary_addValue (StringDictionary *info, const char *key, dynTstring *value); + +dynTstring * stringdictionary_getValue (StringDictionary *info, const char *key); + +hshTiterator * stringdictionary_getIterator (StringDictionary *dict); + +#endif diff --git a/mk4/lib/aura/include/type.h b/mk4/lib/aura/include/type.h new file mode 100644 index 0000000..1d4e269 --- /dev/null +++ b/mk4/lib/aura/include/type.h @@ -0,0 +1,26 @@ +#ifndef __TYPE_H__ +#define __TYPE_H__ + +#include "mecha.h" + +#include "serializationinfo.h" + +#define DEREFERENCE_TYPE(__type,__y) ((__type *) *((__type **) __y)) + +// -aleigh +// typedef __typeof__ (bool (*) (void *, SerializationInfo *)) SerializeDelegate; +// typedef __typeof__ (bool (*) (void *, SerializationInfo *)) DeserializeDelegate; + +typedef bool (*SerializeDelegate)(void *, SerializationInfo *); +typedef bool (*DeserializeDelegate)(void *, SerializationInfo *); + +typedef struct s_Type Type; + +struct s_Type +{ + const char *name; + SerializeDelegate serialize; + DeserializeDelegate deserialize; +}; + +#endif diff --git a/aura/typelocator.h b/mk4/lib/aura/include/typelocator.h similarity index 100% rename from aura/typelocator.h rename to mk4/lib/aura/include/typelocator.h diff --git a/mk4/lib/aura/scripts/CVS/Entries b/mk4/lib/aura/scripts/CVS/Entries new file mode 100644 index 0000000..892b284 --- /dev/null +++ b/mk4/lib/aura/scripts/CVS/Entries @@ -0,0 +1,2 @@ +/create_aura_class.pl/1.1/Wed Apr 28 06:12:24 2004//Tmk4_mod6_rc2 +D diff --git a/mk4/lib/aura/scripts/CVS/Repository b/mk4/lib/aura/scripts/CVS/Repository new file mode 100644 index 0000000..c11067b --- /dev/null +++ b/mk4/lib/aura/scripts/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/lib/aura/scripts diff --git a/mk4/lib/aura/scripts/CVS/Root b/mk4/lib/aura/scripts/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/lib/aura/scripts/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/lib/aura/scripts/CVS/Tag b/mk4/lib/aura/scripts/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/lib/aura/scripts/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/lib/aura/scripts/create_aura_class.pl b/mk4/lib/aura/scripts/create_aura_class.pl new file mode 100644 index 0000000..cca8875 --- /dev/null +++ b/mk4/lib/aura/scripts/create_aura_class.pl @@ -0,0 +1,138 @@ +#!/usr/bin/env perl + +use strict; +use warnings; +use File::Basename; + +my $source_data = q| +#include + +#include "%CLASS_AS_PREFIX%.h" + +struct s_%CLASS% +{ + /* insert fields here */ +}; + +%CLASS% * +%CLASS_AS_PREFIX%_new (void) +{ + %CLASS% *instance = (%CLASS% *) malloc (sizeof (%CLASS%)); + + /* initialize other fields */ + + return (instance); +} + +void +%CLASS_AS_PREFIX%_destroy (void *ptr) +{ + %CLASS% *instance = (%CLASS% *) ptr; + + /* free other fields */ + + free (instance); +} +|; + +my $include_data = q| +#ifndef __%CLASS_AS_PREFIX_UPPER%_H__ +#define __%CLASS_AS_PREFIX_UPPER%_H__ + +typedef struct s_%CLASS% %CLASS%; + +%CLASS% * %CLASS_AS_PREFIX%_new (void); +void %CLASS_AS_PREFIX%_destroy (void *ptr); + +#endif +|; + +exit (main(@ARGV)); + +sub main +{ + my @argv = @_; + + if (!defined ($argv[0])) + { + print "usage: " . basename ($0) . " \n"; + + return (1); + } + + my $class = $argv[0]; + + my $class_prefix = get_class_prefix ($class); + + if (!-d "include" || !-d "src") + { + print "Error: This must be ran from a directory containing \"include\" and \"src\".\n"; + + return (2); + } + + my $include_file = "include/" . $class_prefix . ".h"; + my $src_file = "src/" . $class_prefix . ".c"; + + if (-f $include_file || -f $src_file) + { + print "Error: Cannot overwrite existing files.\n"; + + return (3); + } + + open (FILE, "> $include_file") || die "$include_file: $^E"; + + print FILE get_include ($class); + + close (FILE); + + open (FILE, "> $src_file") || die "$src_file: $^E"; + + print FILE get_source ($class); + + close (FILE); + + return (0); +} + +sub get_source($) +{ + my ($class) = @_; + + return (update_string_for_class ($class, $source_data)); +} + +sub get_include($) +{ + my ($class) = @_; + + return (update_string_for_class ($class, $include_data)); +} + +sub update_string_for_class ($$) +{ + my ($class, $data) = @_; + + my $class_as_prefix = &get_class_prefix ($class); + + my $class_as_prefix_upper = uc ($class_as_prefix); + + $data =~ s/%CLASS%/$class/g; + $data =~ s/%CLASS_AS_PREFIX%/$class_as_prefix/g; + $data =~ s/%CLASS_AS_PREFIX_UPPER%/$class_as_prefix_upper/g; + + return ($data); +} + +sub get_class_prefix ($) +{ + my ($class) = @_; + + #(my $class_as_prefix = $class) =~ s/([A-Z]*)([A-Z])([^A-Z])/lc ($1) . "_" . lc ($2) . $3/eg; + (my $class_as_prefix = $class) =~ s/([A-Z]*)([A-Z])([^A-Z])/\L$1_$2\E$3/g; + + $class_as_prefix =~ s/^_+//g; + + return ($class_as_prefix); +} diff --git a/mk4/lib/aura/src/.cvsignore b/mk4/lib/aura/src/.cvsignore new file mode 100644 index 0000000..39a0668 --- /dev/null +++ b/mk4/lib/aura/src/.cvsignore @@ -0,0 +1 @@ +.deps diff --git a/mk4/lib/aura/src/CVS/Entries b/mk4/lib/aura/src/CVS/Entries new file mode 100644 index 0000000..fe3aa01 --- /dev/null +++ b/mk4/lib/aura/src/CVS/Entries @@ -0,0 +1,10 @@ +/.cvsignore/1.1/Wed Apr 28 06:12:24 2004//Tmk4_mod6_rc2 +/basictypes.c/1.1/Wed Apr 28 06:12:24 2004//Tmk4_mod6_rc2 +/iterator.c/1.2/Wed Apr 28 07:07:20 2004//Tmk4_mod6_rc2 +/list_iterator.c/1.1/Wed Apr 28 07:07:20 2004//Tmk4_mod6_rc2 +/memutil.c/1.3/Thu Jun 3 14:32:48 2004//Tmk4_mod6_rc2 +/serialization.c/1.2/Fri May 14 19:12:09 2004//Tmk4_mod6_rc2 +/serializationinfo.c/1.1/Wed Apr 28 06:12:24 2004//Tmk4_mod6_rc2 +/stringdictionary.c/1.3/Fri May 14 06:20:32 2004//Tmk4_mod6_rc2 +/typelocator.c/1.2/Fri May 14 19:12:09 2004//Tmk4_mod6_rc2 +D diff --git a/mk4/lib/aura/src/CVS/Repository b/mk4/lib/aura/src/CVS/Repository new file mode 100644 index 0000000..fa31cbb --- /dev/null +++ b/mk4/lib/aura/src/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/lib/aura/src diff --git a/mk4/lib/aura/src/CVS/Root b/mk4/lib/aura/src/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/lib/aura/src/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/lib/aura/src/CVS/Tag b/mk4/lib/aura/src/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/lib/aura/src/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/aura/basictypes.c b/mk4/lib/aura/src/basictypes.c similarity index 100% rename from aura/basictypes.c rename to mk4/lib/aura/src/basictypes.c diff --git a/aura/iterator.c b/mk4/lib/aura/src/iterator.c similarity index 100% rename from aura/iterator.c rename to mk4/lib/aura/src/iterator.c diff --git a/mk4/lib/aura/src/list_iterator.c b/mk4/lib/aura/src/list_iterator.c new file mode 100644 index 0000000..fdecfea --- /dev/null +++ b/mk4/lib/aura/src/list_iterator.c @@ -0,0 +1,86 @@ + +#include + +#include "mecha.h" + +#include "iterator.h" + +#include "list_iterator.h" + +struct s_ListIterator +{ + IIterator interface; + + lstTlist *list; + lstTlist_elem *cur_elem; + + int list_size; +}; + + +static IteratorStatus list_iterator_next (IIterator *inst); +static void * list_iterator_value (IIterator *inst); + +ListIterator * +list_iterator_new (lstTlist *list) +{ + ListIterator *instance = (ListIterator *) malloc (sizeof (ListIterator)); + + instance->interface.next = list_iterator_next; + instance->interface.get_value = list_iterator_value; + instance->interface.destroy = list_iterator_destroy; + + instance->list = list; + instance->cur_elem = NULL; + + instance->list_size = lstFlist_size (list); + + return (instance); +} + +void +list_iterator_destroy (IIterator *inst) +{ + ListIterator *instance = (ListIterator *) inst; + + free (instance); +} + +static IteratorStatus +list_iterator_next (IIterator *inst) +{ + ListIterator *instance = (ListIterator *) inst; + + if (lstFlist_size (instance->list) != instance->list_size) + { + return (IteratorOutOfSync); + } + + if (instance->cur_elem == NULL) + { + instance->cur_elem = lstFlist_head (instance->list); + } + else + { + instance->cur_elem = lstFlist_next (instance->cur_elem); + } + + if (instance->cur_elem != NULL) + { + return (IteratorSuccess); + } + else + { + return (IteratorEnd); + } +} + +static void * +list_iterator_value (IIterator *inst) +{ + ListIterator *instance = (ListIterator *) inst; + + assert (instance->cur_elem != NULL); + + return (lstFlist_data (instance->cur_elem)); +} diff --git a/mk4/lib/aura/src/memutil.c b/mk4/lib/aura/src/memutil.c new file mode 100644 index 0000000..6c6e81f --- /dev/null +++ b/mk4/lib/aura/src/memutil.c @@ -0,0 +1,37 @@ + +#include + +#ifndef DARWIN +#include +#endif + +#include "memutil.h" + +void +memutil_printMemAllocated() +{ +#ifdef LINUX + struct mallinfo info; + + info = mallinfo(); + + printf ("= allocated: %d\n", info.uordblks); +#else + printf("memutil_printMemAllocated() not supported on Darwin."); +#endif + +} + +int +memutil_getMemAllocated() +{ +#ifdef LINUX + struct mallinfo info; + + info = mallinfo(); + + return (info.uordblks); +#else + return 0; +#endif +} diff --git a/mk4/lib/aura/src/serialization.c b/mk4/lib/aura/src/serialization.c new file mode 100644 index 0000000..3ca9615 --- /dev/null +++ b/mk4/lib/aura/src/serialization.c @@ -0,0 +1,355 @@ + +#include + +#include "serialization.h" +#include "type.h" +#include "typelocator.h" +#include "serializationinfo.h" +#include "iterator.h" + +#include + +dynTstring * +serialization_serializeType (const char *typeName, void *field) +{ + SerializationInfo *info; + dynTstring *string = NULL; + bool serialize_result; + Type *type; + + type = typelocator_getType (typelocator_getLocator(), typeName); + + if (type == NULL) + { + logFmsg (CONT_LOG_ERROR, "unknown type: %s", typeName); + + return (NULL); + } + + info = serializationinfo_new(); + + serialize_result = type->serialize (field, info); + + if (serialize_result == true) + { + string = serialization_serialize (info); + } + + serializationinfo_destroy (info); + + /* returning the string if successful, and otherwise, NULL */ + return (string); +} + +bool +serialization_deserializeType (const char *typeName, void *field, dynTstring *serializationData) +{ + SerializationInfo *info; + bool deserialize_result; + Type *type = typelocator_getType (typelocator_getLocator(), typeName); + + if (type == NULL) + { + logFmsg (CONT_LOG_ERROR, "unknown type: %s", typeName); + + return (false); + } + + /* this should likely be updated to take a dynstring */ + info = serialization_deserialize (serializationData); + + if (info == NULL) + { + logFmsg (CONT_LOG_ERROR, "couldn't deserialize %s", typeName); + + serializationinfo_destroy (info); + + return (false); + } + + deserialize_result = type->deserialize (field, info); + + serializationinfo_destroy (info); + + return (deserialize_result); +} + +static const char * +serialization_getStringData (const char *data, char **outData, int *outLen) +{ + char *endptr; + int len = strtol (data, &endptr, 10); + + if (*endptr != '[') + { + logFmsg (CONT_LOG_ERROR, "unknown string: %s", data); + + return (NULL); + } + + *outData = endptr + 1; + *outLen = len; + + /* + * data looks like: + * nn[ssssssss] + * + * where + * n = "number" + * s = "string" + * + * endptr will be at "[" and the number in "nn" will be the length of + * "sss", so all we need to do is add 1 to get to "sss", ad len, and add 1 + * to get to the end of the string + */ + endptr += 1 + len + 1; + + return (endptr); +} + +static const char * +serialization_getString (const char *data, dynTstring *string) +{ + const char *endptr; + char *outData; + int outLen; + + endptr = serialization_getStringData (data, &outData, &outLen); + + if (endptr == NULL) + { + return (NULL); + } + + dynFappend (string, outData, outLen); + + return (endptr); +} + + +dynTstring * +serialization_serializeTypeList (const char *typeName, Iterator *iterator) +{ + dynTstring *string = dynFinit(); + + dynFsappend (string, ""); + + while (iterator_next (iterator) == IteratorSuccess) + { + dynTstring *entry_string; + void *entry; + + entry = iterator_value (iterator); + + entry_string = serialization_serializeType (typeName, &entry); + + dynFappend_print (string, "%d", dynFgetlen (entry_string)); + dynFappend (string, "[", 1); + dynFappend (string, dynFgetstr (entry_string), dynFgetlen (entry_string)); + dynFappend (string, "]", 1); + + dynFfree (entry_string); + } + + iterator_destroy (iterator); + + return (string); +} + +bool +serialization_deserializeTypeList (const char *typeName, dynTstring *serializationData, DeserializationCallback callback, void *context) +{ + int len = dynFgetlen (serializationData); + const char *str_loc = dynFgetstr (serializationData); + + if (strncmp ("", str_loc, 3) != 0) + { + logFmsg (CONT_LOG_ERROR, "not a list: %s", str_loc); + + return (false); + } + else + { + str_loc += 3; + } + + while (str_loc != NULL && ((str_loc - dynFgetstr (serializationData)) < len)) + { + dynTstring *value = dynFinit(); + void *value_object; + + str_loc = serialization_getString (str_loc, value); + + if (serialization_deserializeType (typeName, &value_object, value) == false) + { + logFmsg (CONT_LOG_ERROR, "Couldn't deserialize type %s", typeName); + + dynFfree (value); + + return (false); + } + + dynFfree (value); + + callback (context, value_object); + } + + if (str_loc == NULL) + { + logFmsg (CONT_LOG_ERROR, "error in data: %s", dynFgetstr (serializationData)); + + return (false); + } + + return (true); +} + +dynTstring * +serialization_serialize (SerializationInfo *info) +{ + hshTiterator *iter = serializationinfo_getIterator (info); + dynTstring *string = dynFinit(); + + dynFappend (string, "", 4); + + while (hshFiterator_next (iter) == 1) + { + char *key = (char *) hshFiterator_current_key (iter); + dynTstring *value = (dynTstring *) hshFiterator_current_value (iter); + int key_len = strlen (key); + + dynFappend_print (string, "%d", key_len); + dynFappend (string, "[", 1); + dynFappend (string, key, key_len); + dynFappend (string, "]", 1); + + dynFappend_print (string, "%d", dynFgetlen (value)); + dynFappend (string, "[", 1); + dynFappend (string, dynFgetstr (value), dynFgetlen (value)); + dynFappend (string, "]", 1); + } + + hshFiterator_free (iter); + + return (string); +} + +SerializationInfo * +serialization_deserialize (dynTstring *string) +{ + SerializationInfo *info; + const char *str_loc = dynFgetstr (string); + + if (strncmp ("", str_loc, 4) != 0) + { + logFmsg (CONT_LOG_ERROR, "Not a SerializationInfo object: %s", dynFgetstr (string)); + + return (NULL); + } + else + { + str_loc += 4; + } + + info = serializationinfo_new(); + + while (str_loc != NULL && ((unsigned int) (str_loc - dynFgetstr (string)) < dynFgetlen (string))) + { + char *key; + int keyLen; + dynTstring *value; + + str_loc = serialization_getStringData (str_loc, &key, &keyLen); + + if (str_loc == NULL) + { + logFmsg (CONT_LOG_ERROR, "Wrong number of params in: %s", dynFgetstr (string)); + + serializationinfo_destroy (info); + + return (NULL); + } + + value = dynFinit(); + + str_loc = serialization_getString (str_loc, value); + + /* + * we're passing the value dynTstring to the SerializationInfo object, + * so we don't need to free it ourselves in this call. + */ + serializationinfo_addValueData (info, key, keyLen, value); + } + + if (str_loc == NULL) + { + logFmsg (CONT_LOG_ERROR, "Error in data: %s", dynFgetstr (string)); + serializationinfo_destroy (info); + + return (NULL); + } + + return (info); +} + +dynTstring * +serialization_serializeList (lstTlist *list) +{ + dynTstring *string = dynFinit(); + lstTlist_elem *elem; + + dynFappend (string, "", 3); + + for (elem = lstFlist_head (list); elem != NULL; elem = lstFlist_next (elem)) + { + dynTstring *value = lstFlist_data (elem); + + dynFappend_print (string, "%d", dynFgetlen (value)); + dynFappend (string, "[", 1); + dynFappend (string, dynFgetstr (value), dynFgetlen (value)); + dynFappend (string, "]", 1); + } + + return (string); +} + +lstTlist * +serialization_deserializeList (dynTstring *string) +{ + lstTlist *ser_data; + int len = dynFgetlen (string); + const char *str_loc = dynFgetstr (string); + + if (strncmp ("", str_loc, 3) != 0) + { + logFmsg (CONT_LOG_ERROR, "Not a list: %s", dynFgetstr (string)); + + return (NULL); + } + else + { + str_loc += 3; + } + + ser_data = lstFlist_create ((void (*) (void *)) dynFfree); + + while (str_loc != NULL && ((str_loc - dynFgetstr (string)) < len)) + { + dynTstring *value = dynFinit(); + + str_loc = serialization_getString (str_loc, value); + + lstFlist_add_next (ser_data, lstFlist_tail (ser_data), value); + } + + if (str_loc == NULL) + { + logFmsg (CONT_LOG_ERROR, "Error in data: %s", dynFgetstr (string)); + + lstFlist_free (ser_data); + + return (NULL); + } + + return (ser_data); +} diff --git a/aura/serializationinfo.c b/mk4/lib/aura/src/serializationinfo.c similarity index 100% rename from aura/serializationinfo.c rename to mk4/lib/aura/src/serializationinfo.c diff --git a/mk4/lib/aura/src/stringdictionary.c b/mk4/lib/aura/src/stringdictionary.c new file mode 100644 index 0000000..d622990 --- /dev/null +++ b/mk4/lib/aura/src/stringdictionary.c @@ -0,0 +1,233 @@ + +#include +#include + +#include "mecha.h" + +#include "stringdictionary.h" +#include "serializationinfo.h" +#include "type.h" + +struct s_StringDictionary +{ + hshTvoid_list *table; +}; + +static bool stringdictionary_serialize (void *field, SerializationInfo *info); +static bool stringdictionary_deserialize (void *field, SerializationInfo *info); +static dynTstring * stringdictionary_serializeTable (StringDictionary *dict); +static StringDictionary * strictdictionary_deserializeFromString (dynTstring *string); + +Type type_declaration_StringDictionary = { "StringDictionary", stringdictionary_serialize, stringdictionary_deserialize }; + +StringDictionary * +stringdictionary_new() +{ + StringDictionary *info = (StringDictionary *) malloc (sizeof (StringDictionary)); + info->table = hshFvoid_init ((void (*) (void *)) dynFfree); + + return (info); +} + +void +stringdictionary_destroy (void *ptr) +{ + StringDictionary *info = (StringDictionary *) ptr; + + hshFvoid_destroy (info->table); + + free (info); +} + +bool +stringdictionary_addValue (StringDictionary *info, const char *key, dynTstring *value) +{ + if (hshFvoid_add (info->table, key, value)) + { + return (true); + } + else + { + return (false); + } +} + +void +stringdictionary_setValue (StringDictionary *info, const char *key, dynTstring *value) +{ + hshFvoid_replace (info->table, key, (void *) value); +} + +dynTstring * +stringdictionary_getValue (StringDictionary *info, const char *key) +{ + return ((dynTstring *) hshFvoid_find (info->table, key)); +} + +hshTiterator * +stringdictionary_getIterator (StringDictionary *dict) +{ + return (hshFiterator_init (dict->table)); +} + +static bool +stringdictionary_serialize (void *field, SerializationInfo *info) +{ + StringDictionary *dict = DEREFERENCE_TYPE (StringDictionary, field); + + serializationinfo_addValue (info, "table", + stringdictionary_serializeTable (dict)); + + return (true); +} + +static bool +stringdictionary_deserialize (void *field, SerializationInfo *info) +{ + StringDictionary *dict; + + dict = strictdictionary_deserializeFromString ( + serializationinfo_getValue (info, "table")); + + if (dict == NULL) + { + return (false); + } + else + { + StringDictionary **fieldPtr = (StringDictionary **) field; + + *fieldPtr = dict; + + /* DEREFERENCE_TYPE (StringDictionary, field) = dict; */ + + return (true); + } +} + +static const char * +stringdictionary_deserializeGetString (const char *data, dynTstring *string) +{ + char *endptr; + int len = strtol (data, &endptr, 10); + + if (*endptr != '[') + { + printf ("-- unknown string: %s\n", data); + + return (NULL); + } + + dynFappend (string, endptr + 1, len); + + /* + * data looks like: + * nn[ssssssss] + * + * where + * n = "number" + * s = "string" + * + * endptr will be at "[" and the number in "nn" will be the length of + * "sss", so all we need to do is add 1 to get to "sss", ad len, and add 1 + * to get to the end of the string + */ + endptr += 1 + len + 1; + + return (endptr); +} + +static dynTstring * +stringdictionary_serializeTable (StringDictionary *dict) +{ + hshTiterator *iter = hshFiterator_init (dict->table); + dynTstring *string = dynFinit(); + + dynFsappend (string, ""); + + while (hshFiterator_next (iter) == 1) + { + char *key = (char *) hshFiterator_current_key (iter); + dynTstring *value = (dynTstring *) hshFiterator_current_value (iter); + int key_len = strlen (key); + + dynFappend_print (string, "%d", key_len); + dynFappend (string, "[", 1); + dynFappend (string, key, key_len); + dynFappend (string, "]", 1); + + dynFappend_print (string, "%d", dynFgetlen (value)); + dynFappend (string, "[", 1); + dynFappend (string, dynFgetstr (value), dynFgetlen (value)); + dynFappend (string, "]", 1); + } + + hshFiterator_free (iter); + + return (string); +} + + +static StringDictionary * +strictdictionary_deserializeFromString (dynTstring *string) +{ + StringDictionary *dict; + int len = dynFgetlen (string); + const char *str_loc = dynFgetstr (string); + + if (strncmp ("", str_loc, 4) != 0) + { + printf ("-- not a SerializationInfo object: %s", dynFgetstr (string)); + + return (NULL); + } + else + { + str_loc += 4; + } + + dict = stringdictionary_new(); + + while (str_loc != NULL && ((str_loc - dynFgetstr (string)) < len)) + { + dynTstring *key = dynFinit(); + dynTstring *value; + + str_loc = stringdictionary_deserializeGetString (str_loc, key); + + if (str_loc == NULL) + { + printf ("-- wrong number of params in: %s\n", dynFgetstr (string)); + + stringdictionary_destroy (dict); + + dynFfree (key); + + return (NULL); + } + + value = dynFinit(); + + str_loc = stringdictionary_deserializeGetString (str_loc, value); + + /* + * we're passing the value dynTstring to the SerializationInfo object, + * so we don't need to free it ourselves in this call. + */ + stringdictionary_addValue (dict, dynFgetstr (key), value); + + dynFfree (key); + } + + if (str_loc == NULL) + { + printf ("-- error in data: %s\n", dynFgetstr (string)); + stringdictionary_destroy (dict); + + return (NULL); + } + + return (dict); +} + + diff --git a/aura/typelocator.c b/mk4/lib/aura/src/typelocator.c similarity index 100% rename from aura/typelocator.c rename to mk4/lib/aura/src/typelocator.c diff --git a/mk4/lib/causality-client/CVS/Entries b/mk4/lib/causality-client/CVS/Entries new file mode 100644 index 0000000..dc3e5ad --- /dev/null +++ b/mk4/lib/causality-client/CVS/Entries @@ -0,0 +1,3 @@ +/Makefile/1.1/Thu May 13 21:08:28 2004//Tmk4_mod6_rc2 +D/include//// +D/src//// diff --git a/mk4/lib/causality-client/CVS/Repository b/mk4/lib/causality-client/CVS/Repository new file mode 100644 index 0000000..878dfcc --- /dev/null +++ b/mk4/lib/causality-client/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/lib/causality-client diff --git a/mk4/lib/causality-client/CVS/Root b/mk4/lib/causality-client/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/lib/causality-client/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/lib/causality-client/CVS/Tag b/mk4/lib/causality-client/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/lib/causality-client/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/lib/causality-client/Makefile b/mk4/lib/causality-client/Makefile new file mode 100644 index 0000000..ee0bd3a --- /dev/null +++ b/mk4/lib/causality-client/Makefile @@ -0,0 +1,14 @@ +CONTINUITY = ../../continuity + +TARGET = causality-client +TARGETTYPE = shared static + +SOURCES = src/http_request.c src/http_request_handler.c \ + src/http_request_list.c src/http_request_queue.c \ + src/client.c src/http_response.c src/http_request_list_entry.c + +INCLUDES += -Iinclude -I../aura/include -I../causality/include +STATIC_LIBS += $(CONTINUITY)/lib/libaura.a $(CONTINUITY)/lib/libcausality.a +#LOCAL_CFLAGS += + +include $(CONTINUITY)/lib/build.mk diff --git a/mk4/lib/causality-client/include/CVS/Entries b/mk4/lib/causality-client/include/CVS/Entries new file mode 100644 index 0000000..eec6485 --- /dev/null +++ b/mk4/lib/causality-client/include/CVS/Entries @@ -0,0 +1,8 @@ +/client.h/1.1/Thu May 13 21:08:28 2004//Tmk4_mod6_rc2 +/http_request.h/1.1/Thu May 13 21:08:28 2004//Tmk4_mod6_rc2 +/http_request_handler.h/1.1/Thu May 13 21:08:28 2004//Tmk4_mod6_rc2 +/http_request_list.h/1.1/Thu May 13 21:08:28 2004//Tmk4_mod6_rc2 +/http_request_list_entry.h/1.1/Thu May 13 21:08:28 2004//Tmk4_mod6_rc2 +/http_request_queue.h/1.1/Thu May 13 21:08:28 2004//Tmk4_mod6_rc2 +/http_response.h/1.1/Thu May 13 21:08:28 2004//Tmk4_mod6_rc2 +D diff --git a/mk4/lib/causality-client/include/CVS/Repository b/mk4/lib/causality-client/include/CVS/Repository new file mode 100644 index 0000000..c385c4e --- /dev/null +++ b/mk4/lib/causality-client/include/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/lib/causality-client/include diff --git a/mk4/lib/causality-client/include/CVS/Root b/mk4/lib/causality-client/include/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/lib/causality-client/include/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/lib/causality-client/include/CVS/Tag b/mk4/lib/causality-client/include/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/lib/causality-client/include/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/lib/causality-client/include/client.h b/mk4/lib/causality-client/include/client.h new file mode 100644 index 0000000..9d7bb5f --- /dev/null +++ b/mk4/lib/causality-client/include/client.h @@ -0,0 +1,34 @@ +#ifndef __CLIENT_H__ +#define __CLIENT_H__ + +#include "http_request.h" + +void client_init (const key_t ipcKey); +void client_destroy (void); + +void * client_get_request (void); + +bool client_write_data (HttpRequest *httpRequest, const char *data, int dataLen); + +bool client_write_string (HttpRequest *httpRequest, const char *data); + + +bool client_finish (const HttpRequest *request); + +const char * client_get_uri (const HttpRequest *request); +const char * client_get_query (const HttpRequest *request); +const char * client_get_method (const HttpRequest *request); +const char * client_get_request_header (const HttpRequest *httpRequest, const char *key); +const char * client_get_variable (const HttpRequest *httpRequest, char *key); +int client_get_entity (HttpRequest *httpRequest, char *buf, int bufLen); +void client_set_status (HttpRequest *httpRequest, const int status, const char *description); + +bool client_is_entire_entity_loaded (const HttpRequest *httpRequest); +bool client_headers_sent (const HttpRequest *request); + + +void client_set_response_header (const HttpRequest *httpRequest, const char *key, const char *value); + +const char * client_get_remote_ip (HttpRequest *instance); + +#endif diff --git a/mk4/lib/causality-client/include/http_request.h b/mk4/lib/causality-client/include/http_request.h new file mode 100644 index 0000000..2db8a9e --- /dev/null +++ b/mk4/lib/causality-client/include/http_request.h @@ -0,0 +1,57 @@ +#ifndef __HTTP_REQUEST_H__ +#define __HTTP_REQUEST_H__ + +#include "message.h" +#include "processor.h" + +/* from continuity.h */ +#ifndef STATUS_OK + +#define STATUS_OK 1 +#define STATUS_ERROR 2 +#define STATUS_PROCEED 3 +#define STATUS_EXIT 4 +#define STATUS_RESTART 5 + +#endif + +typedef struct s_HttpRequest HttpRequest; + +HttpRequest * http_request_new (Message *requestMessage, Processor *processor); +void http_request_destroy (void *ptr); + +const char * http_request_getToken (const HttpRequest *request); +const char * http_request_getUri (const HttpRequest *request); +const char * http_request_getQuery (const HttpRequest *request); +const char * http_request_getMethod (const HttpRequest *request); +const char * http_request_getDocRoot (const HttpRequest *request); +const char * http_request_getRemoteIP (const HttpRequest *request); + +const dynTstring * http_request_getVariableString (const HttpRequest *request, const char *variable); +const char * http_request_getVariable (const HttpRequest *request, const char *variable); + +const char * http_request_getRequestHeader (const HttpRequest *request, const char *key); +const dynTstring * http_request_getRequestHeaderString (const HttpRequest *request, const char *key); + +bool http_request_writeData (HttpRequest *request, const char *data, int dataLen); +bool http_request_writeString (HttpRequest *request, const char *data); + +bool http_request_finish (const HttpRequest *request); + +int http_request_getEntity (HttpRequest *request, char *outBuf, int bufLen); +bool http_request_isEntireEntityLoaded (const HttpRequest *request); + +const dynTstring * http_request_getEntireEntity (HttpRequest *instance); + +void http_request_setResponseHeader (const HttpRequest *request, const char *key, const char *value); +void http_request_setResponseHeaderData (const HttpRequest *request, const char *key, const char *value, int valueLen); + +void http_request_setHttpStatus (HttpRequest *request, int status, const char *description); + +bool http_request_finishStatus (const HttpRequest *request, int status); + +bool http_request_headersSent (const HttpRequest *request); + +hshTiterator * http_request_getRequestHeaderIterator (const HttpRequest *request); + +#endif diff --git a/mk4/lib/causality-client/include/http_request_handler.h b/mk4/lib/causality-client/include/http_request_handler.h new file mode 100644 index 0000000..ef53023 --- /dev/null +++ b/mk4/lib/causality-client/include/http_request_handler.h @@ -0,0 +1,12 @@ +#ifndef __HTTP_REQUEST_HANDLER_H__ +#define __HTTP_REQUEST_HANDLER_H__ + +#include "message.h" + +Message * http_request_handler_handleRequest (void *context, Message *requestMessage); +Message * http_request_handler_handlePing (void *context, Message *requestMessage); + +extern CommandHandler command_HttpRequestStart; +extern CommandHandler command_HttpRequestPing; + +#endif diff --git a/mk4/lib/causality-client/include/http_request_list.h b/mk4/lib/causality-client/include/http_request_list.h new file mode 100644 index 0000000..40c326a --- /dev/null +++ b/mk4/lib/causality-client/include/http_request_list.h @@ -0,0 +1,30 @@ +#ifndef __HTTP_REQUEST_LIST_H__ +#define __HTTP_REQUEST_LIST_H__ + +#include "message.h" +#include "http_request.h" + +typedef struct s_HttpRequestList HttpRequestList; + +typedef void (*HttpRequestHandlerDelegate) (HttpRequest *request, void *context); + +HttpRequestList * http_request_list_new (void); +void http_request_list_destroy (void *ptr); + +void http_request_list_addRequest (HttpRequestList *requestList, HttpRequest *request); + +void http_request_list_setHandler (HttpRequestList *instance, + HttpRequestHandlerDelegate delegate, void *context); + +HttpRequestList * http_request_list_getRequestList (void); + +void http_request_list_handler (Message *requestMessage); + +HttpRequest * http_request_list_getNextRequest (HttpRequestList *requestList); + +void http_request_list_removeRequest (HttpRequestList *requestList, const char *token); + +bool http_request_list_containsRequest (HttpRequestList *requestList, const char *token); + + +#endif diff --git a/mk4/lib/causality-client/include/http_request_list_entry.h b/mk4/lib/causality-client/include/http_request_list_entry.h new file mode 100644 index 0000000..c0207e4 --- /dev/null +++ b/mk4/lib/causality-client/include/http_request_list_entry.h @@ -0,0 +1,16 @@ + +#ifndef __HTTP_REQUEST_LIST_ENTRY_H__ +#define __HTTP_REQUEST_LIST_ENTRY_H__ + +#include "http_request_list.h" + +typedef struct s_HttpRequestListEntry HttpRequestListEntry; + +HttpRequestListEntry * +http_request_list_entry_new (HttpRequestHandlerDelegate delegate, + HttpRequest *request, void *context); +void http_request_list_entry_destroy (void *ptr); + +void http_request_list_entry_invokeEntry (void *ptr); + +#endif diff --git a/mk4/lib/causality-client/include/http_request_queue.h b/mk4/lib/causality-client/include/http_request_queue.h new file mode 100644 index 0000000..0bc2c8e --- /dev/null +++ b/mk4/lib/causality-client/include/http_request_queue.h @@ -0,0 +1,15 @@ +#ifndef __HTTP_REQUEST_QUEUE_H__ +#define __HTTP_REQUEST_QUEUE_H__ + +#include "http_request.h" + +typedef struct s_HttpRequestQueue HttpRequestQueue; + +HttpRequestQueue * http_request_queue_new (void); + +void http_request_queue_destroy (void *ptr); + +HttpRequest * http_request_queue_getRequest (HttpRequestQueue *resp); +void http_request_queue_addRequest (HttpRequestQueue *resp, HttpRequest *request); + +#endif diff --git a/mk4/lib/causality-client/include/http_response.h b/mk4/lib/causality-client/include/http_response.h new file mode 100644 index 0000000..c26a99d --- /dev/null +++ b/mk4/lib/causality-client/include/http_response.h @@ -0,0 +1,12 @@ +#ifndef __HTTP_RESPONSE_H__ +#define __HTTP_RESPONSE_H__ + +bool http_response_sendWriteMessage (Processor *processor, const char *token, const char *data, int dataLen); + +bool http_response_sendFinishMessage (Processor *processor, const char *token, int returnStatus); + +bool http_response_sendReadEntityBody (Processor *processor, const char *token, dynTstring *entity); + +bool http_response_sendSimpleMessage (Processor *processor, Message *requestMessage); + +#endif diff --git a/mk4/lib/causality-client/src/CVS/Entries b/mk4/lib/causality-client/src/CVS/Entries new file mode 100644 index 0000000..d191e5b --- /dev/null +++ b/mk4/lib/causality-client/src/CVS/Entries @@ -0,0 +1,8 @@ +/client.c/1.2/Fri May 14 16:51:25 2004//Tmk4_mod6_rc2 +/http_request.c/1.1/Thu May 13 21:08:28 2004//Tmk4_mod6_rc2 +/http_request_handler.c/1.2/Fri May 14 15:28:08 2004//Tmk4_mod6_rc2 +/http_request_list.c/1.1/Thu May 13 21:08:28 2004//Tmk4_mod6_rc2 +/http_request_list_entry.c/1.1/Thu May 13 21:08:28 2004//Tmk4_mod6_rc2 +/http_request_queue.c/1.1/Thu May 13 21:08:28 2004//Tmk4_mod6_rc2 +/http_response.c/1.2/Fri May 14 19:12:09 2004//Tmk4_mod6_rc2 +D diff --git a/mk4/lib/causality-client/src/CVS/Repository b/mk4/lib/causality-client/src/CVS/Repository new file mode 100644 index 0000000..a76d10f --- /dev/null +++ b/mk4/lib/causality-client/src/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/lib/causality-client/src diff --git a/mk4/lib/causality-client/src/CVS/Root b/mk4/lib/causality-client/src/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/lib/causality-client/src/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/lib/causality-client/src/CVS/Tag b/mk4/lib/causality-client/src/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/lib/causality-client/src/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/lib/causality-client/src/client.c b/mk4/lib/causality-client/src/client.c new file mode 100644 index 0000000..7fc3b7e --- /dev/null +++ b/mk4/lib/causality-client/src/client.c @@ -0,0 +1,141 @@ + +#include + +#include "client.h" + +#include "command_handlers.h" +#include "http_request_handler.h" + +#include "http_request_list.h" +#include "http_response.h" + +Processor *g_processor; + +void +client_init (const key_t ipcKey) +{ + logFinit(); + + logFmsg (CONT_LOG_DEBUG, "causality-client/%d: initting client.", getpid()); + + thrFmod_init(); + + g_processor = processor_new (ipcKey, true); + + processor_addRequestHandler (g_processor, &command_HttpRequestStart, g_processor); + processor_addRequestHandler (g_processor, &command_HttpRequestPing, NULL); + + processor_finishedInit (g_processor); + + logFmsg (CONT_LOG_DEBUG, "causality-client/%d: finished initting client.", getpid()); +} + +void +client_destroy() +{ + HttpRequestList *requestList = http_request_list_getRequestList(); + + http_request_list_destroy (requestList); + + processor_destroy (g_processor); +} + +void * +client_get_request() +{ + HttpRequestList *requestList = http_request_list_getRequestList(); + HttpRequest *request = http_request_list_getNextRequest (requestList); + + return (request); +} + +bool +client_write_data (HttpRequest *httpRequest, const char *data, int dataLen) +{ + return (http_request_writeData (httpRequest, data, dataLen)); +} + +bool +client_write_string (HttpRequest *httpRequest, const char *data) +{ + return (http_request_writeString (httpRequest, data)); +} + +const char * +client_get_remote_ip (HttpRequest *instance) +{ + return (http_request_getRemoteIP (instance)); +} + +const char * +client_get_uri (const HttpRequest *httpRequest) +{ + return (http_request_getUri (httpRequest)); +} + +const char * +client_get_query (const HttpRequest *httpRequest) +{ + return (http_request_getQuery (httpRequest)); +} + +const char * +client_get_variable (const HttpRequest *httpRequest, char *key) +{ + return (http_request_getVariable (httpRequest, key)); +} + +const char * +client_get_request_header (const HttpRequest *httpRequest, const char *key) +{ + return (http_request_getRequestHeader (httpRequest, key)); +} + +const char * +client_get_method (const HttpRequest *httpRequest) +{ + return (http_request_getMethod (httpRequest)); +} + +int +client_get_entity (HttpRequest *httpRequest, char *buf, int bufLen) +{ + return (http_request_getEntity (httpRequest, buf, bufLen)); +} + +bool +client_is_entire_entity_loaded (const HttpRequest *httpRequest) +{ + return (http_request_isEntireEntityLoaded (httpRequest)); +} + +void +client_set_response_header (const HttpRequest *httpRequest, const char *key, const char *value) +{ + http_request_setResponseHeader (httpRequest, key, value); +} + +void +client_set_status (HttpRequest *httpRequest, const int status, const char *description) +{ + http_request_setHttpStatus (httpRequest, status, description); +} + +bool +client_headers_sent (const HttpRequest *request) +{ + return (http_request_headersSent (request)); +} + +bool +client_finish (const HttpRequest *httpRequest) +{ + bool ret; + + ret = http_request_finish (httpRequest); + + http_request_list_removeRequest (http_request_list_getRequestList(), + http_request_getToken (httpRequest)); + + return (ret); +} diff --git a/mk4/lib/causality-client/src/http_request.c b/mk4/lib/causality-client/src/http_request.c new file mode 100644 index 0000000..6eb752b --- /dev/null +++ b/mk4/lib/causality-client/src/http_request.c @@ -0,0 +1,463 @@ + +#include +#include + +#include + +#include + +#include "http_request.h" +#include "http_response.h" +#include "stringdictionary.h" +#include "serialization.h" + +struct s_HttpRequest +{ + dynTstring *token; + dynTstring *remoteIP; + + bool entityRequested; + unsigned int entityReadOffset; + dynTstring *entity; + + Processor *processor; + + StringDictionary *requestHeaders; + + StringDictionary *transactionVariables; + + int responseStatus; + dynTstring *responseReason; + + bool sentResponseHeaders; + StringDictionary *responseHeaders; +}; + +static bool http_request_setIfNotNull (dynTstring *dest, const dynTstring *src); +static const char *http_request_getInternalString (dynTstring *string); + +HttpRequest * +http_request_new (Message *requestMessage, Processor *processor) +{ + HttpRequest *request = malloc (sizeof (HttpRequest)); + + assert (requestMessage != NULL); + assert (processor != NULL); + + request->token = dynFinit(); + request->remoteIP = dynFinit(); + + request->entityRequested = false; + request->entityReadOffset = 0; + request->entity = dynFinit(); + + request->processor = processor; + + http_request_setIfNotNull (request->token, + message_getParameterString (requestMessage, "token")); + + http_request_setIfNotNull (request->remoteIP, + message_getParameterString (requestMessage, "remoteIP")); + + { + dynTstring *value = message_getParameterString (requestMessage, + "headers"); + + if (value != NULL) + { + serialization_deserializeType ("StringDictionary", + &request->requestHeaders, value); + } + else + { + request->requestHeaders = stringdictionary_new(); + } + } + + { + dynTstring *value = message_getParameterString (requestMessage, + "variables"); + + if (value != NULL) + { + serialization_deserializeType ("StringDictionary", + &request->transactionVariables, value); + } + else + { + request->transactionVariables = stringdictionary_new(); + } + } + + request->responseHeaders = stringdictionary_new(); + request->sentResponseHeaders = false; + + request->responseStatus = 200; + request->responseReason = dynFinit(); + + return (request); +} + +void +http_request_destroy (void *ptr) +{ + HttpRequest *request = (HttpRequest *) ptr; + + assert (request != NULL); + + dynFfree (request->token); + dynFfree (request->remoteIP); + dynFfree (request->entity); + + stringdictionary_destroy (request->requestHeaders); + stringdictionary_destroy (request->responseHeaders); + stringdictionary_destroy (request->transactionVariables); + + dynFfree (request->responseReason); + + free (request); +} + +void +http_request_setHttpStatus (HttpRequest *request, const int status, const char *description) +{ + assert (request != NULL); + + request->responseStatus = status; + + dynFsappend (request->responseReason, description); +} + +const char * +http_request_getToken (const HttpRequest *request) +{ + assert (request != NULL); + + return (dynFgetstr (request->token)); +} + +const char * +http_request_getUri (const HttpRequest *request) +{ + assert (request != NULL); + + return (http_request_getInternalString ( + stringdictionary_getValue (request->transactionVariables, + "uri"))); +} + +const char * +http_request_getQuery (const HttpRequest *request) +{ + assert (request != NULL); + + return (http_request_getInternalString ( + stringdictionary_getValue (request->transactionVariables, + "query"))); +} + +const char * +http_request_getRemoteIP (const HttpRequest *request) +{ + assert (request != NULL); + + return (dynFgetstr (request->remoteIP)); +} + +const dynTstring * +http_request_getVariableString (const HttpRequest *request, const char *variable) +{ + assert (request != NULL); + assert (variable != NULL); + + return (stringdictionary_getValue (request->transactionVariables, + variable)); +} + +const char * +http_request_getVariable (const HttpRequest *request, const char *variable) +{ + assert (request != NULL); + assert (variable != NULL); + + return (http_request_getInternalString ( + stringdictionary_getValue (request->transactionVariables, + variable))); +} + +const char * +http_request_getMethod (const HttpRequest *request) +{ + assert (request != NULL); + + return (http_request_getInternalString ( + stringdictionary_getValue (request->transactionVariables, + "method"))); +} + +bool +http_request_headersSent (const HttpRequest *request) +{ + assert (request != NULL); + + return (request->sentResponseHeaders); +} + +const dynTstring * +http_request_getRequestHeaderString (const HttpRequest *request, const char *key) +{ + assert (request != NULL); + + return (stringdictionary_getValue (request->requestHeaders, key)); +} + +hshTiterator * +http_request_getRequestHeaderIterator (const HttpRequest *request) +{ + return (stringdictionary_getIterator (request->requestHeaders)); +} + +const char * +http_request_getRequestHeader (const HttpRequest *request, const char *key) +{ + dynTstring *stringValue; + + assert (request != NULL); + assert (key != NULL); + + stringValue = stringdictionary_getValue (request->requestHeaders, key); + + if (stringValue == NULL) + { + return (NULL); + } + else + { + return (dynFgetstr (stringValue)); + } +} + +void +http_request_setResponseHeader (const HttpRequest *request, const char *key, const char *value) +{ + dynTstring *value_string = dynFinit(); + + assert (request != NULL); + assert (key != NULL); + assert (value != NULL); + + dynFsappend (value_string, value); + + stringdictionary_setValue (request->responseHeaders, key, value_string); +} + +void +http_request_setResponseHeaderData (const HttpRequest *request, const char *key, const char *value, int valueLen) +{ + dynTstring *value_string = dynFinit(); + + assert (request != NULL); + assert (key != NULL); + assert (value != NULL); + + dynFappend (value_string, value, valueLen); + + stringdictionary_setValue (request->responseHeaders, key, value_string); +} + +static void +http_request_populateInitial (HttpRequest *request, Message *requestMessage) +{ + dynTstring *serializedResponseHeaders; + dynTstring *status = dynFinit(); + + assert (request != NULL); + assert (requestMessage != NULL); + + /* insert responseHeaders */ + serializedResponseHeaders = serialization_serializeType ( + "StringDictionary", &request->responseHeaders); + + message_setParameterString (requestMessage, "responseHeaders", + serializedResponseHeaders); + + dynFfree (serializedResponseHeaders); + + /* insert status */ + dynFappend_print (status, "%d", request->responseStatus); + + message_setParameterString (requestMessage, "status", status); + + dynFfree (status); +} + +bool +http_request_writeData (HttpRequest *request, const char *data, const int dataLen) +{ + Message *requestMessage = message_newRequest ("HttpWrite"); + bool ret; + + assert (request != NULL); + assert (data != NULL); + + message_setParameterString (requestMessage, "token", request->token); + message_setParameterBinary (requestMessage, "data", data, dataLen); + + if (request->sentResponseHeaders == false) + { + http_request_populateInitial (request, requestMessage); + + request->sentResponseHeaders = true; + } + + ret = http_response_sendSimpleMessage (request->processor, + requestMessage); + + message_destroy (requestMessage); + + return (ret); +} + +bool +http_request_writeString (HttpRequest *request, const char *data) +{ + assert (request != NULL); + assert (data != NULL); + + return (http_request_writeData (request, data, strlen (data))); +} + +bool +http_request_finishStatus (const HttpRequest *request, int status) +{ + bool ret; + + assert (request != NULL); + + ret = http_response_sendFinishMessage (request->processor, + dynFgetstr (request->token), status); + + return (ret); +} + +bool +http_request_finish (const HttpRequest *request) +{ + bool ret; + + assert (request != NULL); + + ret = http_response_sendFinishMessage (request->processor, + dynFgetstr (request->token), STATUS_EXIT); + + return (ret); +} + +static bool +http_request_loadEntity (HttpRequest *instance) +{ + assert (instance != NULL); + + if (instance->entityRequested == false) + { + if (http_response_sendReadEntityBody (instance->processor, + dynFgetstr (instance->token), instance->entity) == false) + { + /* logFmsg (CONT_LOG_ERROR, "causality-client: Could not send entity body request."); */ + + return (false); + } + + instance->entityRequested = true; + } + + return (true); +} + +const dynTstring * +http_request_getEntireEntity (HttpRequest *instance) +{ + assert (instance != NULL); + + if (http_request_loadEntity (instance) == false) + { + return (NULL); + } + + return (instance->entity); +} + +int +http_request_getEntity (HttpRequest *request, char *outBuf, const int bufLen) +{ + int size; + + assert (request != NULL); + assert (outBuf != NULL); + + if (http_request_loadEntity (request) == false) + { + return (-1); + } + + size = dynFgetlen (request->entity) - request->entityReadOffset; + + if (size > bufLen) + { + size = bufLen; + } + + if (size > 0) + { + memcpy (outBuf, dynFgetstr (request->entity) + request->entityReadOffset, size); + + request->entityReadOffset += size; + } + + return (size); +} + +bool +http_request_isEntireEntityLoaded (const HttpRequest *request) +{ + assert (request != NULL); + + if (request->entityRequested == true && + request->entityReadOffset == dynFgetlen (request->entity)) + { + return (true); + } + else + { + return (false); + } +} + +static const char * +http_request_getInternalString (dynTstring *string) +{ + if (string == NULL) + { + return (""); + } + else + { + return (dynFgetstr (string)); + } +} + +static bool +http_request_setIfNotNull (dynTstring *dest, const dynTstring *src) +{ + assert (dest != NULL); + + if (src == NULL) + { + return (false); + } + + dynFappend_string (dest, src); + + return (true); +} + diff --git a/mk4/lib/causality-client/src/http_request_handler.c b/mk4/lib/causality-client/src/http_request_handler.c new file mode 100644 index 0000000..b06a258 --- /dev/null +++ b/mk4/lib/causality-client/src/http_request_handler.c @@ -0,0 +1,67 @@ + +#include + +#include "processor.h" +#include "http_request_list.h" +#include "http_request_handler.h" + +#include "command.h" + +static const char *command_HttpRequestStart_RequiredParameters[] = { "token", "variables", "headers", "remoteIP", NULL }; +static const char *command_HttpRequestStart_OptionalParameters[] = { "method", "uri", "protocol", "query", NULL }; +CommandHandler command_HttpRequestStart = { "HttpRequestStart", http_request_handler_handleRequest, + command_HttpRequestStart_RequiredParameters, command_HttpRequestStart_OptionalParameters }; + +static const char *command_HttpRequestPing_RequiredParameters[] = { "token", NULL }; +static const char *command_HttpRequestPing_OptionalParamaters[] = { NULL }; +CommandHandler command_HttpRequestPing = { "HttpRequestPing", http_request_handler_handlePing, + command_HttpRequestPing_RequiredParameters, command_HttpRequestPing_OptionalParamaters }; + +static Message * +http_request_handler_createResponseMessage (Message *requestMessage) +{ + Message *responseMessage = message_makeResponse (requestMessage); + + message_setParameter (responseMessage, "message", "Request Queued."); + + return (responseMessage); +} + +Message * +http_request_handler_handleRequest (void *context, Message *requestMessage) +{ + Processor *proc = (Processor *) context; + HttpRequestList *handlerList = http_request_list_getRequestList(); + HttpRequest *request = http_request_new (requestMessage, proc); + + http_request_list_addRequest (handlerList, request); + + return (http_request_handler_createResponseMessage (requestMessage)); +} + +Message * +http_request_handler_handlePing (MECHA_UNUSED void *context, Message *requestMessage) +{ + HttpRequestList *handlerList = http_request_list_getRequestList(); + const char *token; + + token = message_getParameter (requestMessage, "token"); + + if (http_request_list_containsRequest (handlerList, token)) + { + Message *responseMessage = message_makeResponse (requestMessage); + + message_setParameter (responseMessage, "message", "Request found."); + + return (responseMessage); + } + else + { + Message *responseMessage = message_makeErrorResponse (requestMessage); + + message_setParameter (responseMessage, "message", "Request not found."); + + return (responseMessage); + } +} + diff --git a/mk4/lib/causality-client/src/http_request_list.c b/mk4/lib/causality-client/src/http_request_list.c new file mode 100644 index 0000000..82715af --- /dev/null +++ b/mk4/lib/causality-client/src/http_request_list.c @@ -0,0 +1,133 @@ + +#include +#include + +#include "http_request_queue.h" +#include "http_request_list.h" + +#include "http_request_list_entry.h" +#include "threadpool.h" + +struct s_HttpRequestList +{ + HttpRequestQueue *queue; + + HttpRequestHandlerDelegate handler; + void *handlerContext; + + hshTvoid_list *list; + pthread_rwlock_t listLock; +}; + +HttpRequestList *g_http_request_list = NULL; +static pthread_once_t g_http_request_list_once = PTHREAD_ONCE_INIT; + + +static void http_request_list_setupInstance (void); + +HttpRequestList * +http_request_list_new() +{ + HttpRequestList *request = malloc (sizeof (HttpRequestList)); + + request->list = hshFvoid_init (http_request_destroy); + request->queue = http_request_queue_new(); + request->handler = NULL; + + pthread_rwlock_init (&request->listLock, NULL); + + return (request); +} + +void +http_request_list_destroy (void *ptr) +{ + HttpRequestList *request = (HttpRequestList *) ptr; + + http_request_queue_destroy (request->queue); + + hshFvoid_destroy (request->list); + + free (request); +} + +void +http_request_list_setHandler (HttpRequestList *instance, + HttpRequestHandlerDelegate delegate, void *context) +{ + pthread_rwlock_wrlock (&instance->listLock); + + instance->handler = delegate; + instance->handlerContext = context; + + pthread_rwlock_unlock (&instance->listLock); +} + +bool +http_request_list_containsRequest (HttpRequestList *requestList, const char *token) +{ + bool ret; + + pthread_rwlock_rdlock (&requestList->listLock); + + ret = hshFvoid_contains (requestList->list, token); + + pthread_rwlock_unlock (&requestList->listLock); + + return (ret); +} + +static void +http_request_list_setupInstance() +{ + g_http_request_list = http_request_list_new(); +} + +HttpRequestList * +http_request_list_getRequestList() +{ + pthread_once (&g_http_request_list_once, http_request_list_setupInstance); + + return (g_http_request_list); +} + +void +http_request_list_addRequest (HttpRequestList *requestList, HttpRequest *request) +{ + pthread_rwlock_wrlock (&requestList->listLock); + + hshFvoid_add (requestList->list, http_request_getToken (request), request); + + if (requestList->handler != NULL) + { + HttpRequestListEntry *entry = + http_request_list_entry_new (requestList->handler, request, + requestList->handlerContext); + + /* entry will be cleaned up by itself after the call is completed */ + threadpool_queueUserWorkItem (threadpool_getInstance(), + http_request_list_entry_invokeEntry, entry); + } + else + { + http_request_queue_addRequest (requestList->queue, request); + } + + pthread_rwlock_unlock (&requestList->listLock); +} + +void +http_request_list_removeRequest (HttpRequestList *requestList, const char *token) +{ + pthread_rwlock_wrlock (&requestList->listLock); + + hshFvoid_del (requestList->list, token); + + pthread_rwlock_unlock (&requestList->listLock); +} + +HttpRequest * +http_request_list_getNextRequest (HttpRequestList *requestList) +{ + return (http_request_queue_getRequest (requestList->queue)); +} diff --git a/mk4/lib/causality-client/src/http_request_list_entry.c b/mk4/lib/causality-client/src/http_request_list_entry.c new file mode 100644 index 0000000..f670a41 --- /dev/null +++ b/mk4/lib/causality-client/src/http_request_list_entry.c @@ -0,0 +1,44 @@ + +#include + +#include "http_request_list_entry.h" + +struct s_HttpRequestListEntry +{ + HttpRequestHandlerDelegate delegate; + HttpRequest *request; + void *context; +}; + +HttpRequestListEntry * +http_request_list_entry_new (HttpRequestHandlerDelegate delegate, + HttpRequest *request, void *context) +{ + HttpRequestListEntry *instance = (HttpRequestListEntry *) malloc (sizeof (HttpRequestListEntry)); + + instance->delegate = delegate; + instance->request = request; + instance->context = context; + + return (instance); +} + +void +http_request_list_entry_destroy (void *ptr) +{ + HttpRequestListEntry *instance = (HttpRequestListEntry *) ptr; + + /* free other fields */ + + free (instance); +} + +void +http_request_list_entry_invokeEntry (void *ptr) +{ + HttpRequestListEntry *instance = (HttpRequestListEntry *) ptr; + + instance->delegate (instance->request, instance->context); + + http_request_list_entry_destroy (instance); +} diff --git a/mk4/lib/causality-client/src/http_request_queue.c b/mk4/lib/causality-client/src/http_request_queue.c new file mode 100644 index 0000000..1b74184 --- /dev/null +++ b/mk4/lib/causality-client/src/http_request_queue.c @@ -0,0 +1,75 @@ + + +#include +#include +#include +#include + +#include "http_request_queue.h" +#include "message.h" + +struct s_HttpRequestQueue +{ + lstTlist *queue; + pthread_mutex_t queueMutex; + sem_t queueSemaphore; +}; + +HttpRequestQueue * +http_request_queue_new() +{ + HttpRequestQueue *resp = malloc (sizeof (HttpRequestQueue)); + + sem_init (&resp->queueSemaphore, 0, 0); + pthread_mutex_init (&resp->queueMutex, NULL); + + resp->queue = lstFlist_create (NULL); + + return (resp); +} + +void +http_request_queue_destroy (void *ptr) +{ + HttpRequestQueue *resp = (HttpRequestQueue *) ptr; + + sem_destroy (&resp->queueSemaphore); + pthread_mutex_destroy (&resp->queueMutex); + + lstFlist_free (resp->queue); + + free (resp); +} + +HttpRequest * +http_request_queue_getRequest (HttpRequestQueue *resp) +{ + HttpRequest *request; + + /* this will block until it is 1 */ + sem_wait (&resp->queueSemaphore); + + pthread_mutex_lock (&resp->queueMutex); + + assert (lstFlist_size (resp->queue) > 0); + + lstFlist_remove (resp->queue, lstFlist_head (resp->queue), (void **) &request); + + pthread_mutex_unlock (&resp->queueMutex); + + return (request); +} + +void +http_request_queue_addRequest (HttpRequestQueue *resp, HttpRequest *request) +{ + pthread_mutex_lock (&resp->queueMutex); + + lstFlist_add_next (resp->queue, lstFlist_tail (resp->queue), request); + + pthread_mutex_unlock (&resp->queueMutex); + + /* this will increment the semaphore to 1 */ + sem_post (&resp->queueSemaphore); +} + diff --git a/mk4/lib/causality-client/src/http_response.c b/mk4/lib/causality-client/src/http_response.c new file mode 100644 index 0000000..ad1212c --- /dev/null +++ b/mk4/lib/causality-client/src/http_response.c @@ -0,0 +1,124 @@ + +#include + +#include "processor.h" +#include "message.h" + +#include "http_response.h" + +bool +http_response_sendSimpleMessage (Processor *processor, Message *requestMessage) +{ + Message *responseMessage; + bool ret; + + ret = processor_sendMessage (processor, requestMessage, &responseMessage); + + if (ret == false) + { + logFmsg (CONT_LOG_ERROR, "%d/Could not send message.", getpid()); + } + else + { + if (message_getType (responseMessage) == MessageTypeErrorResponse) + { + logFmsg (CONT_LOG_DEBUG, "causality-client: An error was returned."); + + message_print (responseMessage); + + ret = false; + } + else + { + ret = true; + } + + message_destroy (responseMessage); + } + + return (ret); +} + +bool +http_response_sendFinishMessage (Processor *processor, const char *token, + int returnStatus) +{ + Message *requestMessage; + Message *responseMessage; + bool ret; + + requestMessage= message_newRequest ("HttpFinish"); + + message_setParameter (requestMessage, "token", token); + + message_setParameterInt (requestMessage, "returnStatus", returnStatus); + + ret = processor_sendMessage (processor, requestMessage, &responseMessage); + + if (ret == false) + { + logFmsg (CONT_LOG_ERROR, "%d/Could not send message.", getpid()); + } + else + { + if (message_getType (responseMessage) == MessageTypeErrorResponse) + { + logFmsg (CONT_LOG_DEBUG, "causality-client: An error was returned."); + + message_print (responseMessage); + + ret = false; + } + else + { + ret = true; + } + + message_destroy (responseMessage); + } + + message_destroy (requestMessage); + + return (ret); +} + +bool +http_response_sendReadEntityBody (Processor *processor, const char *token, dynTstring *entity) +{ + Message *requestMessage; + Message *responseMessage; + bool ret; + + requestMessage= message_newRequest ("HttpReadEntityBody"); + + message_setParameter (requestMessage, "token", token); + + ret = processor_sendMessage (processor, requestMessage, &responseMessage); + + if (ret == false) + { + logFmsg (CONT_LOG_ERROR, "%d/Could not send message.", getpid()); + } + else + { + if (message_getType (responseMessage) == MessageTypeErrorResponse) + { + ret = false; + } + else + { + ret = true; + + dynFappend_string (entity, + message_getParameterString (responseMessage, "data")); + } + + message_destroy (responseMessage); + } + + message_destroy (requestMessage); + + return (ret); +} + + diff --git a/mk4/lib/causality/CVS/Entries b/mk4/lib/causality/CVS/Entries new file mode 100644 index 0000000..76ba71d --- /dev/null +++ b/mk4/lib/causality/CVS/Entries @@ -0,0 +1,3 @@ +/Makefile/1.1/Thu May 13 21:05:12 2004//Tmk4_mod6_rc2 +D/include//// +D/src//// diff --git a/mk4/lib/causality/CVS/Repository b/mk4/lib/causality/CVS/Repository new file mode 100644 index 0000000..58bf00e --- /dev/null +++ b/mk4/lib/causality/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/lib/causality diff --git a/mk4/lib/causality/CVS/Root b/mk4/lib/causality/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/lib/causality/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/lib/causality/CVS/Tag b/mk4/lib/causality/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/lib/causality/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/lib/causality/Makefile b/mk4/lib/causality/Makefile new file mode 100644 index 0000000..a82a067 --- /dev/null +++ b/mk4/lib/causality/Makefile @@ -0,0 +1,15 @@ +CONTINUITY = ../../continuity + +TARGET = causality +TARGETTYPE = shared static + +SOURCES = src/message.c src/processor.c src/sysvipc.c \ + src/responseholder.c src/responseholderlist.c \ + src/request_dispatcher.c src/request_handler_entry.c \ + src/command_handlers.c src/threadpool.c src/message_processor.c + +INCLUDES += -Iinclude -I../aura/include +STATIC_LIBS += ../aura/libaura.a +#LOCAL_CFLAGS += + +include $(CONTINUITY)/lib/build.mk diff --git a/mk4/lib/causality/include/CVS/Entries b/mk4/lib/causality/include/CVS/Entries new file mode 100644 index 0000000..8459046 --- /dev/null +++ b/mk4/lib/causality/include/CVS/Entries @@ -0,0 +1,12 @@ +/command.h/1.1/Thu May 13 21:05:12 2004//Tmk4_mod6_rc2 +/command_handlers.h/1.1/Thu May 13 21:05:12 2004//Tmk4_mod6_rc2 +/message.h/1.1/Thu May 13 21:05:12 2004//Tmk4_mod6_rc2 +/message_processor.h/1.1/Thu May 13 21:05:12 2004//Tmk4_mod6_rc2 +/processor.h/1.2/Fri May 14 06:20:33 2004//Tmk4_mod6_rc2 +/request_dispatcher.h/1.1/Thu May 13 21:05:12 2004//Tmk4_mod6_rc2 +/request_handler_entry.h/1.1/Thu May 13 21:05:12 2004//Tmk4_mod6_rc2 +/responseholder.h/1.1/Thu May 13 21:05:12 2004//Tmk4_mod6_rc2 +/responseholderlist.h/1.1/Thu May 13 21:05:12 2004//Tmk4_mod6_rc2 +/sysvipc.h/1.1/Thu May 13 21:05:12 2004//Tmk4_mod6_rc2 +/threadpool.h/1.1/Thu May 13 21:05:12 2004//Tmk4_mod6_rc2 +D diff --git a/mk4/lib/causality/include/CVS/Repository b/mk4/lib/causality/include/CVS/Repository new file mode 100644 index 0000000..9693b65 --- /dev/null +++ b/mk4/lib/causality/include/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/lib/causality/include diff --git a/mk4/lib/causality/include/CVS/Root b/mk4/lib/causality/include/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/lib/causality/include/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/lib/causality/include/CVS/Tag b/mk4/lib/causality/include/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/lib/causality/include/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/lib/causality/include/command.h b/mk4/lib/causality/include/command.h new file mode 100644 index 0000000..70a0dae --- /dev/null +++ b/mk4/lib/causality/include/command.h @@ -0,0 +1,18 @@ +#ifndef __COMMAND_H__ +#define __COMMAND_H__ + +#include "message.h" + +typedef Message * (*CommandHandlerDelegate) (void *context, Message *requestMessage); + +struct s_CommandHandler +{ + const char *commandName; + CommandHandlerDelegate handler; + const char **requiredParameters; + const char **optionalParameters; +}; + +typedef struct s_CommandHandler CommandHandler; + +#endif diff --git a/mk4/lib/causality/include/command_handlers.h b/mk4/lib/causality/include/command_handlers.h new file mode 100644 index 0000000..2593583 --- /dev/null +++ b/mk4/lib/causality/include/command_handlers.h @@ -0,0 +1,21 @@ +#ifndef __REQUESTHANDLERS_H_ +#define __REQUESTHANDLERS_H_ + +#include "message.h" +#include "processor.h" + +typedef struct s_CommandHandlers CommandHandlers; + +/* +typedef Message * (*RequestHandler) (Message *requestMessage); +*/ + +CommandHandlers * command_handlers_new (void); +void command_handlers_destroy (void *ptr); + +bool command_handlers_addHandler (CommandHandlers *reqs, const CommandHandler *handler, void *context); + + +void command_handlers_processMessage (CommandHandlers *reqs, Message *message, Processor *processor); + +#endif diff --git a/mk4/lib/causality/include/message.h b/mk4/lib/causality/include/message.h new file mode 100644 index 0000000..eab0bb6 --- /dev/null +++ b/mk4/lib/causality/include/message.h @@ -0,0 +1,43 @@ +#ifndef __MESSAGE_H_ +#define __MESSAGE_H_ + +#include + +enum e_MessageType +{ + MessageTypeRequest, + MessageTypeResponse, + MessageTypeErrorResponse +}; + +typedef enum e_MessageType MessageType; + +typedef struct s_Message Message; + +Message * message_new (const char *name, MessageType type); +void message_destroy (void *ptr); + +Message * message_newRequest (const char *command); + +void message_setParameter (Message *message, const char *key, const char *value); +const char * message_getParameter (Message *message, const char *key); + +void message_setParameterBinary (Message *message, const char *key, const char *value, int valueLen); +void message_setParameterString (Message *message, const char *key, const dynTstring *value); +void message_setParameterInt (Message *message, const char *key, const int value); + +const char * message_getCommand (Message *message); +MessageType message_getType (Message *message); + +void message_setSequence (Message *message, int sequence); +int message_getSequence (Message *message); + +Message * message_makeResponse (Message *request); +Message * message_makeErrorResponse (Message *request); + +void message_print (Message *message); + +dynTstring * message_getParameterString (Message *message, const char *key); + + +#endif diff --git a/mk4/lib/causality/include/message_processor.h b/mk4/lib/causality/include/message_processor.h new file mode 100644 index 0000000..4a47e0b --- /dev/null +++ b/mk4/lib/causality/include/message_processor.h @@ -0,0 +1,19 @@ +#ifndef __MESSAGE_PROCESSOR_H__ +#define __MESSAGE_PROCESSOR_H__ + +#include "mecha.h" +#include "responseholderlist.h" +#include "command_handlers.h" +#include "processor.h" + +typedef struct s_MessageProcessor MessageProcessor; + +MessageProcessor * +message_processor_new (dynTstring *message, ResponseHolderList *responses, + CommandHandlers *commandHandlers, Processor *processor); + +void message_processor_destroy (void *ptr); +void message_processor_process (void *context); + + +#endif diff --git a/mk4/lib/causality/include/processor.h b/mk4/lib/causality/include/processor.h new file mode 100644 index 0000000..5f3b73e --- /dev/null +++ b/mk4/lib/causality/include/processor.h @@ -0,0 +1,22 @@ +#ifndef __PROCESSOR_H_ +#define __PROCESSOR_H_ + +#include "message.h" +#include "request_handler_entry.h" + +typedef struct s_Processor Processor; + +Processor * processor_new (const key_t ipcKey, bool isClient); +void processor_destroy (void *ptr); + +bool processor_sendMessage (Processor *proc, Message *msg, Message **receiveMessage); +Message * processor_getMessage (Processor *proc); + +bool processor_sendMessageResponse (Processor *proc, Message *msg); + +void processor_addRequestHandler (Processor *processor, const CommandHandler *handler, void *context); + +void processor_finishedInit (Processor *processor); + + +#endif diff --git a/mk4/lib/causality/include/request_dispatcher.h b/mk4/lib/causality/include/request_dispatcher.h new file mode 100644 index 0000000..f80cc3a --- /dev/null +++ b/mk4/lib/causality/include/request_dispatcher.h @@ -0,0 +1,12 @@ +#ifndef __REQUEST_DISPATCHER_H__ +#define __REQUEST_DISPATCHER_H__ + +typedef struct s_RequestDispatcher RequestDispatcher; + +RequestDispatcher * request_dispatcher_new (Processor *processor, RequestHandlerEntry *handlerEntry, Message *requestMessage); + +void request_dispatcher_destroy (void *ptr); + +void request_dispatcher_process (void *requestDispatcherPtr); + +#endif diff --git a/mk4/lib/causality/include/request_handler_entry.h b/mk4/lib/causality/include/request_handler_entry.h new file mode 100644 index 0000000..44306c7 --- /dev/null +++ b/mk4/lib/causality/include/request_handler_entry.h @@ -0,0 +1,17 @@ +#ifndef __REQUEST_HANDLER_ENTRY_H__ +#define __REQUEST_HANDLER_ENTRY_H__ + +#include "message.h" +#include "command.h" + +typedef struct s_RequestHandlerEntry RequestHandlerEntry; + +typedef Message * (*RequestHandler) (void *context, Message *requestMessage); + +RequestHandlerEntry * request_handler_entry_new (const CommandHandler *handler, void *context); +void request_handler_entry_destroy (void *ptr); + +const CommandHandler *request_handler_entry_getHandler (RequestHandlerEntry *entry); +void * request_handler_entry_getContext (RequestHandlerEntry *entry); + +#endif diff --git a/mk4/lib/causality/include/responseholder.h b/mk4/lib/causality/include/responseholder.h new file mode 100644 index 0000000..565a7d1 --- /dev/null +++ b/mk4/lib/causality/include/responseholder.h @@ -0,0 +1,15 @@ +#ifndef __RESPONSEHOLDER_H_ +#define __RESPONSEHOLDER_H_ + +#include "message.h" + +typedef struct s_ResponseHolder ResponseHolder; + +ResponseHolder * responseholder_new (int seq); +void responseholder_destroy (void *ptr); +Message * responseholder_getResponse (ResponseHolder *resp); + +void responseholder_setResponse (ResponseHolder *resp, Message *message); + + +#endif diff --git a/mk4/lib/causality/include/responseholderlist.h b/mk4/lib/causality/include/responseholderlist.h new file mode 100644 index 0000000..94dbcfd --- /dev/null +++ b/mk4/lib/causality/include/responseholderlist.h @@ -0,0 +1,16 @@ +#ifndef __RESPONSEHOLDERLIST_H_ +#define __RESPONSEHOLDERLIST_H_ + +#include "message.h" + +typedef struct s_ResponseHolderList ResponseHolderList; + +ResponseHolderList * responseholderlist_new (void); +void responseholderlist_destroy (void *ptr); + +Message * responseholderlist_getResponse (ResponseHolderList *response_list, int seq); +void responseholderlist_setResponse (ResponseHolderList *response_list, Message *response); +void responseholderlist_addResponseHolder (ResponseHolderList *response_list, int sequence); + + +#endif diff --git a/mk4/lib/causality/include/sysvipc.h b/mk4/lib/causality/include/sysvipc.h new file mode 100644 index 0000000..e71c2d3 --- /dev/null +++ b/mk4/lib/causality/include/sysvipc.h @@ -0,0 +1,23 @@ +#ifndef __SYSVIPC_H_ +#define __SYSVIPC_H + +#include "mecha.h" + +enum e_IPCDisposition +{ + IPCClient, + IPCServer +}; + +typedef enum e_IPCDisposition IPCDisposition; + +typedef struct s_SysVIPC SysVIPC; + +SysVIPC * sysvipc_new (const key_t ipcKey, IPCDisposition disposition); +void sysvipc_destroy (void *ptr); + +bool sysvipc_sendData (SysVIPC *ipc, dynTstring *data); +dynTstring * sysvipc_getData (SysVIPC *ipc); + + +#endif diff --git a/mk4/lib/causality/include/threadpool.h b/mk4/lib/causality/include/threadpool.h new file mode 100644 index 0000000..45882ec --- /dev/null +++ b/mk4/lib/causality/include/threadpool.h @@ -0,0 +1,15 @@ +#ifndef __THREADPOOL_H__ +#define __THREADPOOL_H__ + +#include "type.h" + +typedef struct s_ThreadPool ThreadPool; + +typedef void (*WorkItemDelegate) (void *context); + +ThreadPool * threadpool_new (void); +void threadpool_destroy (void *ptr); +ThreadPool * threadpool_getInstance (void); +bool threadpool_queueUserWorkItem (ThreadPool *pool, WorkItemDelegate delegate, void *context); + +#endif diff --git a/mk4/lib/causality/src/CVS/Entries b/mk4/lib/causality/src/CVS/Entries new file mode 100644 index 0000000..6b3e1b0 --- /dev/null +++ b/mk4/lib/causality/src/CVS/Entries @@ -0,0 +1,12 @@ +/command.c/1.1/Thu May 13 21:05:12 2004//Tmk4_mod6_rc2 +/command_handlers.c/1.1/Thu May 13 21:05:12 2004//Tmk4_mod6_rc2 +/message.c/1.1/Thu May 13 21:05:12 2004//Tmk4_mod6_rc2 +/message_processor.c/1.2/Fri May 14 19:12:09 2004//Tmk4_mod6_rc2 +/processor.c/1.1/Thu May 13 21:05:12 2004//Tmk4_mod6_rc2 +/request_dispatcher.c/1.1/Thu May 13 21:05:12 2004//Tmk4_mod6_rc2 +/request_handler_entry.c/1.1/Thu May 13 21:05:12 2004//Tmk4_mod6_rc2 +/responseholder.c/1.1/Thu May 13 21:05:12 2004//Tmk4_mod6_rc2 +/responseholderlist.c/1.1/Thu May 13 21:05:12 2004//Tmk4_mod6_rc2 +/sysvipc.c/1.4/Thu Jun 24 15:45:47 2004//Tmk4_mod6_rc2 +/threadpool.c/1.2/Thu Jun 24 15:45:48 2004//Tmk4_mod6_rc2 +D diff --git a/mk4/lib/causality/src/CVS/Repository b/mk4/lib/causality/src/CVS/Repository new file mode 100644 index 0000000..6490ffa --- /dev/null +++ b/mk4/lib/causality/src/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/lib/causality/src diff --git a/mk4/lib/causality/src/CVS/Root b/mk4/lib/causality/src/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/lib/causality/src/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/lib/causality/src/CVS/Tag b/mk4/lib/causality/src/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/lib/causality/src/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/lib/causality/src/command.c b/mk4/lib/causality/src/command.c new file mode 100644 index 0000000..f119d9a --- /dev/null +++ b/mk4/lib/causality/src/command.c @@ -0,0 +1,21 @@ + +#include + + +#include "command.h" + +static Message * test_command_handler (void *context, Message *requestMessage); + +static const char *requiredParameters[] = { "one", "two", NULL }; +static const char *optionalParameters[] = { NULL }; +CommandHandler test_command = { "test", test_command_handler, requiredParameters, optionalParameters }; + +Message * +test_command_handler (void *context, Message *requestMessage) +{ + + + return (NULL); +} + + diff --git a/mk4/lib/causality/src/command_handlers.c b/mk4/lib/causality/src/command_handlers.c new file mode 100644 index 0000000..995b7ef --- /dev/null +++ b/mk4/lib/causality/src/command_handlers.c @@ -0,0 +1,68 @@ + +#include + +#include "mecha.h" + +#include "command_handlers.h" +#include "processor.h" +#include "request_dispatcher.h" + +#include "request_handler_entry.h" + +#include "threadpool.h" + +struct s_CommandHandlers +{ + hshTvoid_list *handlers; +}; + +CommandHandlers * +command_handlers_new() +{ + CommandHandlers *reqs = malloc (sizeof (CommandHandlers)); + + reqs->handlers = hshFvoid_init (request_handler_entry_destroy); + + return (reqs); +} + +void +command_handlers_destroy (void *ptr) +{ + CommandHandlers *reqs = (CommandHandlers *) ptr; + + hshFvoid_destroy (reqs->handlers); + + free (reqs); +} + +bool +command_handlers_addHandler (CommandHandlers *reqs, const CommandHandler *handler, void *context) +{ + RequestHandlerEntry *entry = request_handler_entry_new (handler, context); + + if (hshFvoid_add (reqs->handlers, handler->commandName, entry)) + { + return (true); + } + else + { + return (false); + } +} + +void +command_handlers_processMessage (CommandHandlers *reqs, Message *message, Processor *processor) +{ + RequestDispatcher *dispatcher; + RequestHandlerEntry *handlerEntry; + + handlerEntry = (RequestHandlerEntry *) hshFvoid_find (reqs->handlers, + message_getCommand (message)); + + dispatcher = request_dispatcher_new (processor, handlerEntry, message); + + threadpool_queueUserWorkItem ( + threadpool_getInstance(), request_dispatcher_process, dispatcher); +} + diff --git a/mk4/lib/causality/src/message.c b/mk4/lib/causality/src/message.c new file mode 100644 index 0000000..437ec3c --- /dev/null +++ b/mk4/lib/causality/src/message.c @@ -0,0 +1,226 @@ + +#include +#include + +#include + +#include "serialization.h" +#include "stringdictionary.h" +#include "message.h" + +struct s_Message +{ + char *command; + int sequence; + MessageType type; + StringDictionary *params; +}; + +static bool message_serialize (void *field, SerializationInfo *info); +static bool message_deserialize (void *field, SerializationInfo *info); + +Type type_declaration_Message = { "Message", message_serialize, message_deserialize }; + + +Message * +message_new (const char *command, MessageType type) +{ + Message *message = malloc (sizeof (Message)); + + message->command = strdup (command); + message->type = type; + message->params = stringdictionary_new(); + + return (message); +} + +void +message_destroy (void *ptr) +{ + Message *message = (Message *) ptr; + + free (message->command); + + stringdictionary_destroy (message->params); + + free (message); +} + +Message * +message_newRequest (const char *command) +{ + return (message_new (command, MessageTypeRequest)); +} + +MessageType +message_getType (Message *message) +{ + return (message->type); +} + +Message * +message_makeResponse (Message *request) +{ + Message *response = message_new (message_getCommand (request), MessageTypeResponse); + + response->sequence = request->sequence; + + return (response); +} + +Message * +message_makeErrorResponse (Message *request) +{ + Message *response = message_new (message_getCommand (request), MessageTypeErrorResponse); + + response->sequence = request->sequence; + + return (response); +} + +int +message_getSequence (Message *message) +{ + return (message->sequence); +} + +void +message_setSequence (Message *message, int sequence) +{ + message->sequence = sequence; +} + +void +message_setParameter (Message *message, const char *key, const char *value) +{ + dynTstring *stringValue = dynFinit(); + + dynFsappend (stringValue, value); + + stringdictionary_setValue (message->params, key, stringValue); +} + +void +message_setParameterInt (Message *message, const char *key, const int value) +{ + dynTstring *stringValue = dynFinit(); + + dynFappend_print (stringValue, "%d", value); + + stringdictionary_setValue (message->params, key, stringValue); +} + +void +message_setParameterString (Message *message, const char *key, const dynTstring *value) +{ + dynTstring *stringValue = dynFinit(); + + dynFappend_string (stringValue, value); + + stringdictionary_setValue (message->params, key, stringValue); +} + +void +message_setParameterBinary (Message *message, const char *key, const char *value, int valueLen) +{ + dynTstring *stringValue = dynFinit(); + + dynFappend (stringValue, value, valueLen); + + stringdictionary_setValue (message->params, key, stringValue); +} + +dynTstring * +message_getParameterString (Message *message, const char *key) +{ + return (stringdictionary_getValue (message->params, key)); +} + +const char * +message_getParameter (Message *message, const char *key) +{ + dynTstring *stringValue = stringdictionary_getValue (message->params, key); + + if (stringValue != NULL) + { + return (dynFgetstr (stringValue)); + } + else + { + return (NULL); + } +} + +const char * +message_getCommand (Message *message) +{ + return (message->command); +} + +void +message_print (Message *message) +{ + hshTiterator *iter; + + printf (" command: %s\n", message->command); + printf (" sequence: %d\n", message->sequence); + printf (" type: %d\n", message->type); + printf (" params:\n"); + + iter = stringdictionary_getIterator (message->params); + + while (hshFiterator_next (iter) == 1) + { + char *key = (char *) hshFiterator_current_key (iter); + dynTstring *value = (dynTstring *) hshFiterator_current_value (iter); + + printf (" %s: %s\n", key, dynFgetstr (value)); + } + + hshFiterator_free (iter); +} + +static bool +message_serialize (void *field, SerializationInfo *info) +{ + Message *message = DEREFERENCE_TYPE (Message, field); + + serializationinfo_addValue (info, "command", + serialization_serializeType ("String", &message->command)); + + serializationinfo_addValue (info, "sequence", + serialization_serializeType ("Int", &message->sequence)); + + serializationinfo_addValue (info, "type", + serialization_serializeType ("Int", &message->type)); + + serializationinfo_addValue (info, "params", + serialization_serializeType ("StringDictionary", &message->params)); + + return (true); +} + +static bool +message_deserialize (void *field, SerializationInfo *info) +{ + Message *message = malloc (sizeof (Message)); + Message **fieldPtr = (Message **) field; + + *fieldPtr = message; + /* DEREFERENCE_TYPE (Message, field) = message; */ + + serialization_deserializeType ("String", &message->command, + serializationinfo_getValue (info, "command")); + + serialization_deserializeType ("Int", &message->sequence, + serializationinfo_getValue (info, "sequence")); + + serialization_deserializeType ("Int", &message->type, + serializationinfo_getValue (info, "type")); + + serialization_deserializeType ("StringDictionary", &message->params, + serializationinfo_getValue (info, "params")); + + return (true); +} + diff --git a/mk4/lib/causality/src/message_processor.c b/mk4/lib/causality/src/message_processor.c new file mode 100644 index 0000000..73eef40 --- /dev/null +++ b/mk4/lib/causality/src/message_processor.c @@ -0,0 +1,71 @@ + +#include "mecha.h" +#include "responseholderlist.h" +#include "command_handlers.h" +#include "processor.h" + +#include "serialization.h" + +#include "message_processor.h" + +struct s_MessageProcessor +{ + dynTstring *message; + ResponseHolderList *responses; + CommandHandlers *commandHandlers; + Processor *processor; +}; + +MessageProcessor * +message_processor_new (dynTstring *message, ResponseHolderList *responses, + CommandHandlers *commandHandlers, Processor *processor) +{ + MessageProcessor *mp = malloc (sizeof (MessageProcessor)); + + mp->message = message; + mp->responses = responses; + mp->commandHandlers = commandHandlers; + mp->processor = processor; + + return (mp); +} + +void +message_processor_destroy (void *ptr) +{ + MessageProcessor *mp = (MessageProcessor *) ptr; + + dynFfree (mp->message); + + free (mp); +} + +void +message_processor_process (void *context) +{ + MessageProcessor *mp = (MessageProcessor *) context; + Message *message; + bool ret; + + ret = serialization_deserializeType ("Message", &message, mp->message); + + if (ret == false) + { + logFmsg (CONT_LOG_ERROR, "Failed to deserialize message: %s", dynFgetstr (mp->message)); + } + else + { + if (message_getType (message) == MessageTypeRequest) + { + /* message will be destroyed when it is done being used */ + command_handlers_processMessage (mp->commandHandlers, message, mp->processor); + } + else + { + responseholderlist_setResponse (mp->responses, message); + } + } + + message_processor_destroy (mp); +} + diff --git a/mk4/lib/causality/src/processor.c b/mk4/lib/causality/src/processor.c new file mode 100644 index 0000000..a42778e --- /dev/null +++ b/mk4/lib/causality/src/processor.c @@ -0,0 +1,243 @@ + +#include + +#include +#include +#include + + +#include +#include +#include + +#include "threadpool.h" +#include "message_processor.h" + +#include "message.h" +#include "processor.h" +#include "serialization.h" +#include "sysvipc.h" +#include "responseholder.h" +#include "responseholderlist.h" +#include "command_handlers.h" + +struct s_Processor +{ + SysVIPC *ipc; + + int last_sequence; + + ResponseHolderList *responses; + CommandHandlers *commandHandlers; + + pthread_t incoming_handler_thread; + + bool init_sync; + pthread_cond_t init_sync_cond; + pthread_mutex_t init_sync_mutex; +}; + +static void *processor_incomingHandler (void *arg); + +Processor * +processor_new (const key_t ipcKey, bool isClient) +{ + Processor *proc; + + proc = malloc (sizeof (Processor)); + + if (isClient == true) + { + proc->ipc = sysvipc_new (ipcKey, IPCClient); + } + else + { + proc->ipc = sysvipc_new (ipcKey, IPCServer); + } + + if (proc->ipc == NULL) + { + free (proc); + + return (NULL); + } + + proc->last_sequence = 0; + proc->responses = responseholderlist_new(); + proc->commandHandlers = command_handlers_new(); + + proc->init_sync = false; + + pthread_cond_init (&proc->init_sync_cond, NULL); + pthread_mutex_init (&proc->init_sync_mutex, NULL); + + pthread_create (&proc->incoming_handler_thread, NULL, processor_incomingHandler, proc); + + return (proc); +} + +void +processor_destroy (void *ptr) +{ + Processor *proc = (Processor *) ptr; + + pthread_cancel (proc->incoming_handler_thread); + pthread_join (proc->incoming_handler_thread, NULL); + + sysvipc_destroy (proc->ipc); + + pthread_cond_destroy (&proc->init_sync_cond); + pthread_mutex_destroy (&proc->init_sync_mutex); + + command_handlers_destroy (proc->commandHandlers); + + responseholderlist_destroy (proc->responses); + + free (proc); +} + +static int +processor_getNextSequence (Processor *proc) +{ + int next_seq = ++proc->last_sequence; + + return (next_seq); +} + +void +processor_finishedInit (Processor *processor) +{ + pthread_mutex_lock (&processor->init_sync_mutex); + + processor->init_sync = true; + + pthread_cond_broadcast (&processor->init_sync_cond); + pthread_mutex_unlock (&processor->init_sync_mutex); +} + +bool +processor_sendMessageResponse (Processor *proc, Message *msg) +{ + dynTstring *msgString; + bool ret; + + if (message_getType (msg) != MessageTypeResponse && + message_getType (msg) != MessageTypeErrorResponse) + { + return (false); + } + + msgString = serialization_serializeType ("Message", &msg); + + ret = sysvipc_sendData (proc->ipc, msgString); + + dynFfree (msgString); + + return (ret); +} + + +bool +processor_sendMessage (Processor *proc, Message *msg, Message **receiveMessage) +{ + dynTstring *msgString; + bool ret; + int seq; + + if (message_getType (msg) != MessageTypeRequest) + { + return (false); + } + + seq = processor_getNextSequence (proc); + + responseholderlist_addResponseHolder (proc->responses, seq); + + message_setSequence (msg, seq); + + msgString = serialization_serializeType ("Message", &msg); + + ret = sysvipc_sendData (proc->ipc, msgString); + + dynFfree (msgString); + + if (ret == false) + { + /* we're leaking ResponseHolders here */ + + abort(); + + return (false); + } + else + { + *receiveMessage = responseholderlist_getResponse (proc->responses, seq); + + if (*receiveMessage == NULL) + { + return (false); + } + else + { + return (true); + } + } +} + +void +processor_addRequestHandler (Processor *processor, const CommandHandler *handler, void *context) +{ + command_handlers_addHandler (processor->commandHandlers, handler, context); +} + +static void * +processor_incomingHandler (void *arg) +{ + Processor *proc = (Processor *) arg; + + { + /* + * we'll wait for 5 seconds until someone calls the signal + */ + struct timespec waitTime = { 0, 0 }; + + waitTime.tv_sec = time (0) + 5; + + pthread_mutex_lock (&proc->init_sync_mutex); + + if (proc->init_sync == false) + { + pthread_cond_timedwait (&proc->init_sync_cond, + &proc->init_sync_mutex, &waitTime); + } + + pthread_mutex_unlock (&proc->init_sync_mutex); + } + + while (true) + { + dynTstring *msgString; + MessageProcessor *msgProc; + + msgString = sysvipc_getData (proc->ipc); + + if (msgString == NULL) + { + logFmsg (CONT_LOG_ERROR, "IPC communication failed. Exiting handler."); + + return (NULL); + } + + /* + * there is obviously refactoring that needs to happen when we need to + * pass this much data in. + */ + msgProc = message_processor_new (msgString, proc->responses, + proc->commandHandlers, proc); + + threadpool_queueUserWorkItem ( + threadpool_getInstance(), message_processor_process, msgProc); + } + + return (NULL); +} diff --git a/mk4/lib/causality/src/request_dispatcher.c b/mk4/lib/causality/src/request_dispatcher.c new file mode 100644 index 0000000..1232121 --- /dev/null +++ b/mk4/lib/causality/src/request_dispatcher.c @@ -0,0 +1,114 @@ + +#include +#include +#include + +#include "processor.h" +#include "command_handlers.h" +#include "request_dispatcher.h" +#include "request_handler_entry.h" + +struct s_RequestDispatcher +{ + Processor *processor; + RequestHandlerEntry *handlerEntry; + Message *requestMessage; +}; + + +RequestDispatcher * +request_dispatcher_new (Processor *processor, RequestHandlerEntry *handlerEntry, Message *requestMessage) +{ + RequestDispatcher *disp = malloc (sizeof (RequestDispatcher)); + + disp->processor = processor; + disp->handlerEntry = handlerEntry; + disp->requestMessage = requestMessage; + + return (disp); +} + +void +request_dispatcher_destroy (void *ptr) +{ + RequestDispatcher *disp = (RequestDispatcher *) ptr; + + message_destroy (disp->requestMessage); + + free (disp); +} + +static Message * +request_dispatcher_validateMessage (const CommandHandler *handler, + Message *requestMessage) +{ + Message *responseMessage = NULL; + dynTstring *errorMessage = dynFinit(); + int i; + + for (i = 0; handler->requiredParameters[i] != NULL; i++) + { + const char *value = message_getParameter (requestMessage, + handler->requiredParameters[i]); + + if (value == NULL) + { + dynFappend_print (errorMessage, "\nCould not find required parameter '%s'.", + handler->requiredParameters[i]); + } + } + + if (dynFgetlen (errorMessage) > 0) + { + responseMessage = message_makeErrorResponse (requestMessage); + + message_setParameterString (responseMessage, "message", errorMessage); + } + + dynFfree (errorMessage); + + return (responseMessage); +} + +void +request_dispatcher_process (void *requestDispatcherPtr) +{ + RequestDispatcher *dispatcher = (RequestDispatcher *) requestDispatcherPtr; + Message *responseMessage = NULL; + + if (dispatcher->handlerEntry == NULL) + { + responseMessage = message_makeErrorResponse (dispatcher->requestMessage); + + message_setParameter (responseMessage, "message", "Could not find command."); + } + else + { + const CommandHandler *handler = request_handler_entry_getHandler (dispatcher->handlerEntry); + void *context = request_handler_entry_getContext (dispatcher->handlerEntry); + + responseMessage = request_dispatcher_validateMessage (handler, + dispatcher->requestMessage); + + if (responseMessage == NULL) + { + responseMessage = handler->handler (context, dispatcher->requestMessage); + + if (responseMessage == NULL) + { + responseMessage = message_makeErrorResponse (dispatcher->requestMessage); + + message_setParameter (responseMessage, "message", "Could not execute handler."); + } + } + } + + if (processor_sendMessageResponse (dispatcher->processor, responseMessage) == false) + { + logFmsg (CONT_LOG_ERROR, "causality: could not send message."); + } + + message_destroy (responseMessage); + + request_dispatcher_destroy (dispatcher); +} diff --git a/mk4/lib/causality/src/request_handler_entry.c b/mk4/lib/causality/src/request_handler_entry.c new file mode 100644 index 0000000..2f707da --- /dev/null +++ b/mk4/lib/causality/src/request_handler_entry.c @@ -0,0 +1,43 @@ + +#include + +#include "request_handler_entry.h" +#include "command.h" + + +struct s_RequestHandlerEntry +{ + const CommandHandler *handler; + void *context; +}; + +RequestHandlerEntry * +request_handler_entry_new (const CommandHandler *handler, void *context) +{ + RequestHandlerEntry *entry = malloc (sizeof (RequestHandlerEntry)); + + entry->handler = handler; + entry->context = context; + + return (entry); +} + +void +request_handler_entry_destroy (void *ptr) +{ + RequestHandlerEntry *entry = (RequestHandlerEntry *) ptr; + + free (entry); +} + +const CommandHandler * +request_handler_entry_getHandler (RequestHandlerEntry *entry) +{ + return (entry->handler); +} + +void * +request_handler_entry_getContext (RequestHandlerEntry *entry) +{ + return (entry->context); +} diff --git a/mk4/lib/causality/src/responseholder.c b/mk4/lib/causality/src/responseholder.c new file mode 100644 index 0000000..3ab4adb --- /dev/null +++ b/mk4/lib/causality/src/responseholder.c @@ -0,0 +1,84 @@ + +#include +#include + +#include "responseholder.h" + +#define MESSAGE_WAIT_SECONDS (5 * 60) + +struct s_ResponseHolder +{ + int sequence; + + pthread_cond_t cond; + pthread_mutex_t mutex; + + Message *response; +}; + +ResponseHolder * +responseholder_new (int seq) +{ + ResponseHolder *resp = malloc (sizeof (ResponseHolder)); + + resp->sequence = seq; + + pthread_cond_init (&resp->cond, NULL); + pthread_mutex_init (&resp->mutex, NULL); + + resp->response = NULL; + + return (resp); +} + +void +responseholder_destroy (void *ptr) +{ + ResponseHolder *resp = (ResponseHolder *) ptr; + + pthread_cond_destroy (&resp->cond); + pthread_mutex_destroy (&resp->mutex); + + free (resp); +} + +Message * +responseholder_getResponse (ResponseHolder *resp) +{ + Message *messageResponse = NULL; + + pthread_mutex_lock (&resp->mutex); + + if (resp->response == NULL) + { + struct timespec timeout; + + timeout.tv_sec = time(0) + MESSAGE_WAIT_SECONDS; + timeout.tv_nsec = 0; + + /* + * if this returns, we've either got our signal, or we timed out, + * either way, we're done waiting. + */ + pthread_cond_timedwait (&resp->cond, &resp->mutex, &timeout); + } + + messageResponse = resp->response; + + pthread_mutex_unlock (&resp->mutex); + + return (messageResponse); +} + +void +responseholder_setResponse (ResponseHolder *resp, Message *message) +{ + pthread_mutex_lock (&resp->mutex); + + resp->response = message; + + pthread_mutex_unlock (&resp->mutex); + + pthread_cond_signal (&resp->cond); +} + diff --git a/mk4/lib/causality/src/responseholderlist.c b/mk4/lib/causality/src/responseholderlist.c new file mode 100644 index 0000000..b9eff48 --- /dev/null +++ b/mk4/lib/causality/src/responseholderlist.c @@ -0,0 +1,106 @@ + +#include +#include + +#include "responseholder.h" +#include "responseholderlist.h" + +struct s_ResponseHolderList +{ + hshTvoid_list *list; + + pthread_rwlock_t list_lock; + +}; + +ResponseHolderList * +responseholderlist_new() +{ + ResponseHolderList *response_list = malloc (sizeof (ResponseHolderList)); + + response_list->list = hshFvoid_int_init (responseholder_destroy); + + pthread_rwlock_init (&response_list->list_lock, NULL); + + return (response_list); +} + +void +responseholderlist_destroy (void *ptr) +{ + ResponseHolderList *response_list = (ResponseHolderList *) ptr; + + pthread_rwlock_destroy (&response_list->list_lock); + + hshFvoid_destroy (response_list->list); + + free (response_list); +} + + +void +responseholderlist_addResponseHolder (ResponseHolderList *response_list, int sequence) +{ + ResponseHolder *resp = responseholder_new (sequence); + + pthread_rwlock_wrlock (&response_list->list_lock); + + hshFvoid_int_add (response_list->list, sequence, resp); + + pthread_rwlock_unlock (&response_list->list_lock); +} + + +static ResponseHolder * +responseholderlist_getResponseHolder (ResponseHolderList *response_list, int sequence) +{ + ResponseHolder *resp; + + pthread_rwlock_rdlock (&response_list->list_lock); + + resp = (ResponseHolder *) hshFvoid_int_find (response_list->list, sequence); + + pthread_rwlock_unlock (&response_list->list_lock); + + return (resp); +} + +static void +responseholderlist_removeResponseHolder (ResponseHolderList *response_list, int sequence) +{ + pthread_rwlock_wrlock (&response_list->list_lock); + + hshFvoid_int_del (response_list->list, sequence); + + pthread_rwlock_unlock (&response_list->list_lock); +} + +Message * +responseholderlist_getResponse (ResponseHolderList *response_list, int seq) +{ + Message *responseMessage; + ResponseHolder *resp = responseholderlist_getResponseHolder (response_list, seq); + + responseMessage = responseholder_getResponse (resp); + + responseholderlist_removeResponseHolder (response_list, seq); + + return (responseMessage); +} + +void +responseholderlist_setResponse (ResponseHolderList *response_list, Message *response) +{ + ResponseHolder *resp = responseholderlist_getResponseHolder (response_list, + message_getSequence (response)); + + if (resp != NULL) + { + responseholder_setResponse (resp, response); + } + else + { + /* we don't know what this is responding to */ + } +} + diff --git a/mk4/lib/causality/src/sysvipc.c b/mk4/lib/causality/src/sysvipc.c new file mode 100644 index 0000000..fc6654b --- /dev/null +++ b/mk4/lib/causality/src/sysvipc.c @@ -0,0 +1,321 @@ +#define _GNU_SOURCE 1 + +#include +#include +#include +#include + +#include +#include +#include + +#include "mecha.h" + +#include "sysvipc.h" + + +#define IPC_CLIENT_SEND_ID 1 +#define IPC_SERVER_SEND_ID 2 + +struct s_SysVIPC +{ + int queue_id; + IPCDisposition disposition; + + int last_seq; + pthread_mutex_t last_seq_mutex; + + hshTvoid_list *message_queue; + pthread_rwlock_t message_queue_lock; +}; + +typedef struct s_IPCMessage IPCMessage; + +struct s_IPCMessage +{ + int seq; + bool last; + int data_len; + char data[1]; +}; + + +#ifndef MSGMAX +#define MSGMAX 8192 +#endif + +static const unsigned int MAX_PAYLOAD = MSGMAX - sizeof (IPCMessage); + +void sysvipc_cleanup (int sig, void *ptr); + +SysVIPC * +sysvipc_new (const key_t ipcKey, IPCDisposition disposition) +{ + SysVIPC *ipc; + int queue_id; + + if ((queue_id = msgget (ipcKey, IPC_CREAT | 0600)) == -1) + { + perror ("msgget"); + + return (NULL); + } + + ipc = malloc (sizeof (SysVIPC)); + ipc->last_seq = 1; + ipc->queue_id = queue_id; + ipc->message_queue = hshFvoid_init ((void (*) (void *)) dynFfree); + ipc->disposition = disposition; + + pthread_mutex_init (&ipc->last_seq_mutex, NULL); + pthread_rwlock_init (&ipc->message_queue_lock, NULL); + +#ifdef HAVE_ON_EXIT + on_exit (sysvipc_cleanup, ipc); +#endif + + return (ipc); +} + +void +sysvipc_destroy (void *ptr) +{ + SysVIPC *ipc = (SysVIPC *) ptr; + + if (ipc->disposition == IPCServer) + { + msgctl (ipc->queue_id, IPC_RMID, NULL); + } + + pthread_rwlock_wrlock (&ipc->message_queue_lock); + + hshFvoid_destroy (ipc->message_queue); + + pthread_rwlock_unlock (&ipc->message_queue_lock); + + pthread_mutex_destroy (&ipc->last_seq_mutex); + pthread_rwlock_destroy (&ipc->message_queue_lock); + + free (ipc); +} + +void +sysvipc_cleanup (int sig MECHA_UNUSED, void *ptr) +{ + logFmsg (CONT_LOG_DEBUG, "sysvipc: Cleaning up resources."); + + sysvipc_destroy (ptr); +} + +static struct msgbuf * +sysvipc_createMessage (const char *data, size_t size, bool isLast, size_t *bufSize, int sequence) +{ + struct msgbuf *tmpBuf; + IPCMessage *message; + size_t allocSize; + + *bufSize = sizeof (IPCMessage) + size; + allocSize = sizeof (struct msgbuf) + *bufSize; + + tmpBuf = malloc (allocSize); + + memset (tmpBuf, 0, allocSize); + + message = (IPCMessage *) tmpBuf->mtext; + + message->seq = sequence; + message->last = isLast; + message->data_len = size; + memcpy (message->data, data, size); + + return (tmpBuf); +} + +static int +sysvipc_getNextSequence (SysVIPC *ipc) +{ + int seq; + + pthread_mutex_lock (&ipc->last_seq_mutex); + + seq = ++ipc->last_seq; + + pthread_mutex_unlock (&ipc->last_seq_mutex); + + return (seq); +} + +bool +sysvipc_sendData (SysVIPC *ipc, dynTstring *data) +{ + long msgtyp; + int dataOffset = 0; + int sequence = sysvipc_getNextSequence (ipc); + + if (ipc->disposition == IPCClient) + { + msgtyp = IPC_CLIENT_SEND_ID; + } + else + { + msgtyp = IPC_SERVER_SEND_ID; + } + + while ((dynFgetlen (data) - dataOffset) > 0) + { + struct msgbuf *tmpBuf; + bool isLast = true; + size_t dataSize = dynFgetlen (data) - dataOffset; + size_t bufSize; + int msgsndRet; + + if (dataSize > MAX_PAYLOAD) + { + dataSize = MAX_PAYLOAD; + isLast = false; + } + + tmpBuf = sysvipc_createMessage (dynFgetstr (data) + dataOffset, dataSize, isLast, &bufSize, sequence); + + tmpBuf->mtype = msgtyp; + + do + { + msgsndRet = msgsnd (ipc->queue_id, tmpBuf, bufSize, 0); + } + while (msgsndRet == -1 && errno == EINTR); + + if (msgsndRet == -1) + { + perror ("msgsnd"); + free (tmpBuf); + + abort(); + + return (false); + } + + free (tmpBuf); + + dataOffset += dataSize; + } + + return (true); +} + +static dynTstring * +sysvipc_getPendingMessage (SysVIPC *ipc, int sequence) +{ + dynTstring *partString; + + pthread_rwlock_rdlock (&ipc->message_queue_lock); + + partString = (dynTstring *) hshFvoid_int_find (ipc->message_queue, sequence); + + pthread_rwlock_unlock (&ipc->message_queue_lock); + + return (partString); +} + +static void +sysvipc_addPendingMessage (SysVIPC *ipc, int sequence, dynTstring *data) +{ + pthread_rwlock_wrlock (&ipc->message_queue_lock); + + hshFvoid_int_add (ipc->message_queue, sequence, data); + + pthread_rwlock_unlock (&ipc->message_queue_lock); +} + +static void +sysvipc_removePendingMessage (SysVIPC *ipc, int sequence) +{ + pthread_rwlock_wrlock (&ipc->message_queue_lock); + + /* this doesn't free the string, it just removes it from the hashtable */ + hshFvoid_int_remove (ipc->message_queue, sequence); + + pthread_rwlock_unlock (&ipc->message_queue_lock); +} + +dynTstring * +sysvipc_getData (SysVIPC *ipc) +{ + long msgtyp; + + if (ipc->disposition == IPCClient) + { + msgtyp = IPC_SERVER_SEND_ID; + } + else + { + msgtyp = IPC_CLIENT_SEND_ID; + } + + while (1) + { + struct msgbuf *tmpBuf = malloc (sizeof (struct msgbuf) + MSGMAX); + IPCMessage *message; + dynTstring *partString; + int ret; + + do + { + pthread_testcancel(); + ret = msgrcv (ipc->queue_id, tmpBuf, MSGMAX, msgtyp, 0); + pthread_testcancel(); + } + while (ret == -1 && errno == EINTR); + + if (ret == -1) + { + perror ("msgrcv"); + + free (tmpBuf); + + return (NULL); + } + + message = (IPCMessage *) tmpBuf->mtext; + + partString = sysvipc_getPendingMessage (ipc, message->seq); + + if (partString == NULL) + { + dynTstring *retString = dynFinit(); + + dynFappend (retString, message->data, message->data_len); + + if (message->last == true) + { + free (tmpBuf); + + return (retString); + } + else + { + sysvipc_addPendingMessage (ipc, message->seq, retString); + } + } + else + { + dynFappend (partString, message->data, message->data_len); + + if (message->last == true) + { + /* + * this doesn't free the string, it just removes it from the + * hashtable + */ + sysvipc_removePendingMessage (ipc, message->seq); + + free (tmpBuf); + + return (partString); + } + } + + free (tmpBuf); + } +} + diff --git a/mk4/lib/causality/src/threadpool.c b/mk4/lib/causality/src/threadpool.c new file mode 100644 index 0000000..688c444 --- /dev/null +++ b/mk4/lib/causality/src/threadpool.c @@ -0,0 +1,96 @@ + +#include + +#include "mecha.h" + +#include "threadpool.h" +#include "processor.h" +#include "request_dispatcher.h" + +#include "request_handler_entry.h" + +struct s_ThreadPool +{ + thrTtpool *pool; +}; + + +static ThreadPool *g_threadpool = NULL; +static pthread_rwlock_t g_threadpool_lock = PTHREAD_RWLOCK_INITIALIZER; + +#undef CLEANUP_THREADPOOL + +#ifdef CLEANUP_THREADPOOL +static void threadpool_cleanup (int sig, void *ptr); +#endif + + +ThreadPool * +threadpool_new() +{ + ThreadPool *threads = malloc (sizeof (ThreadPool)); + + threads->pool = thrFinit (64, 64, 1); + +#ifdef CLEANUP_THREADPOOL +#ifdef HAVE_ON_EXIT + on_exit (threadpool_cleanup, threads); +#endif +#endif + + return (threads); +} + +void +threadpool_destroy (void *ptr) +{ + ThreadPool *threads = (ThreadPool *) ptr; + + thrFdestroy (threads->pool, 0); + + free (threads); +} + +#ifdef CLEANUP_THREADPOOL +static void +threadpool_cleanup (__attribute__ ((unused)) int sig, void *ptr) +{ + logFmsg (CONT_LOG_DEBUG, "threadpool: Cleaning up resources."); + + threadpool_destroy (ptr); +} +#endif + +ThreadPool * +threadpool_getInstance() +{ + pthread_rwlock_rdlock (&g_threadpool_lock); + + if (g_threadpool == NULL) + { + pthread_rwlock_unlock (&g_threadpool_lock); + pthread_rwlock_wrlock (&g_threadpool_lock); + + if (g_threadpool == NULL) + { + g_threadpool = threadpool_new(); + } + } + + pthread_rwlock_unlock (&g_threadpool_lock); + + return (g_threadpool); +} + +bool +threadpool_queueUserWorkItem (ThreadPool *pool, WorkItemDelegate delegate, void *context) +{ + if (thrFadd_work (pool->pool, delegate, context) == 1) + { + return (true); + } + else + { + return (false); + } +} diff --git a/mk4/mobility-client/CVS/Entries b/mk4/mobility-client/CVS/Entries new file mode 100644 index 0000000..7f1522a --- /dev/null +++ b/mk4/mobility-client/CVS/Entries @@ -0,0 +1,3 @@ +/Makefile.in/1.1/Wed May 19 21:02:58 2004//Tmk4_mod6_rc2 +D/modcgi//// +D/modmono//// diff --git a/mk4/mobility-client/CVS/Repository b/mk4/mobility-client/CVS/Repository new file mode 100644 index 0000000..304ba45 --- /dev/null +++ b/mk4/mobility-client/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/mobility-client diff --git a/mk4/mobility-client/CVS/Root b/mk4/mobility-client/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/mobility-client/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/mobility-client/CVS/Tag b/mk4/mobility-client/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/mobility-client/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/mobility-client/Makefile.in b/mk4/mobility-client/Makefile.in new file mode 100644 index 0000000..a306851 --- /dev/null +++ b/mk4/mobility-client/Makefile.in @@ -0,0 +1,12 @@ + +SUBDIRS = modcgi modmono + +default: all + + +all clean: + for dir in $(SUBDIRS); do \ + $(MAKE) -C $$dir $@; \ + done +depend: + echo No depends, I can go to the bathroom thanks. diff --git a/mk4/mobility-client/modcgi/.cvsignore b/mk4/mobility-client/modcgi/.cvsignore new file mode 100644 index 0000000..2ba3218 --- /dev/null +++ b/mk4/mobility-client/modcgi/.cvsignore @@ -0,0 +1,14 @@ +.svn +modcgi-client +modcgi-client-dmalloc.sh +build.h +.dep +test-cgi.sh +.rev +.build +modcgi-client-valgrind.sh +modcgi-client-check.sh +modcgi-client-valgrind-addrcheck.sh +modcgi-client-valgrind-helgrind.sh +modcgi-client-valgrind-vgprof.sh +modcgi diff --git a/mk4/mobility-client/modcgi/CVS/Entries b/mk4/mobility-client/modcgi/CVS/Entries new file mode 100644 index 0000000..23d3b72 --- /dev/null +++ b/mk4/mobility-client/modcgi/CVS/Entries @@ -0,0 +1,4 @@ +/.cvsignore/1.1/Thu May 13 21:52:14 2004//Tmk4_mod6_rc2 +/Makefile/1.3/Fri May 14 19:12:09 2004//Tmk4_mod6_rc2 +D/include//// +D/src//// diff --git a/mk4/mobility-client/modcgi/CVS/Repository b/mk4/mobility-client/modcgi/CVS/Repository new file mode 100644 index 0000000..2d2eb11 --- /dev/null +++ b/mk4/mobility-client/modcgi/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/mobility-client/modcgi diff --git a/mk4/mobility-client/modcgi/CVS/Root b/mk4/mobility-client/modcgi/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/mobility-client/modcgi/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/mobility-client/modcgi/CVS/Tag b/mk4/mobility-client/modcgi/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/mobility-client/modcgi/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/mobility-client/modcgi/Makefile b/mk4/mobility-client/modcgi/Makefile new file mode 100644 index 0000000..526f52f --- /dev/null +++ b/mk4/mobility-client/modcgi/Makefile @@ -0,0 +1,16 @@ +CONTINUITY = ../../continuity + +TARGET = modcgi +TARGETTYPE = executable + +SOURCES = src/modcgi.c src/remote_process.c src/string_collection.c \ + src/cgi_request.c src/fd_watcher_entry.c src/fd_watcher.c \ + src/fd_reader.c src/process_watcher_entry.c src/process_watcher.c + +INCLUDES += -Iinclude -I../../lib/aura/include -I../../lib/causality/include -I../../lib/causality-client/include +#STATIC_LIBS += $(CONTINUITY)/lib/libcausality-client.a $(CONTINUITY)/lib/mechanism.a + +STATIC_LIBS += $(CONTINUITY)/lib/libcausality-client.a $(CONTINUITY)/lib/mechanism.a +WHOLE_STATIC_LIBS += $(CONTINUITY)/lib/libaura.a $(CONTINUITY)/lib/libcausality.a + +include $(CONTINUITY)/lib/build.mk diff --git a/mk4/mobility-client/modcgi/include/.cvsignore b/mk4/mobility-client/modcgi/include/.cvsignore new file mode 100644 index 0000000..90ec22b --- /dev/null +++ b/mk4/mobility-client/modcgi/include/.cvsignore @@ -0,0 +1 @@ +.svn diff --git a/mk4/mobility-client/modcgi/include/CVS/Entries b/mk4/mobility-client/modcgi/include/CVS/Entries new file mode 100644 index 0000000..e1c50fe --- /dev/null +++ b/mk4/mobility-client/modcgi/include/CVS/Entries @@ -0,0 +1,10 @@ +/.cvsignore/1.1/Thu May 13 21:52:14 2004//Tmk4_mod6_rc2 +/cgi_request.h/1.1/Thu May 13 21:38:06 2004//Tmk4_mod6_rc2 +/fd_reader.h/1.1/Thu May 13 21:38:06 2004//Tmk4_mod6_rc2 +/fd_watcher.h/1.1/Thu May 13 21:38:06 2004//Tmk4_mod6_rc2 +/fd_watcher_entry.h/1.1/Thu May 13 21:38:06 2004//Tmk4_mod6_rc2 +/process_watcher.h/1.1/Thu May 13 21:38:06 2004//Tmk4_mod6_rc2 +/process_watcher_entry.h/1.1/Thu May 13 21:38:06 2004//Tmk4_mod6_rc2 +/remote_process.h/1.2/Sun May 16 20:31:59 2004//Tmk4_mod6_rc2 +/string_collection.h/1.1/Thu May 13 21:38:06 2004//Tmk4_mod6_rc2 +D diff --git a/mk4/mobility-client/modcgi/include/CVS/Repository b/mk4/mobility-client/modcgi/include/CVS/Repository new file mode 100644 index 0000000..26ba1fc --- /dev/null +++ b/mk4/mobility-client/modcgi/include/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/mobility-client/modcgi/include diff --git a/mk4/mobility-client/modcgi/include/CVS/Root b/mk4/mobility-client/modcgi/include/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/mobility-client/modcgi/include/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/mobility-client/modcgi/include/CVS/Tag b/mk4/mobility-client/modcgi/include/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/mobility-client/modcgi/include/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/mobility-client/modcgi/include/cgi_request.h b/mk4/mobility-client/modcgi/include/cgi_request.h new file mode 100644 index 0000000..42f22e9 --- /dev/null +++ b/mk4/mobility-client/modcgi/include/cgi_request.h @@ -0,0 +1,16 @@ + +#ifndef __CGI_REQUEST_H__ +#define __CGI_REQUEST_H__ + +#include "http_request.h" + +typedef struct s_CgiRequest CgiRequest; + +CgiRequest * cgi_request_new (HttpRequest *request); +void cgi_request_destroy (void *ptr); + +bool cgi_request_start (CgiRequest *instance); + +void cgi_request_handler (HttpRequest *request, void *context); + +#endif diff --git a/mk4/mobility-client/modcgi/include/fd_reader.h b/mk4/mobility-client/modcgi/include/fd_reader.h new file mode 100644 index 0000000..52f88c4 --- /dev/null +++ b/mk4/mobility-client/modcgi/include/fd_reader.h @@ -0,0 +1,15 @@ + +#ifndef __FD_READER_H__ +#define __FD_READER_H__ + +#include + +typedef struct s_FDReader FDReader; + +FDReader * fd_reader_new (int fd); +void fd_reader_destroy (void *ptr); + +ssize_t fd_reader_readLine (FDReader *instance, char *buf, int len); +ssize_t fd_reader_read (FDReader *instance, char *buf, int len); + +#endif diff --git a/mk4/mobility-client/modcgi/include/fd_watcher.h b/mk4/mobility-client/modcgi/include/fd_watcher.h new file mode 100644 index 0000000..ce68e3e --- /dev/null +++ b/mk4/mobility-client/modcgi/include/fd_watcher.h @@ -0,0 +1,21 @@ + +#ifndef __FD_WATCHER_H__ +#define __FD_WATCHER_H__ + +#include "fd_watcher_entry.h" + +typedef struct s_FDWatcher FDWatcher; + +FDWatcher * fd_watcher_new (void); +void fd_watcher_destroy (void *ptr); + +FDWatcher * fd_watcher_getInstance (void); + +void fd_watcher_watchRead (FDWatcher *instance, int fd, FDWatcherDelegate delegate, void *context); +void fd_watcher_watchWrite (FDWatcher *instance, int fd, FDWatcherDelegate delegate, void *context); + +void fd_watcher_watchFD (FDWatcher *instance, int fd, FDWatcherDelegate delegate, void *context, short events); +void fd_watcher_removeWatchFD (FDWatcher *instance, int fd); + + +#endif diff --git a/mk4/mobility-client/modcgi/include/fd_watcher_entry.h b/mk4/mobility-client/modcgi/include/fd_watcher_entry.h new file mode 100644 index 0000000..26dd50b --- /dev/null +++ b/mk4/mobility-client/modcgi/include/fd_watcher_entry.h @@ -0,0 +1,19 @@ + +#ifndef __FD_WATCHER_ENTRY_H__ +#define __FD_WATCHER_ENTRY_H__ + +typedef struct s_FDWatcherEntry FDWatcherEntry; + +typedef void (*FDWatcherDelegate) (void *context, int fd, short events); + +FDWatcherEntry * fd_watcher_entry_new (int fd, FDWatcherDelegate function, void *context, short events); +void fd_watcher_entry_destroy (void *ptr); + +void fd_watcher_entry_addEvent (FDWatcherEntry *instance, short event); + +void fd_watcher_entry_invoke (FDWatcherEntry *instance, short events); + +int fd_watcher_entry_getFD (FDWatcherEntry *instance); +short fd_watcher_entry_getEvents (FDWatcherEntry *instance); + +#endif diff --git a/mk4/mobility-client/modcgi/include/process_watcher.h b/mk4/mobility-client/modcgi/include/process_watcher.h new file mode 100644 index 0000000..4c039bf --- /dev/null +++ b/mk4/mobility-client/modcgi/include/process_watcher.h @@ -0,0 +1,19 @@ + +#ifndef __PROCESS_WATCHER_H__ +#define __PROCESS_WATCHER_H__ + +typedef struct s_ProcessWatcher ProcessWatcher; + +ProcessWatcher * process_watcher_new (void); +void process_watcher_destroy (void *ptr); + +typedef void (*ProcessWatcherDelegate) (void *context, int status); + +ProcessWatcher * process_watcher_getInstance (void); + +void process_watcher_watchPid (ProcessWatcher *instance, int pid, + ProcessWatcherDelegate delegate, void *context); + +void process_watcher_removeWatchPid (ProcessWatcher *instance, int pid); + +#endif diff --git a/mk4/mobility-client/modcgi/include/process_watcher_entry.h b/mk4/mobility-client/modcgi/include/process_watcher_entry.h new file mode 100644 index 0000000..6db056c --- /dev/null +++ b/mk4/mobility-client/modcgi/include/process_watcher_entry.h @@ -0,0 +1,16 @@ + +#ifndef __PROCESS_WATCHER_ENTRY_H__ +#define __PROCESS_WATCHER_ENTRY_H__ + +#include + +#include "process_watcher.h" + +typedef struct s_ProcessWatcherEntry ProcessWatcherEntry; + +ProcessWatcherEntry * process_watcher_entry_new (int pid, ProcessWatcherDelegate delegate, void *context); +void process_watcher_entry_destroy (void *ptr); + +void process_watcher_entry_invoke (ProcessWatcherEntry *instance, int status); + +#endif diff --git a/mk4/mobility-client/modcgi/include/remote_process.h b/mk4/mobility-client/modcgi/include/remote_process.h new file mode 100644 index 0000000..d6e0966 --- /dev/null +++ b/mk4/mobility-client/modcgi/include/remote_process.h @@ -0,0 +1,27 @@ +#ifndef __REMOTE_PROCESS_H__ +#define __REMOTE_PROCESS_H__ + +#include "mecha.h" + +typedef struct s_RemoteProcess RemoteProcess; + +RemoteProcess * remote_process_new (const char *executable); +void remote_process_destroy (void *ptr); + +void remote_process_addEnvironment (RemoteProcess *instance, const char *variable); +void remote_process_addEnvironmentData (RemoteProcess *instance, const char *variable, int len); + +void remote_process_addArgument (RemoteProcess *instance, const char *argument); + +bool remote_process_start (RemoteProcess *instance); + +int remote_process_getStdIn (RemoteProcess *instance); +int remote_process_getStdOut (RemoteProcess *instance); +int remote_process_getStdErr (RemoteProcess *instance); + +bool remote_process_closeStdOut (RemoteProcess *instance); +bool remote_process_closeStdIn (RemoteProcess *instance); + +const char *remote_process_get_executable (RemoteProcess *instance); + +#endif diff --git a/mk4/mobility-client/modcgi/include/string_collection.h b/mk4/mobility-client/modcgi/include/string_collection.h new file mode 100644 index 0000000..6fd9ba2 --- /dev/null +++ b/mk4/mobility-client/modcgi/include/string_collection.h @@ -0,0 +1,15 @@ + +#ifndef __STRING_COLLECTION_H__ +#define __STRING_COLLECTION_H__ + +typedef struct s_StringCollection StringCollection; + +StringCollection * string_collection_new (void); +void string_collection_destroy (void *ptr); + +void string_collection_addString (StringCollection *instance, const char *string); +void string_collection_addData (StringCollection *instance, const char *string, int len); +char ** string_collection_getInternal (StringCollection *instance); + + +#endif diff --git a/mk4/mobility-client/modcgi/src/.cvsignore b/mk4/mobility-client/modcgi/src/.cvsignore new file mode 100644 index 0000000..12fa2a0 --- /dev/null +++ b/mk4/mobility-client/modcgi/src/.cvsignore @@ -0,0 +1,3 @@ +*.sw? +.deps +.svn diff --git a/mk4/mobility-client/modcgi/src/CVS/Entries b/mk4/mobility-client/modcgi/src/CVS/Entries new file mode 100644 index 0000000..f11a01a --- /dev/null +++ b/mk4/mobility-client/modcgi/src/CVS/Entries @@ -0,0 +1,11 @@ +/.cvsignore/1.1/Thu May 13 21:52:15 2004//Tmk4_mod6_rc2 +/cgi_request.c/1.2/Sun May 16 20:31:59 2004//Tmk4_mod6_rc2 +/fd_reader.c/1.2/Fri May 14 06:20:33 2004//Tmk4_mod6_rc2 +/fd_watcher.c/1.1/Thu May 13 21:38:06 2004//Tmk4_mod6_rc2 +/fd_watcher_entry.c/1.1/Thu May 13 21:38:06 2004//Tmk4_mod6_rc2 +/modcgi.c/1.1/Thu May 13 21:38:06 2004//Tmk4_mod6_rc2 +/process_watcher.c/1.1/Thu May 13 21:38:06 2004//Tmk4_mod6_rc2 +/process_watcher_entry.c/1.1/Thu May 13 21:38:06 2004//Tmk4_mod6_rc2 +/remote_process.c/1.3/Sun May 16 20:31:59 2004//Tmk4_mod6_rc2 +/string_collection.c/1.1/Thu May 13 21:38:06 2004//Tmk4_mod6_rc2 +D diff --git a/mk4/mobility-client/modcgi/src/CVS/Repository b/mk4/mobility-client/modcgi/src/CVS/Repository new file mode 100644 index 0000000..ded7df8 --- /dev/null +++ b/mk4/mobility-client/modcgi/src/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/mobility-client/modcgi/src diff --git a/mk4/mobility-client/modcgi/src/CVS/Root b/mk4/mobility-client/modcgi/src/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/mobility-client/modcgi/src/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/mobility-client/modcgi/src/CVS/Tag b/mk4/mobility-client/modcgi/src/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/mobility-client/modcgi/src/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/mobility-client/modcgi/src/cgi_request.c b/mk4/mobility-client/modcgi/src/cgi_request.c new file mode 100644 index 0000000..252c37e --- /dev/null +++ b/mk4/mobility-client/modcgi/src/cgi_request.c @@ -0,0 +1,651 @@ + +#include +#include + + +#include "cgi_request.h" + +#include "remote_process.h" +#include "http_request.h" +#include "string_collection.h" +#include "fd_reader.h" +#include "fd_watcher.h" + +struct s_CgiRequest +{ + HttpRequest *request; + RemoteProcess *process; + + FDReader *stdoutReader; + FDReader *stderrReader; + + bool readHeaders; + bool finished; + + unsigned int entityOffset; +}; + +static void cgi_request_addEnvFromVariable (CgiRequest *instance, + const char *envName, int envLen, const char *varName); + +static void cgi_request_addEnv (CgiRequest *instance, const char *envName, + int envLen, const char *value, int valLen); + +static void cgi_request_addEnvFromHeader (CgiRequest *instance, + const char *envName, int envLen, const char *varName); + +static void cgi_request_initEnvironment (CgiRequest *instance); + +static void cgi_request_addRequestVars (CgiRequest *instance); + +static void cgi_request_handleStdError (void *context, int fd, short events); + +static void cgi_request_add_env_from_parent (CgiRequest *instance, const char *name, int len); + +CgiRequest * +cgi_request_new (HttpRequest *request) +{ + CgiRequest *instance = (CgiRequest *) malloc (sizeof (CgiRequest)); + + instance->request = request; + + instance->process = NULL; + + instance->readHeaders = false; + + instance->stdoutReader = NULL; + + instance->stderrReader = NULL; + + instance->entityOffset = 0; + + instance->finished = false; + + return (instance); +} + +void +cgi_request_destroy (void *ptr) +{ + CgiRequest *instance = (CgiRequest *) ptr; + + /* + * even if getStdOut or getStdIn return -1, it shouldn't hurt to remove + * that + */ + if (instance->process != NULL) + { + fd_watcher_removeWatchFD (fd_watcher_getInstance(), + remote_process_getStdOut (instance->process)); + + fd_watcher_removeWatchFD (fd_watcher_getInstance(), + remote_process_getStdIn (instance->process)); + + remote_process_destroy (instance->process); + } + + http_request_destroy (instance->request); + + if (instance->stdoutReader != NULL) + { + fd_reader_destroy (instance->stdoutReader); + } + + if (instance->stderrReader != NULL) + { + fd_reader_destroy (instance->stderrReader); + } + + free (instance); +} + +void +cgi_request_handler (HttpRequest *request, __attribute__((unused)) void *context) +{ + CgiRequest *cgiReq = cgi_request_new (request); + + cgi_request_start (cgiReq); +} + +static void +cgi_request_finish (CgiRequest *instance, int status) +{ + assert (instance->finished == false); + + /* If we got headers but never sent them (if we didn't have a body) */ + if (instance->readHeaders == true && http_request_headersSent (instance->request) == false) + { + /* BUGBUG: We should be using something better than sending an empty + * string to flush the headers. + * + * -eric@5stops.com 5.15.2004 + */ + http_request_writeData (instance->request, "", 0); + } + + instance->finished = true; + + http_request_finishStatus (instance->request, status); + + cgi_request_destroy (instance); +} + +static bool +cgi_request_setNonBlocking (int fd) +{ + int fdFlags; + + assert (fd >= 0); + + if ((fdFlags = fcntl (fd, F_GETFL)) == -1) + { + return (false); + } + + fdFlags |= O_NONBLOCK; + + if (fcntl (fd, F_SETFL, fdFlags) == -1) + { + return (false); + } + + return (true); +} + +static int +cgi_request_readHeaders (CgiRequest *instance) +{ + while (true) + { + char reqLine[1024]; + + char *name_p; + char *value_p; + char *state_p; + + ssize_t ret = fd_reader_readLine (instance->stdoutReader, reqLine, sizeof (reqLine)); + + if (ret < 1) + { + return (ret); + } + + if (reqLine[0] == '\n') + { + break; + } + + name_p = strtok_r (reqLine, ":", &state_p); + value_p = state_p; + + if (value_p != NULL) + { + while (*value_p == ' ' && *value_p != '\n' && *value_p != '\0') + { + value_p++; + } + } + else + { + /* could not parse headers */ + return (-1); + } + + if (name_p != NULL && value_p != NULL) + { + int value_len = (reqLine + ret) - value_p; + + strFstrip_crlf (value_p, value_len); + + if (strcasecmp (name_p, "Status") == 0) + { + char *status = strtok_r (NULL, " ", &value_p); + + http_request_setHttpStatus (instance->request, atoi (status), value_p); + } + else + { + http_request_setResponseHeaderData (instance->request, name_p, value_p, value_len); + } + } + } + + return (0); +} + +static ssize_t +cgi_request_readContent (CgiRequest *instance) +{ + char buffer[1024]; + + while (true) + { + ssize_t ret = fd_reader_read (instance->stdoutReader, buffer, sizeof (buffer)); + + if (ret > 0) + { + if (http_request_writeData (instance->request, buffer, ret) == false) + { + /* if we couldn't write, we're obviously done here */ + return (0); + } + } + else + { + return (ret); + } + } +} + +static void +cgi_request_handleStdError (void *context, MECHA_UNUSED_ARGUMENT int fd, MECHA_UNUSED_ARGUMENT short events) +{ + CgiRequest *instance = (CgiRequest *) context; + char lineBuf[1024]; + + while (true) + { + ssize_t ret = fd_reader_readLine (instance->stderrReader, lineBuf, sizeof (lineBuf)); + + if (ret == 0) + { + return; + } + + if (ret < 0 && ret == -EAGAIN) + { + fd_watcher_watchFD (fd_watcher_getInstance(), + remote_process_getStdErr (instance->process), + cgi_request_handleStdError, instance, POLLIN); + + return; + } + + if (ret == 1) + { + continue; + } + + lineBuf[ret - 1] = 0; + + logFmsg (CONT_LOG_ERROR, "%s: %s", remote_process_get_executable (instance->process), lineBuf); + } +} + +static void +cgi_request_handleStdOut (void *context, MECHA_UNUSED_ARGUMENT int fd, MECHA_UNUSED_ARGUMENT short events) +{ + CgiRequest *instance = context; + ssize_t ret; + + if (instance->readHeaders == false) + { + ret = cgi_request_readHeaders (instance); + + if (ret == 0) + { + /* we're done finding headers */ + instance->readHeaders = true; + } + } + + if (instance->readHeaders == true) + { + ret = cgi_request_readContent (instance); + + if (ret == 0) + { + /* we're done with the request */ + cgi_request_finish (instance, STATUS_EXIT); + + return; + } + } + + if (ret < 0 && ret != -EAGAIN) + { + char buf[1024]; + + snprintf (buf, sizeof (buf), "Error while processing cgi: %s (%d)", strerror (-ret), -ret); + + logFmsg (CONT_LOG_DEBUG, "mod/cgi: %s", buf); + + if (http_request_headersSent (instance->request) == false) + { + http_request_setHttpStatus (instance->request, 500, "Error"); + + http_request_writeString (instance->request, buf); + } + + /* we have to bail */ + cgi_request_finish (instance, STATUS_ERROR); + } + else + { + fd_watcher_watchFD (fd_watcher_getInstance(), + remote_process_getStdOut (instance->process), + cgi_request_handleStdOut, instance, POLLIN); + } +} + +static void +cgi_request_handleStdIn (void *context, __attribute__((unused)) int fd, __attribute__((unused)) short events) +{ + CgiRequest *instance = context; + const dynTstring *entity; + int len; + + entity = http_request_getEntireEntity (instance->request); + + if (entity == NULL) + { + remote_process_closeStdIn (instance->process); + + return; + } + + len = write (remote_process_getStdIn (instance->process), + dynFgetstr (entity) + instance->entityOffset, + dynFgetlen (entity) - instance->entityOffset); + + if (len < 1) + { + remote_process_closeStdIn (instance->process); + + return; + } + + instance->entityOffset += len; + + if (dynFgetlen (entity) == instance->entityOffset) + { + remote_process_closeStdIn (instance->process); + + return; + } + + fd_watcher_watchFD (fd_watcher_getInstance(), + remote_process_getStdIn (instance->process), + cgi_request_handleStdIn, instance, POLLOUT); + +} + +bool +cgi_request_start (CgiRequest *instance) +{ + bool ret; + + const dynTstring *path = http_request_getVariableString ( + instance->request, "path"); + + if (path == NULL) + { + /* we'll just let this fall through */ + cgi_request_finish (instance, STATUS_PROCEED); + + return (false); + } + + { + struct stat sbuf; + + if (lstat (dynFgetstr (path), &sbuf) == -1 || + !S_ISREG (sbuf.st_mode) || + (sbuf.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0) + { + /* we can't run this, so we won't try */ + cgi_request_finish (instance, STATUS_PROCEED); + + return (false); + } + } + + instance->process = remote_process_new ( + dynFgetstr (path)); + + cgi_request_initEnvironment (instance); + + ret = remote_process_start (instance->process); + + if (ret == false) + { + /* we'll just let this fall through */ + cgi_request_finish (instance, STATUS_PROCEED); + + return (false); + } + + cgi_request_setNonBlocking (remote_process_getStdIn (instance->process)); + + cgi_request_setNonBlocking (remote_process_getStdOut (instance->process)); + + cgi_request_setNonBlocking (remote_process_getStdErr (instance->process)); + + instance->stdoutReader = fd_reader_new ( + remote_process_getStdOut (instance->process)); + + instance->stderrReader = fd_reader_new ( + remote_process_getStdErr (instance->process)); + + http_request_setHttpStatus (instance->request, 200, "OK OK"); + + { + const dynTstring *method = http_request_getVariableString ( + instance->request, "method"); + + if (method != NULL && strcmp (dynFgetstr (method), "POST") == 0) + { + fd_watcher_watchFD (fd_watcher_getInstance(), + remote_process_getStdIn (instance->process), + cgi_request_handleStdIn, instance, POLLOUT); + } + else + { + remote_process_closeStdIn (instance->process); + } + } + + fd_watcher_watchFD (fd_watcher_getInstance(), + remote_process_getStdOut (instance->process), + cgi_request_handleStdOut, instance, POLLIN); + + fd_watcher_watchFD (fd_watcher_getInstance(), + remote_process_getStdErr (instance->process), + cgi_request_handleStdError, instance, POLLIN); + + return (true); +} + +static void +cgi_request_initEnvironment (CgiRequest *instance) +{ + cgi_request_add_env_from_parent (instance, "LD_PRELOAD", 10); + cgi_request_add_env_from_parent (instance, "LD_LIBRARY_PATH", 15); + cgi_request_add_env_from_parent (instance, "VG_ARGS", 7); + + cgi_request_add_env_from_parent (instance, "TERM", 4); + cgi_request_add_env_from_parent (instance, "PATH", 4); + cgi_request_add_env_from_parent (instance, "HOSTTYPE", 8); + cgi_request_add_env_from_parent (instance, "VENDOR", 6); + cgi_request_add_env_from_parent (instance, "OSTYPE", 6); + cgi_request_add_env_from_parent (instance, "LANG", 4); + cgi_request_add_env_from_parent (instance, "MACHTYPE", 8); + cgi_request_add_env_from_parent (instance, "PWD", 3); + cgi_request_add_env_from_parent (instance, "HOST", 4); + cgi_request_add_env_from_parent (instance, "HOSTNAME", 8); + cgi_request_add_env_from_parent (instance, "TZ", 2); + + cgi_request_addEnvFromVariable (instance, "SERVER_SOFTWARE", + 15, "server"); + + /* SERVER_NAME */ + + cgi_request_addEnv (instance, "GATEWAY_INTERFACE", + 17, "CGI/1.1", 7); + + cgi_request_addEnvFromVariable (instance, "SERVER_PROTOCOL", + 15, "protocol"); + + /* + cgi_request_addEnvFromVariable (instance, "SERVER_PORT", + 11, ""); + */ + + cgi_request_addEnvFromVariable (instance, "REQUEST_METHOD", + 14, "method"); + + cgi_request_addEnvFromVariable (instance, "PATH_INFO", + 9, "path_info"); + + cgi_request_addEnvFromVariable (instance, "PATH_TRANSLATED", + 15, "path_translated"); + + cgi_request_addEnvFromVariable (instance, "SCRIPT_NAME", + 11, "uri"); + + cgi_request_addEnvFromVariable (instance, "QUERY_STRING", + 12, "query"); + + /* + * we don't have the resolved version of REMOTE_ADDR from the webserver, + * and there isn't any benefit of resolving it ourselves. + * + * ---- + * + cgi_request_addEnvFromVariable (instance, "REMOTE_HOST", + 11, ""); + */ + + cgi_request_addEnv (instance, "REMOTE_ADDR", + 11, http_request_getRemoteIP (instance->request), + strlen (http_request_getRemoteIP (instance->request))); + + /* + cgi_request_addEnvFromVariable (instance, "AUTH_TYPE", + 9, ""); + */ + + /* + cgi_request_addEnvFromVariable (instance, "REMOTE_USER", + 11, ""); + */ + + /* + cgi_request_addEnvFromVariable (instance, "REMOTE_IDENT", + 12, ""); + */ + + cgi_request_addEnvFromHeader (instance, "CONTENT_TYPE", + 12, "content-type"); + + cgi_request_addEnvFromHeader (instance, "CONTENT_LENGTH", + 14, "content-length"); + + /* This is added by apache and seems like a good idea */ + cgi_request_addEnvFromVariable (instance, "SCRIPT_FILENAME", + 15, "path"); + + cgi_request_addRequestVars (instance); +} + +static void +cgi_request_add_env_from_parent (CgiRequest *instance, const char *name, int len) +{ + char *e = getenv (name); + + if (e != NULL) + { + cgi_request_addEnv (instance, name, len, e, strlen (e)); + } +} + +static void +cgi_request_addRequestVars (CgiRequest *instance) +{ + hshTiterator *iter = http_request_getRequestHeaderIterator ( + instance->request); + + dynTstring *newKey = dynFinit(); + + while (hshFiterator_next (iter) == 1) + { + const char *key = (const char *) hshFiterator_current_key (iter); + const dynTstring *value = (const dynTstring *) + hshFiterator_current_value (iter); + + dynFreset (newKey); + dynFappend (newKey, "HTTP_", 5); + + while (*key != 0) + { + if (*key == '-') + { + dynFappend (newKey, "_", 1); + } + else + { + char c = toupper (*key); + + dynFappend (newKey, &c, 1); + } + + key++; + } + + cgi_request_addEnv (instance, dynFgetstr (newKey), + dynFgetlen (newKey), dynFgetstr (value), + dynFgetlen (value)); + } + + hshFiterator_free (iter); + dynFfree (newKey); +} + +static void +cgi_request_addEnv (CgiRequest *instance, const char *envName, + int envLen, const char *value, int valLen) +{ + dynTstring *envString = dynFinit(); + + dynFappend (envString, envName, envLen); + + dynFappend (envString, "=", 1); + + if (valLen > 0) + { + dynFappend (envString, value, valLen); + } + + remote_process_addEnvironmentData (instance->process, + dynFgetstr (envString), dynFgetlen (envString)); + + dynFfree (envString); +} + +static void +cgi_request_addEnvFromHeader (CgiRequest *instance, const char *envName, + int envLen, const char *varName) +{ + const dynTstring *value = http_request_getRequestHeaderString ( + instance->request, varName); + + if (value != NULL) + { + cgi_request_addEnv (instance, envName, envLen, + dynFgetstr (value), dynFgetlen (value)); + } +} + +static void +cgi_request_addEnvFromVariable (CgiRequest *instance, const char *envName, + int envLen, const char *varName) +{ + const dynTstring *value = http_request_getVariableString ( + instance->request, varName); + + if (value != NULL) + { + cgi_request_addEnv (instance, envName, envLen, + dynFgetstr (value), dynFgetlen (value)); + } +} diff --git a/mk4/mobility-client/modcgi/src/fd_reader.c b/mk4/mobility-client/modcgi/src/fd_reader.c new file mode 100644 index 0000000..2a20f04 --- /dev/null +++ b/mk4/mobility-client/modcgi/src/fd_reader.c @@ -0,0 +1,229 @@ + +#include +#include +#include +#include + +#include "mecha.h" + +#include "fd_reader.h" + +#define READER_CHUNK_SZ 1024 + +struct s_FDReader +{ + char *buf; + + int allocSize; + + ssize_t startOffset; + ssize_t endOffset; + + int fd; + + bool foundEnd; +}; + +FDReader * +fd_reader_new (int fd) +{ + FDReader *instance = (FDReader *) malloc (sizeof (FDReader)); + + instance->buf = malloc (sizeof (char) * READER_CHUNK_SZ); + instance->allocSize = READER_CHUNK_SZ; + + instance->startOffset = 0; + instance->endOffset = 0; + + instance->fd = fd; + + instance->foundEnd = FALSE; + + return (instance); +} + +void +fd_reader_destroy (void *ptr) +{ + FDReader *instance = (FDReader *) ptr; + + free (instance->buf); + + free (instance); +} + +static int +fd_reader_populateBuffer (FDReader *instance, int requestedLen, bool guarantee) +{ + /* if we have more in our buffer than is requested, we're okay. */ + if (instance->endOffset - instance->startOffset > requestedLen) + { + return (0); + } + + if (instance->foundEnd == TRUE) + { + return (0); + } + + /* reset the offsets if we have an empty buffer */ + if (instance->startOffset == instance->endOffset) + { + instance->startOffset = 0; + instance->endOffset = 0; + } + + /* we don't have enough room to write what we want to onto our buffer */ + if (instance->startOffset + requestedLen > instance->allocSize) + { + /* + * if we're just too close to the end, lets move back to the beginning + * of the buffer + */ + if (requestedLen <= instance->allocSize) + { + memmove (instance->buf, instance->buf + instance->startOffset, + instance->endOffset - instance->startOffset); + + instance->endOffset = instance->endOffset - instance->startOffset; + instance->startOffset = 0; + } + else + { + int newLen = sizeof (char) * (instance->startOffset + + requestedLen + READER_CHUNK_SZ); + + /* we need to get more buffer space */ + instance->buf = realloc (instance->buf, newLen); + + logFmsg (CONT_LOG_DEBUG, "modcgi/fd_reader: resizing from %d -> %d", + instance->allocSize, newLen); + + instance->allocSize = newLen; + } + } + + do + { + ssize_t len = read (instance->fd, instance->buf + instance->endOffset, + instance->allocSize - instance->endOffset); + + if (len == -1) + { + return (errno); + } + else if (len == 0) + { + instance->foundEnd = TRUE; + + break; + } + + instance->endOffset += len; + } + while (requestedLen > instance->endOffset - instance->startOffset && guarantee == TRUE); + + return (0); +} + + +ssize_t +fd_reader_readLine (FDReader *instance, char *buf, int len) +{ + char *p; + ssize_t i; + int status; + + status = fd_reader_populateBuffer (instance, len, TRUE); + + if (status != 0) + { + return (-status); + } + + p = instance->buf + instance->startOffset; + + for (i = 0; i < (len - 1) && instance->startOffset < instance->endOffset; i++) + { + instance->startOffset++; + + if (p[i] == '\r') + { + buf[i] = '\n'; + + buf[i + 1] = 0; + + /* if we're using windows, which uses: \r\n */ + if (p[i + 1] == '\n') + { + instance->startOffset++; + } + + /* + * if "i" is the offset of our last character, we have to add one + * to get the length + */ + return (i + 1); + } + else if (p[i] == '\n') + { + buf[i] = '\n'; + + buf[i + 1] = 0; + + /* if we're using a mac, which uses: \n\r */ + if (p[i + 1] == '\r') + { + instance->startOffset++; + } + + /* + * if "i" is the offset of our last character, we have to add one + * to get the length + */ + return (i + 1); + } + else + { + buf[i] = p[i]; + } + } + + /* make sure we always end in a NULL */ + buf[i] = 0; + + return (i); +} + +ssize_t +fd_reader_read (FDReader *instance, char *buf, int len) +{ + int status; + + status = fd_reader_populateBuffer (instance, len, FALSE); + + if (status != 0) + { + return (-status); + } + + /* + * if we have less bytes to return than the buffer has room, we need to + * only return what we have. + * + * this will happen if we have found the end of the file + */ + if (len > instance->endOffset - instance->startOffset) + { + len = instance->endOffset - instance->startOffset; + } + + if (len != 0) + { + memcpy (buf, instance->buf + instance->startOffset, len); + + instance->startOffset += len; + } + + return (len); +} diff --git a/mk4/mobility-client/modcgi/src/fd_watcher.c b/mk4/mobility-client/modcgi/src/fd_watcher.c new file mode 100644 index 0000000..af8d871 --- /dev/null +++ b/mk4/mobility-client/modcgi/src/fd_watcher.c @@ -0,0 +1,172 @@ + +#include +#include + +#include "mecha.h" + +#include "fd_watcher.h" + +#include "fd_watcher_entry.h" + +static FDWatcher *g_instance = NULL; +static pthread_once_t g_instanceOnce = PTHREAD_ONCE_INIT; + +struct s_FDWatcher +{ + hshTvoid_list *fdList; + + pthread_mutex_t fdListMutex; + pthread_cond_t fdListCond; + + pthread_t pollerThread; +}; + +static void *fd_watcher_dispatcher (void *context); +static void fd_watcher_setupInstance (void); + +FDWatcher * +fd_watcher_new (void) +{ + FDWatcher *instance = (FDWatcher *) malloc (sizeof (FDWatcher)); + + instance->fdList = hshFvoid_int_init (fd_watcher_entry_destroy); + + pthread_mutex_init (&instance->fdListMutex, NULL); + pthread_cond_init (&instance->fdListCond, NULL); + + pthread_create (&instance->pollerThread, NULL, fd_watcher_dispatcher, instance); + + return (instance); +} + +void +fd_watcher_destroy (void *ptr) +{ + FDWatcher *instance = (FDWatcher *) ptr; + + pthread_cancel (instance->pollerThread); + pthread_join (instance->pollerThread, NULL); + + hshFvoid_destroy (instance->fdList); + + pthread_mutex_destroy (&instance->fdListMutex); + pthread_cond_destroy (&instance->fdListCond); + + free (instance); +} + +static void +fd_watcher_setupInstance() +{ + g_instance = fd_watcher_new(); +} + +FDWatcher * +fd_watcher_getInstance() +{ + pthread_once (&g_instanceOnce, fd_watcher_setupInstance); + + return (g_instance); +} + +static void * +fd_watcher_dispatcher (void *context) +{ + FDWatcher *instance = (FDWatcher *) context; + + while (1) + { + struct pollfd *ufds; + hshTiterator *iter; + int i = 0; + int listSize; + + pthread_mutex_lock (&instance->fdListMutex); + + if (hshFvoid_size (instance->fdList) == 0) + { + pthread_cond_wait (&instance->fdListCond, &instance->fdListMutex); + } + + listSize = hshFvoid_size (instance->fdList); + + ufds = malloc (sizeof (struct pollfd) * + listSize); + + iter = hshFiterator_init (instance->fdList); + + while (hshFiterator_next (iter) == 1) + { + FDWatcherEntry *entry = hshFiterator_current_value (iter); + + ufds[i].fd = fd_watcher_entry_getFD (entry); + ufds[i].events = fd_watcher_entry_getEvents (entry); + + i++; + } + + hshFiterator_free (iter); + + pthread_mutex_unlock (&instance->fdListMutex); + + { + int rfds = poll (ufds, listSize, 300); + + for (i = 0; i < listSize && rfds > 0; i++) + { + if (ufds[i].revents != 0) + { + FDWatcherEntry *entry; + + pthread_mutex_lock (&instance->fdListMutex); + + entry = hshFvoid_int_remove (instance->fdList, ufds[i].fd); + + pthread_mutex_unlock (&instance->fdListMutex); + + if (entry != NULL) + { + /* + * this will destroy the entry as soon as it is completed + */ + fd_watcher_entry_invoke (entry, ufds[i].revents); + } + } + } + } + + free (ufds); + } + + return (NULL); +} + +void +fd_watcher_removeWatchFD (FDWatcher *instance, int fd) +{ + pthread_mutex_lock (&instance->fdListMutex); + + hshFvoid_int_del (instance->fdList, fd); + + pthread_mutex_unlock (&instance->fdListMutex); +} + +void +fd_watcher_watchFD (FDWatcher *instance, int fd, FDWatcherDelegate delegate, void *context, short events) +{ + pthread_mutex_lock (&instance->fdListMutex); + + hshFvoid_int_add (instance->fdList, fd, + fd_watcher_entry_new (fd, delegate, context, events)); + + /* + * if the size is 1, that means it was at 0 before we added ourselves, + * which means we should notify the watcher. + */ + if (hshFvoid_size (instance->fdList) == 1) + { + pthread_cond_signal (&instance->fdListCond); + } + + pthread_mutex_unlock (&instance->fdListMutex); +} diff --git a/mk4/mobility-client/modcgi/src/fd_watcher_entry.c b/mk4/mobility-client/modcgi/src/fd_watcher_entry.c new file mode 100644 index 0000000..6a2f25b --- /dev/null +++ b/mk4/mobility-client/modcgi/src/fd_watcher_entry.c @@ -0,0 +1,77 @@ + +#include +#include + +#include "fd_watcher_entry.h" +#include "threadpool.h" + +struct s_FDWatcherEntry +{ + int fd; + + short events; + short revents; + + FDWatcherDelegate function; + + void *context; +}; + +FDWatcherEntry * +fd_watcher_entry_new (int fd, FDWatcherDelegate function, void *context, short events) +{ + FDWatcherEntry *instance = (FDWatcherEntry *) malloc (sizeof (FDWatcherEntry)); + + instance->fd = fd; + instance->function = function; + instance->context = context; + instance->events = events; + + return (instance); +} + +void +fd_watcher_entry_destroy (void *ptr) +{ + FDWatcherEntry *instance = (FDWatcherEntry *) ptr; + + free (instance); +} + +int +fd_watcher_entry_getFD (FDWatcherEntry *instance) +{ + return (instance->fd); +} + +short +fd_watcher_entry_getEvents (FDWatcherEntry *instance) +{ + return (instance->events); +} + +void +fd_watcher_entry_addEvent (FDWatcherEntry *instance, short event) +{ + instance->events |= event; +} + +static void +fd_watcher_entry_internalInvoke (void *context) +{ + FDWatcherEntry *instance = context; + + instance->function (instance->context, instance->fd, instance->revents); + + fd_watcher_entry_destroy (instance); +} + +void +fd_watcher_entry_invoke (FDWatcherEntry *instance, short events) +{ + instance->revents = events; + + threadpool_queueUserWorkItem (threadpool_getInstance(), + fd_watcher_entry_internalInvoke, instance); +} + diff --git a/mk4/mobility-client/modcgi/src/modcgi.c b/mk4/mobility-client/modcgi/src/modcgi.c new file mode 100644 index 0000000..503511b --- /dev/null +++ b/mk4/mobility-client/modcgi/src/modcgi.c @@ -0,0 +1,36 @@ +#include +#include + +#include +#include + +#include "type.h" + +#include "remote_process.h" +#include "http_request_list.h" + +#include "cgi_request.h" + +#include "client.h" + +int main (int argc, char **argv) +{ + if (argc < 2) + { + printf ("usage: %s \n", argv[0]); + return (2); + } + + signal (SIGPIPE, SIG_IGN); + + client_init (atoi (argv[1])); + + http_request_list_setHandler (http_request_list_getRequestList(), + cgi_request_handler, NULL); + + while (TRUE) + { + thrFsleep (60 * 1000); + } +} + diff --git a/mk4/mobility-client/modcgi/src/process_watcher.c b/mk4/mobility-client/modcgi/src/process_watcher.c new file mode 100644 index 0000000..7c353fd --- /dev/null +++ b/mk4/mobility-client/modcgi/src/process_watcher.c @@ -0,0 +1,253 @@ +#define _GNU_SOURCE +#include + +#include +#include +#include +#include +#include +#include + + +#include "process_watcher.h" +#include "process_watcher_entry.h" + +#include "mecha.h" + +static ProcessWatcher *g_instance = NULL; +static pthread_once_t g_instanceOnce = PTHREAD_ONCE_INIT; + +static void * process_watcher_watchChildren (void *context); +static void process_watcher_setupInstance (void); + +static void process_watcher_sigchildHandler (int signum, siginfo_t *siginfo, __attribute__ ((unused)) void *data); + +static void process_watcher_setupPipes (ProcessWatcher *instance); +static void process_watcher_installHandlers (void); + +struct s_ProcessWatcher +{ + hshTvoid_list *children; + pthread_mutex_t childrenMutex; + pthread_t watcherThread; + + int readFD; + int writeFD; +}; + +ProcessWatcher * +process_watcher_new (void) +{ + ProcessWatcher *instance = (ProcessWatcher *) malloc (sizeof (ProcessWatcher)); + + instance->children = hshFvoid_int_init (process_watcher_entry_destroy); + + pthread_mutex_init (&instance->childrenMutex, NULL); + + process_watcher_setupPipes (instance); + + pthread_create (&instance->watcherThread, NULL, process_watcher_watchChildren, instance); + + process_watcher_installHandlers(); + + return (instance); +} + +void +process_watcher_destroy (void *ptr) +{ + ProcessWatcher *instance = (ProcessWatcher *) ptr; + + pthread_cancel (instance->watcherThread); + pthread_join (instance->watcherThread, NULL); + + close (instance->readFD); + close (instance->writeFD); + + pthread_mutex_destroy (&instance->childrenMutex); + + hshFvoid_destroy (instance->children); + + free (instance); +} + +static void +process_watcher_setupInstance() +{ + g_instance = process_watcher_new(); +} + +ProcessWatcher * +process_watcher_getInstance() +{ + pthread_once (&g_instanceOnce, process_watcher_setupInstance); + + return (g_instance); +} + +void +process_watcher_removeWatchPid (ProcessWatcher *instance, int pid) +{ + pthread_mutex_lock (&instance->childrenMutex); + + hshFvoid_int_del (instance->children, pid); + + pthread_mutex_unlock (&instance->childrenMutex); +} + +void +process_watcher_watchPid (ProcessWatcher *instance, int pid, + ProcessWatcherDelegate delegate, void *context) +{ + pthread_mutex_lock (&instance->childrenMutex); + + hshFvoid_int_add (instance->children, pid, + process_watcher_entry_new (pid, delegate, context)); + + pthread_mutex_unlock (&instance->childrenMutex); +} + +static void +process_watcher_installHandlers() +{ +#if 0 + signal (SIGHUP, process_watcher_sigchildHandler); + signal (SIGINT, process_watcher_sigchildHandler); + signal (SIGQUIT, process_watcher_sigchildHandler); +#endif + + /* + * It seems that with linux 2.4, you won't get called unless you use + * SA_SIGINFO. + * + * -eric@5stops.com 1.18.2004 + */ + { + struct sigaction action; + + action.sa_handler = NULL; + action.sa_sigaction = process_watcher_sigchildHandler; + action.sa_flags = SA_NOCLDSTOP | SA_RESTART | SA_SIGINFO | SA_NODEFER; + action.sa_restorer = NULL; + + sigemptyset (&action.sa_mask); + + if (sigaction (SIGCHLD, &action, NULL) != 0) + { + logFmsg (CONT_LOG_ERROR, "Could not install signal handler for SIGCHLD: %s", + strerror (errno)); + + return; + } + } +} + +static void +process_watcher_setupPipes (ProcessWatcher *instance) +{ + int fdpipes[2]; + + if (pipe (fdpipes) != 0) + { + perror ("pipe"); + } + + instance->readFD = fdpipes[0]; + instance->writeFD = fdpipes[1]; +} + + +struct process_watcher_data +{ + int status; + pid_t pid; +}; + +static void +process_watcher_sigchildHandler (int signum, __attribute__ ((unused)) siginfo_t *siginfo, __attribute__ ((unused)) void *extraData) +{ + struct process_watcher_data data; + + if (signum != SIGCHLD) + { + logFmsg (CONT_LOG_DEBUG, "modcgi/process_watcher: Received signal %d. Exiting.", signum); + + exit (0); + } + + while (TRUE) + { + data.pid = waitpid (0, &data.status, WNOHANG); + + if (data.pid == 0 || (data.pid == -1 && errno == ECHILD)) + { + /* we apparently don't have any more children to wait on */ + + return; + } + + if (data.pid == -1) + { + logFmsg (CONT_LOG_DEBUG, "modcgi/process_watcher: wait: %d: %s", errno, strerror (errno)); + + return; + } + +#if PROCESS_DEBUGGING + logFmsg (CONT_LOG_DEBUG, "modcgi/process_watcher: reaped process %d.", data.pid); +#endif + + /* + * BUGBUG: This really shouldn't be using g_instance directly, but we + * can't use mutexes in here (which process_watcher_getInstance() does). + */ + if (write (g_instance->writeFD, &data, sizeof (data)) != sizeof (data)) + { + logFmsg (CONT_LOG_ERROR, "modcgi/process_watcher: Could not write to fd: %s", strerror (errno)); + + return; + } + } +} + + +/* + * Because sigwait() seems to not work properly for SIGCHLD on linux 2.4, we + * are resorting to using a signal handler write the required information to a + * pipe + * + * -eric@5stops.com 1.18.2004 + */ +static void * +process_watcher_watchChildren (void *context) +{ + ProcessWatcher *instance = context; + + while (TRUE) + { + ProcessWatcherEntry *entry; + struct process_watcher_data data; + + if (read (instance->readFD, &data, sizeof (data)) != sizeof (data)) + { + logFmsg (CONT_LOG_ERROR, "modcgi/process_watcher: Could not read from fd: %s", strerror (errno)); + + return (NULL); + } + + pthread_mutex_lock (&instance->childrenMutex); + + entry = hshFvoid_int_remove (instance->children, data.pid); + + if (entry != NULL) + { + process_watcher_entry_invoke (entry, data.status); + } + + pthread_mutex_unlock (&instance->childrenMutex); + } + + return (NULL); +} + + diff --git a/mk4/mobility-client/modcgi/src/process_watcher_entry.c b/mk4/mobility-client/modcgi/src/process_watcher_entry.c new file mode 100644 index 0000000..b429b00 --- /dev/null +++ b/mk4/mobility-client/modcgi/src/process_watcher_entry.c @@ -0,0 +1,58 @@ + +#include +#include + +#include "process_watcher_entry.h" +#include "threadpool.h" + +struct s_ProcessWatcherEntry +{ + int pid; + ProcessWatcherDelegate delegate; + void *context; + int status; +}; + +ProcessWatcherEntry * +process_watcher_entry_new (int pid, ProcessWatcherDelegate delegate, void *context) +{ + ProcessWatcherEntry *instance = (ProcessWatcherEntry *) malloc (sizeof (ProcessWatcherEntry)); + + instance->pid = pid; + instance->delegate = delegate; + instance->context = context; + instance->status = 0; + + return (instance); +} + +void +process_watcher_entry_destroy (void *ptr) +{ + ProcessWatcherEntry *instance = (ProcessWatcherEntry *) ptr; + + free (instance); +} + +static void +process_watcher_entry_internalInvoke (void *context) +{ + ProcessWatcherEntry *instance = (ProcessWatcherEntry *) context; + + instance->delegate (instance->context, instance->status); + + process_watcher_entry_destroy (instance); +} + +void +process_watcher_entry_invoke (ProcessWatcherEntry *instance, + int status) +{ + instance->status = status; + + /* + threadpool_queueUserWorkItem (threadpool_getInstance(), + process_watcher_entry_internalInvoke, instance); + */ + process_watcher_entry_internalInvoke (instance); +} diff --git a/mk4/mobility-client/modcgi/src/remote_process.c b/mk4/mobility-client/modcgi/src/remote_process.c new file mode 100644 index 0000000..b55f614 --- /dev/null +++ b/mk4/mobility-client/modcgi/src/remote_process.c @@ -0,0 +1,491 @@ + +#include +#include +#include +#include +#include + +#include "type.h" + +#include "remote_process.h" +#include "string_collection.h" + +#include "process_watcher.h" + +static void remote_process_closeFDs (RemoteProcess *instance); + +struct s_RemoteProcess +{ + int pid; + + char *executable; + + StringCollection *arguments; + + StringCollection *environment; + + int stdin; + int stdout; + int stderr; + + bool exited; + int exitCode; + + pthread_mutex_t processMutex; +}; + +RemoteProcess * +remote_process_new (const char *executable) +{ + RemoteProcess *instance = (RemoteProcess *) malloc (sizeof (RemoteProcess)); + + /* make sure the executable is not NULL */ + assert (executable != NULL); + /* make sure the executable is not an empty string */ + assert (*executable != 0); + + instance->executable = strdup (executable); + + instance->pid = -1; + instance->stdin = -1; + instance->stdout = -1; + instance->stderr = -1; + + instance->exitCode = 0; + instance->exited = FALSE; + + instance->arguments = string_collection_new(); + + instance->environment = string_collection_new(); + + string_collection_addString (instance->arguments, instance->executable); + + pthread_mutex_init (&instance->processMutex, NULL); + + return (instance); +} + +void +remote_process_destroy (void *ptr) +{ + RemoteProcess *instance = (RemoteProcess *) ptr; + + process_watcher_removeWatchPid (process_watcher_getInstance(), + instance->pid); + + pthread_mutex_lock (&instance->processMutex); + + string_collection_destroy (instance->arguments); + string_collection_destroy (instance->environment); + + if (instance->exited == FALSE) + { + kill (instance->pid, SIGKILL); + } + + remote_process_closeFDs (instance); + + pthread_mutex_unlock (&instance->processMutex); + + pthread_mutex_destroy (&instance->processMutex); + + free (instance->executable); + + free (instance); +} + +static void +remote_process_closeFDs (RemoteProcess *instance) +{ + if (instance->stdin != -1) + { + close (instance->stdin); + + instance->stdin = -1; + } + + if (instance->stdout != -1) + { + close (instance->stdout); + + instance->stdout = -1; + } + + if (instance->stderr != -1) + { + close (instance->stderr); + + instance->stderr = -1; + } +} + +const char * +remote_process_get_executable (RemoteProcess *instance) +{ + return (instance->executable); +} + +void +remote_process_addEnvironment (RemoteProcess *instance, const char *variable) +{ + pthread_mutex_lock (&instance->processMutex); + + string_collection_addString (instance->environment, variable); + + pthread_mutex_unlock (&instance->processMutex); +} + +void +remote_process_addEnvironmentData (RemoteProcess *instance, const char *variable, int len) +{ + pthread_mutex_lock (&instance->processMutex); + + string_collection_addData (instance->environment, variable, len); + + pthread_mutex_unlock (&instance->processMutex); +} + +void +remote_process_addArgument (RemoteProcess *instance, const char *argument) +{ + pthread_mutex_lock (&instance->processMutex); + + string_collection_addString (instance->arguments, argument); + + pthread_mutex_unlock (&instance->processMutex); +} + +int +remote_process_getStdIn (RemoteProcess *instance) +{ + int fd; + + pthread_mutex_lock (&instance->processMutex); + + fd = instance->stdin; + + pthread_mutex_unlock (&instance->processMutex); + + return (fd); +} + +int +remote_process_getStdOut (RemoteProcess *instance) +{ + int fd; + + pthread_mutex_lock (&instance->processMutex); + + fd = instance->stdout; + + pthread_mutex_unlock (&instance->processMutex); + + return (fd); +} + +bool +remote_process_closeStdOut (RemoteProcess *instance) +{ + bool ret; + + pthread_mutex_lock (&instance->processMutex); + + if (instance->stdout != -1) + { + close (instance->stdout); + + instance->stdout = -1; + + ret = TRUE; + } + else + { + ret = FALSE; + } + + pthread_mutex_unlock (&instance->processMutex); + + return (ret); +} + +bool +remote_process_closeStdIn (RemoteProcess *instance) +{ + bool ret; + + pthread_mutex_lock (&instance->processMutex); + + if (instance->stdin != -1) + { + close (instance->stdin); + + instance->stdin = -1; + + ret = TRUE; + } + else + { + ret = FALSE; + } + + pthread_mutex_unlock (&instance->processMutex); + + return (ret); +} + +int +remote_process_getStdErr (RemoteProcess *instance) +{ + int fd; + + pthread_mutex_lock (&instance->processMutex); + + fd = instance->stderr; + + pthread_mutex_unlock (&instance->processMutex); + + return (fd); +} + +static void +remote_process_cleanupProcess (void *context, int status) +{ + RemoteProcess *instance = (RemoteProcess *) context; + + pthread_mutex_lock (&instance->processMutex); + + instance->exited = TRUE; + + if (WIFEXITED (status)) + { + instance->exitCode = WEXITSTATUS (status); + } + + pthread_mutex_unlock (&instance->processMutex); +} + +bool +remote_process_start (RemoteProcess *instance) +{ + int stdin_pipe[2]; + int stdout_pipe[2]; + int stderr_pipe[2]; + int pid; + struct stat statb; + + pthread_mutex_lock (&instance->processMutex); + + if (stat (instance->executable, &statb) == -1) + { + perror ("stat"); + + pthread_mutex_unlock (&instance->processMutex); + + return (FALSE); + } + + if (pipe (stdin_pipe) != 0) + { + perror ("pipe"); + + pthread_mutex_unlock (&instance->processMutex); + return (FALSE); + } + + if (pipe (stdout_pipe) != 0) + { + perror ("pipe"); + + close (stdin_pipe[0]); + close (stdin_pipe[1]); + + pthread_mutex_unlock (&instance->processMutex); + + return (FALSE); + } + + if (pipe (stderr_pipe) != 0) + { + perror ("pipe"); + + close (stdin_pipe[0]); + close (stdin_pipe[1]); + close (stdout_pipe[0]); + close (stdout_pipe[1]); + + pthread_mutex_unlock (&instance->processMutex); + + return (FALSE); + } + + if ((pid = fork()) == -1) + { + /* we couldn't fork */ + perror ("fork"); + + close (stdin_pipe[0]); + close (stdin_pipe[1]); + close (stdout_pipe[0]); + close (stdout_pipe[1]); + close (stderr_pipe[0]); + close (stderr_pipe[1]); + + pthread_mutex_unlock (&instance->processMutex); + + return (FALSE); + } + + if (pid == 0) + { + /* + * HACK: syncronize with the calling process by reading a single char + * from stdin + */ + { + char buf; + + if (read (stdin_pipe[0], &buf, 1) != 1) + { + perror ("read"); + } + } + + char *dir = strFcopy (instance->executable); + + char *lastSlash = rindex (dir, '/'); + + if (lastSlash != NULL) + { + *lastSlash = 0; + + chdir (dir); + } + else + { + logFmsg (CONT_LOG_WARN, "Could not change directory for: %s", instance->executable); + } + + /* close the write side of the stdin fd */ + close (stdin_pipe[1]); + + /* close the read side of stdout fd */ + close (stdout_pipe[0]); + + /* close the read side of stderr fd */ + close (stderr_pipe[0]); + + /* set our stdin pipe to STDIN */ + if (dup2 (stdin_pipe[0], STDIN_FILENO) == -1) + { + perror ("dup2"); + return (errno); + } + + /* close the "higher" fd num */ + close (stdin_pipe[0]); + + /* set our stdout pipe to STDOUT */ + if (dup2 (stdout_pipe[1], STDOUT_FILENO) == -1) + { + perror ("dup2"); + return (errno); + } + + /* close the "higher" fd num */ + close (stdout_pipe[1]); + + /* set our stderr pipe to STDERR */ + if (dup2 (stderr_pipe[1], STDERR_FILENO) == -1) + { + perror ("dup2"); + return (errno); + } + + /* close the "higher" fd num */ + close (stderr_pipe[1]); + + if (getuid() == 0) + { + if (setregid (statb.st_gid, statb.st_gid) != 0) + { + int e = errno; + + perror ("setregid"); + + return (e); + } + + if (setreuid (statb.st_uid, statb.st_uid) != 0) + { + int e = errno; + + perror ("setreuid"); + + return (e); + } + } + + execve (instance->executable, + string_collection_getInternal (instance->arguments), + string_collection_getInternal (instance->environment)); + + /* we should never reach this */ + + perror (instance->executable); + + return (errno); + } + else + { + instance->pid = pid; + + process_watcher_watchPid (process_watcher_getInstance(), + instance->pid, remote_process_cleanupProcess, instance); + + /* close the read side of the stdin fd */ + close (stdin_pipe[0]); + + /* save the write side of the stdin fd */ + instance->stdin = stdin_pipe[1]; + + /* mark this fd to be closed if we fork again */ + fleFset_close_exec (instance->stdin); + + /* close the write side of stdout fd */ + close (stdout_pipe[1]); + + /* save the read side of the stdout fd */ + instance->stdout = stdout_pipe[0]; + + /* mark this fd to be closed if we fork again */ + fleFset_close_exec (instance->stdout); + + /* close the write side of stderr fd */ + close (stderr_pipe[1]); + + /* save the read side of the stderr fd */ + instance->stderr = stderr_pipe[0]; + + /* mark this fd to be closed if we fork again */ + fleFset_close_exec (instance->stderr); + + /* + * HACK: syncronize with the child process by writing a single char + * to stdin -- the child should block until this is written + */ + { + char buf = '1'; + + if (write (instance->stdin, &buf, 1) != 1) + { + perror ("write"); + + return (FALSE); + } + } + + pthread_mutex_unlock (&instance->processMutex); + + return (TRUE); + } +} diff --git a/mk4/mobility-client/modcgi/src/string_collection.c b/mk4/mobility-client/modcgi/src/string_collection.c new file mode 100644 index 0000000..a467897 --- /dev/null +++ b/mk4/mobility-client/modcgi/src/string_collection.c @@ -0,0 +1,108 @@ + +#include +#include +#include + +#include + +#include "string_collection.h" + +struct s_StringCollection +{ + int numStrings; + char **strings; +}; + +static void string_collection_growArray (StringCollection *instance, int newLength); + + +StringCollection * +string_collection_new (void) +{ + StringCollection *instance = (StringCollection *) malloc (sizeof (StringCollection)); + + instance->numStrings = 0; + instance->strings = NULL; + + /* + * this will allocate the initial array + * + * from execvp man page: + * The array of pointers _must_ be terminated by a NULL pointer. + */ + string_collection_growArray (instance, 0); + + return (instance); +} + +void +string_collection_destroy (void *ptr) +{ + StringCollection *instance = (StringCollection *) ptr; + + if (instance->numStrings > 0) + { + int i; + + for (i = 0; i < instance->numStrings; i++) + { + free (instance->strings[i]); + } + } + + free (instance->strings); + + free (instance); +} + +static void +string_collection_growArray (StringCollection *instance, int newLength) +{ + int i; + + assert (newLength >= 0); + assert (newLength >= instance->numStrings); + + instance->strings = realloc (instance->strings, sizeof (char *) * (newLength + 1)); + + /* set each new entry to NULL */ + for (i = instance->numStrings; i <= newLength; i++) + { + instance->strings[i] = NULL; + } +} + +void +string_collection_addString (StringCollection *instance, const char *string) +{ + assert (string != NULL); + + string_collection_addData (instance, string, strlen (string)); +} + +void +string_collection_addData (StringCollection *instance, const char *string, int len) +{ + assert (string != NULL); + assert (len > 0); + + /* allocate one for the added entry */ + string_collection_growArray (instance, instance->numStrings + 1); + + /* allocate an extra one for the NULL */ + instance->strings[instance->numStrings] = malloc (sizeof (char) * (len + 1)); + + /* add the NULL to the end of the string */ + instance->strings[instance->numStrings][len] = 0; + + /* copy the string to the array */ + memcpy (instance->strings[instance->numStrings], string, len); + + instance->numStrings++; +} + +char ** +string_collection_getInternal (StringCollection *instance) +{ + return (instance->strings); +} diff --git a/mk4/mobility-client/modmono/.cvsignore b/mk4/mobility-client/modmono/.cvsignore new file mode 100644 index 0000000..b6b8dcd --- /dev/null +++ b/mk4/mobility-client/modmono/.cvsignore @@ -0,0 +1,7 @@ +poke_ltmono.sh +poke_mono.sh +.svn +.dep +w3wp-profile.sh +w3wp-mint.sh +w3wp.sh diff --git a/mk4/mobility-client/modmono/CVS/Entries b/mk4/mobility-client/modmono/CVS/Entries new file mode 100644 index 0000000..60a0316 --- /dev/null +++ b/mk4/mobility-client/modmono/CVS/Entries @@ -0,0 +1,3 @@ +/.cvsignore/1.1/Thu May 13 21:52:15 2004//Tmk4_mod6_rc2 +/Makefile/1.2/Fri May 14 16:51:25 2004//Tmk4_mod6_rc2 +D/src//// diff --git a/mk4/mobility-client/modmono/CVS/Repository b/mk4/mobility-client/modmono/CVS/Repository new file mode 100644 index 0000000..3959b89 --- /dev/null +++ b/mk4/mobility-client/modmono/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/mobility-client/modmono diff --git a/mk4/mobility-client/modmono/CVS/Root b/mk4/mobility-client/modmono/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/mobility-client/modmono/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/mobility-client/modmono/CVS/Tag b/mk4/mobility-client/modmono/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/mobility-client/modmono/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/mobility-client/modmono/Makefile b/mk4/mobility-client/modmono/Makefile new file mode 100644 index 0000000..d9b7905 --- /dev/null +++ b/mk4/mobility-client/modmono/Makefile @@ -0,0 +1,45 @@ +# $Id: Makefile,v 1.2 2004/05/14 16:51:25 eric Exp $ + +CONTINUITY = ../../continuity + +MCS_LOCATION := $(shell which mcs 2>&1) + +ifeq (,$(findstring no mcs in,$(MCS_LOCATION))) + +include $(CONTINUITY)/lib/env.mk + +PROJECT = modmono + +MANAGED_BINARY = $(PROJECT).exe + +MANAGED_SRC = src/CausalityClient.cs src/OxideApplicationHost.cs \ + src/OxideMain.cs src/OxideWorkerRequest.cs \ + src/CausalityRequest.cs src/CThreadPool.cs \ + src/OxideApplicationPool.cs + +CSC = mcs +CS_FLAGS = -debug -g -r:System.Web -target:exe + + +.PHONY: clean distclean buildtar count buildcount all depend + +all: $(MANAGED_BINARY) + + +$(MANAGED_BINARY): $(MANAGED_SRC) + $(CSC) $(CS_FLAGS) -out:$(MANAGED_BINARY) $(MANAGED_SRC) + +clean: + -rm -f src/*.o src/*~ include/*~ *~ core $(MANAGED_BINARY) + +distclean: + -rm -f src/*.o src/*~ include/*~ core $(BINARY) .dep + +else +# +# we don't have mcs installed +# +all: +$(warning Could not find mcs in path. Skipping build of mod/mono.) + +endif diff --git a/mk4/mobility-client/modmono/src/.cvsignore b/mk4/mobility-client/modmono/src/.cvsignore new file mode 100644 index 0000000..90ec22b --- /dev/null +++ b/mk4/mobility-client/modmono/src/.cvsignore @@ -0,0 +1 @@ +.svn diff --git a/mk4/mobility-client/modmono/src/CThreadPool.cs b/mk4/mobility-client/modmono/src/CThreadPool.cs new file mode 100644 index 0000000..27d9122 --- /dev/null +++ b/mk4/mobility-client/modmono/src/CThreadPool.cs @@ -0,0 +1,296 @@ +// +// System.Threading.ThreadPool +// +// Author: +// Patrik Torstensson +// Dick Porter (dick@ximian.com) +// +// (C) Ximian, Inc. http://www.ximian.com +// (C) Patrik Torstensson +// +using System; +using System.Collections; +using System.Threading; + +namespace Fivestops.Oxide { + /// (Patrik T notes) + /// This threadpool is focused on saving resources not giving max performance. + /// + /// Note, this class is not perfect but it works. ;-) Should also replace + /// the queue with an internal one (performance) + /// + /// This class should also use a specialized queue to increase performance.. + /// + /// + public sealed class CThreadPool { + internal struct ThreadPoolWorkItem { + public WaitCallback _CallBack; + public object _Context; + } + + private int _ThreadTimeout; + + private long _MaxThreads; + private long _CurrentThreads; + private long _ThreadsInUse; + private long _RequestInQueue; + private long _ThreadCreateTriggerRequests; + + // private Thread _MonitorThread; + private Queue _RequestQueue; + + private ArrayList _Threads; + private ManualResetEvent _DataInQueue; + + static CThreadPool _Threadpool; + + static CThreadPool() { + _Threadpool = new CThreadPool(); + } + + private CThreadPool() { + // 30 sec timeout default + _ThreadTimeout = 30 * 1000; + + // Used to signal that there is data in the queue + _DataInQueue = new ManualResetEvent(false); + + _Threads = ArrayList.Synchronized(new ArrayList()); + + // Holds requests.. + _RequestQueue = new Queue(128); + // _RequestQueue = Queue.Synchronized(new Queue(128)); + + // TODO: This should be 2 x number of CPU:s in the box + _MaxThreads = 16; + _CurrentThreads = 0; + _RequestInQueue = 0; + _ThreadsInUse = 0; + _ThreadCreateTriggerRequests = 5; + + // TODO: This temp starts one thread, remove this.. + CheckIfStartThread(); + + // Keeps track of requests in the queue and increases the number of threads if needed + + // PT: Disabled - causes problems during shutdown + //_MonitorThread = new Thread(new ThreadStart(MonitorThread)); + //_MonitorThread.Start(); + } + + internal void RemoveThread() { + Interlocked.Decrement(ref _CurrentThreads); + _Threads.Remove(Thread.CurrentThread); + } + + internal void CheckIfStartThread() { + bool bCreateThread = false; + + if (_CurrentThreads == 0) { + bCreateThread = true; + } + + if (( _MaxThreads == -1 || _CurrentThreads < _MaxThreads) && + _ThreadsInUse > 0 && + _RequestInQueue >= _ThreadCreateTriggerRequests) { + bCreateThread = true; + } + + if (bCreateThread) { + Interlocked.Increment(ref _CurrentThreads); + + Thread Start = new Thread(new ThreadStart(WorkerThread)); + Start.IsBackground = true; + Start.Start(); + + _Threads.Add(Start); + } + } + + internal void AddItem(ref ThreadPoolWorkItem Item) { + lock (_RequestQueue) + { + _RequestQueue.Enqueue(Item); + + Interlocked.Increment(ref _RequestInQueue); + + _DataInQueue.Set(); + } + } + + // Work Thread main function + internal void WorkerThread() + { + while (true) { + if (!_DataInQueue.WaitOne(_ThreadTimeout, false)) { + // Keep one thread running + if (_CurrentThreads > 1) { + // timeout + RemoveThread(); + return; + } + continue; + } + + Interlocked.Increment(ref _ThreadsInUse); + + // TODO: Remove when we know how to stop the watch thread + CheckIfStartThread(); + + try + { + ThreadPoolWorkItem oItem; + + lock (_RequestQueue) + { + if (_RequestQueue.Count < 1) + { + _DataInQueue.Reset(); + continue; + } + + oItem = (ThreadPoolWorkItem) _RequestQueue.Dequeue(); + } + + Interlocked.Decrement(ref _RequestInQueue); + + oItem._CallBack(oItem._Context); + } + catch (InvalidOperationException) { + // Queue empty + } + catch (ThreadAbortException) { + // We will leave here.. (thread abort can't be handled) + RemoveThread(); + } + finally { + Interlocked.Decrement(ref _ThreadsInUse); + } + } + } + + /* This is currently not in use + + internal void MonitorThread() { + while (true) { + if (_DataInQueue.WaitOne ()) { + CheckIfStartThread(); + } + + Thread.Sleep(500); + } + } + + */ + internal bool QueueUserWorkItemInternal(WaitCallback callback) { + return QueueUserWorkItem(callback, null); + } + + internal bool QueueUserWorkItemInternal(WaitCallback callback, object context) { + ThreadPoolWorkItem Item = new ThreadPoolWorkItem(); + + Item._CallBack = callback; + Item._Context = context; + + AddItem(ref Item); + + // LAMESPEC: Return value? should use exception here if anything goes wrong + return true; + } + + public static bool BindHandle(IntPtr osHandle) { + throw new NotSupportedException("This is a win32 specific method, not supported Mono"); + } + + public static bool QueueUserWorkItem(WaitCallback callback) { + return _Threadpool.QueueUserWorkItemInternal(callback); + } + + public static bool QueueUserWorkItem(WaitCallback callback, object state) { + return _Threadpool.QueueUserWorkItemInternal(callback, state); + } + + public static bool UnsafeQueueUserWorkItem(WaitCallback callback, object state) { + return _Threadpool.QueueUserWorkItemInternal(callback, state); + } + + static TimeSpan GetTSFromMS (long ms) + { + if (ms < -1) + throw new ArgumentOutOfRangeException ("millisecondsTimeOutInterval", "timeout < -1"); + + return new TimeSpan (0, 0, 0, 0, (int) ms); + } + +#if NEEDED + public static RegisteredWaitHandle RegisterWaitForSingleObject (WaitHandle waitObject, + WaitOrTimerCallback callback, + object state, + int millisecondsTimeOutInterval, + bool executeOnlyOnce) + { + TimeSpan ts = GetTSFromMS ((long) millisecondsTimeOutInterval); + return RegisterWaitForSingleObject (waitObject, callback, state, ts, executeOnlyOnce); + } + + public static RegisteredWaitHandle RegisterWaitForSingleObject (WaitHandle waitObject, + WaitOrTimerCallback callback, + object state, + long millisecondsTimeOutInterval, + bool executeOnlyOnce) + { + TimeSpan ts = GetTSFromMS (millisecondsTimeOutInterval); + return RegisterWaitForSingleObject (waitObject, callback, state, ts, executeOnlyOnce); + } + + public static RegisteredWaitHandle RegisterWaitForSingleObject (WaitHandle waitObject, + WaitOrTimerCallback callback, + object state, + TimeSpan timeout, + bool executeOnlyOnce) + { + long ms = (long) timeout.TotalMilliseconds; + if (ms < -1) + throw new ArgumentOutOfRangeException ("timeout", "timeout < -1"); + + if (ms > Int32.MaxValue) + throw new NotSupportedException ("Timeout is too big. Maximum is Int32.MaxValue"); + + RegisteredWaitHandle waiter = new RegisteredWaitHandle (waitObject, callback, state, timeout, executeOnlyOnce); + _Threadpool.QueueUserWorkItemInternal (new WaitCallback (waiter.Wait), null); + return waiter; + } + + [CLSCompliant(false)] + public static RegisteredWaitHandle RegisterWaitForSingleObject (WaitHandle waitObject, + WaitOrTimerCallback callback, + object state, + uint millisecondsTimeOutInterval, + bool executeOnlyOnce) + { + TimeSpan ts = GetTSFromMS ((long) millisecondsTimeOutInterval); + return RegisterWaitForSingleObject (waitObject, callback, state, ts, executeOnlyOnce); + } + + [MonoTODO] + public static RegisteredWaitHandle UnsafeRegisterWaitForSingleObject(WaitHandle waitObject, WaitOrTimerCallback callback, object state, int millisecondsTimeOutInterval, bool executeOnlyOnce) { + throw new NotImplementedException(); + } + + [MonoTODO] + public static RegisteredWaitHandle UnsafeRegisterWaitForSingleObject(WaitHandle waitObject, WaitOrTimerCallback callback, object state, long millisecondsTimeOutInterval, bool executeOnlyOnce) { + throw new NotImplementedException(); + } + + [MonoTODO] + public static RegisteredWaitHandle UnsafeRegisterWaitForSingleObject(WaitHandle waitObject, WaitOrTimerCallback callback, object state, TimeSpan timeout, bool executeOnlyOnce) { + throw new NotImplementedException(); + } + + [CLSCompliant(false)][MonoTODO] + public static RegisteredWaitHandle UnsafeRegisterWaitForSingleObject(WaitHandle waitObject, WaitOrTimerCallback callback, object state, uint millisecondsTimeOutInterval, bool executeOnlyOnce) { + throw new NotImplementedException(); + } +#endif + } +} diff --git a/mk4/mobility-client/modmono/src/CVS/Entries b/mk4/mobility-client/modmono/src/CVS/Entries new file mode 100644 index 0000000..67a73e1 --- /dev/null +++ b/mk4/mobility-client/modmono/src/CVS/Entries @@ -0,0 +1,10 @@ +/.cvsignore/1.1/Thu May 13 21:52:15 2004//Tmk4_mod6_rc2 +/CThreadPool.cs/1.1/Thu May 13 21:48:08 2004//Tmk4_mod6_rc2 +/CausalityClient.cs/1.1/Thu May 13 21:48:08 2004//Tmk4_mod6_rc2 +/CausalityRequest.cs/1.1/Thu May 13 21:48:08 2004//Tmk4_mod6_rc2 +/OxideApplicationHost.cs/1.1/Thu May 13 21:48:08 2004//Tmk4_mod6_rc2 +/OxideApplicationPool.cs/1.1/Thu May 13 21:48:08 2004//Tmk4_mod6_rc2 +/OxideMain.cs/1.1/Thu May 13 21:48:08 2004//Tmk4_mod6_rc2 +/OxideThreadPool.cs/1.1/Thu May 13 21:48:08 2004//Tmk4_mod6_rc2 +/OxideWorkerRequest.cs/1.1/Thu May 13 21:48:08 2004//Tmk4_mod6_rc2 +D diff --git a/mk4/mobility-client/modmono/src/CVS/Repository b/mk4/mobility-client/modmono/src/CVS/Repository new file mode 100644 index 0000000..d9fecd0 --- /dev/null +++ b/mk4/mobility-client/modmono/src/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/mobility-client/modmono/src diff --git a/mk4/mobility-client/modmono/src/CVS/Root b/mk4/mobility-client/modmono/src/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/mobility-client/modmono/src/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/mobility-client/modmono/src/CVS/Tag b/mk4/mobility-client/modmono/src/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/mobility-client/modmono/src/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/mobility-client/modmono/src/CausalityClient.cs b/mk4/mobility-client/modmono/src/CausalityClient.cs new file mode 100644 index 0000000..8a78cd9 --- /dev/null +++ b/mk4/mobility-client/modmono/src/CausalityClient.cs @@ -0,0 +1,59 @@ +using System; +using System.Runtime.InteropServices; + +namespace Fivestops.Oxide +{ + public class CausalityClient + { + const string LIBRARY_LOCATION = "/home/eric/src/depot/src/main/causality-client/"; + + // [DllImport (LIBRARY_LOCATION + "libcausality-client.so", CallingConvention=CallingConvention.Cdecl, EntryPoint="client_init")] + [DllImport (LIBRARY_LOCATION + "libcausality-client.so", CallingConvention=CallingConvention.StdCall, CharSet=CharSet.Ansi, EntryPoint="client_init")] + public static extern void Init (int key); + + [DllImport (LIBRARY_LOCATION + "libcausality-client.so", EntryPoint="client_get_request")] + public static extern IntPtr GetRequest(); + + [DllImport (LIBRARY_LOCATION + "libcausality-client.so", EntryPoint="client_write_string")] + public static extern bool WriteString (IntPtr request, string data); + + [DllImport (LIBRARY_LOCATION + "libcausality-client.so", EntryPoint="client_write_data")] + public static extern bool WriteData (IntPtr request, [MarshalAs(UnmanagedType.LPArray)] byte[] data, int dataLen); + + [DllImport (LIBRARY_LOCATION + "libcausality-client.so", EntryPoint="client_get_uri")] + public static extern string GetUri (IntPtr request); + + [DllImport (LIBRARY_LOCATION + "libcausality-client.so", EntryPoint="client_get_query")] + public static extern string GetQuery (IntPtr request); + + [DllImport (LIBRARY_LOCATION + "libcausality-client.so", EntryPoint="client_finish")] + public static extern bool Finish (IntPtr request); + + [DllImport (LIBRARY_LOCATION + "libcausality-client.so", EntryPoint="client_get_entity")] + public static extern int ReadEntityBody (IntPtr request, [Out] [MarshalAs(UnmanagedType.LPArray)] byte[] bufOut, int bufLen); + + [DllImport (LIBRARY_LOCATION + "libcausality-client.so", EntryPoint="client_is_entire_entity_loaded")] + public static extern bool IsEntireEntityLoaded (IntPtr request); + + [DllImport (LIBRARY_LOCATION + "libcausality-client.so", EntryPoint="client_get_method")] + public static extern string GetMethod (IntPtr request); + + [DllImport (LIBRARY_LOCATION + "libcausality-client.so", EntryPoint="client_get_request_header")] + public static extern string GetRequestHeader (IntPtr request, string key); + + [DllImport (LIBRARY_LOCATION + "libcausality-client.so", EntryPoint="client_set_response_header")] + public static extern void SetResponseHeader (IntPtr request, string key, string value); + + [DllImport (LIBRARY_LOCATION + "libcausality-client.so", EntryPoint="client_set_status")] + public static extern void SetStatus (IntPtr request, int status, string description); + + [DllImport (LIBRARY_LOCATION + "libcausality-client.so", EntryPoint="client_headers_sent")] + public static extern bool HeadersSent (IntPtr request); + + [DllImport (LIBRARY_LOCATION + "libcausality-client.so", EntryPoint="client_get_variable")] + public static extern string GetTransactionVariable (IntPtr request, string key); + + [DllImport (LIBRARY_LOCATION + "libcausality-client.so", EntryPoint="client_get_remote_ip")] + public static extern string GetRemoteIP (IntPtr request); + } +} diff --git a/mk4/mobility-client/modmono/src/CausalityRequest.cs b/mk4/mobility-client/modmono/src/CausalityRequest.cs new file mode 100644 index 0000000..266f331 --- /dev/null +++ b/mk4/mobility-client/modmono/src/CausalityRequest.cs @@ -0,0 +1,137 @@ +using System; + +namespace Fivestops.Oxide +{ + public class CausalityRequest : IDisposable + { + private IntPtr m_ipRequest; + private bool m_bDisposed = false; + + public string Page + { + get + { + return (CausalityClient.GetUri (m_ipRequest)); + } + } + + public string Query + { + get + { + return (CausalityClient.GetQuery (m_ipRequest)); + } + } + + public string Method + { + get + { + return (CausalityClient.GetMethod (m_ipRequest)); + } + } + + public CausalityRequest (IntPtr request) + { + if (request == IntPtr.Zero) + { + throw (new ArgumentNullException ("request")); + } + + m_ipRequest = request; + } + + public string GetVariable (string key) + { + return (CausalityClient.GetTransactionVariable (m_ipRequest, key)); + } + + public int ReadEntityBody (byte[] outBuf, int bufLen) + { + if (outBuf.Length != bufLen) + { + throw (new ApplicationException ( + "outBuf.Length != bufLen: " + outBuf.Length.ToString() + + " " + bufLen.ToString())); + } + + return (CausalityClient.ReadEntityBody (m_ipRequest, outBuf, bufLen)); + } + + public bool IsEntireEntityLoaded() + { + return (CausalityClient.IsEntireEntityLoaded (m_ipRequest)); + } + + public string GetRequestHeader (string key) + { + return (CausalityClient.GetRequestHeader (m_ipRequest, key)); + } + + public void SetResponseHeader (string key, string value) + { + CausalityClient.SetResponseHeader (m_ipRequest, key, value); + } + + public void SetStatus (int status, string description) + { + CausalityClient.SetStatus (m_ipRequest, status, description); + } + + public bool Write (byte[] data, int dataLen) + { + return (CausalityClient.WriteData (m_ipRequest, data, dataLen)); + } + + public bool Write (string data) + { + return (CausalityClient.WriteString (m_ipRequest, data)); + } + + public bool HeadersSent() + { + return (CausalityClient.HeadersSent (m_ipRequest)); + } + + public string GetRemoteIP() + { + return (CausalityClient.GetRemoteIP (m_ipRequest)); + } + + public void Finish() + { + this.Dispose (true); + + GC.SuppressFinalize (this); + } + + public void Dispose() + { + this.Dispose (true); + + GC.SuppressFinalize (this); + } + + private void Dispose (bool disposing) + { + if (m_bDisposed == false) + { + if (disposing) + { + // release managed components + } + + CausalityClient.Finish (m_ipRequest); + + m_ipRequest = IntPtr.Zero; + + m_bDisposed = true; + } + } + + ~CausalityRequest() + { + Dispose (false); + } + } +} diff --git a/mk4/mobility-client/modmono/src/OxideApplicationHost.cs b/mk4/mobility-client/modmono/src/OxideApplicationHost.cs new file mode 100644 index 0000000..1b9dd21 --- /dev/null +++ b/mk4/mobility-client/modmono/src/OxideApplicationHost.cs @@ -0,0 +1,61 @@ +using System; +using System.Web; +using System.IO; +using System.Web.Hosting; +using System.Threading; +using System.Runtime.Remoting.Lifetime; + + +namespace Fivestops.Oxide +{ + public class OxideApplicationHost : MarshalByRefObject + { + // tell the GC that we don't ever want to be collected. + public override object InitializeLifetimeService () + { + return (null); + } + + public string Path + { + get + { + return (AppDomain.CurrentDomain.GetData (".appPath").ToString()); + } + } + + public string VPath + { + get + { + return (AppDomain.CurrentDomain.GetData (".appVPath").ToString()); + } + } + + private void DispatchRequest (object stateObject) + { + OxideWorkerRequest owrRequest = (OxideWorkerRequest) stateObject; + + HttpRuntime.ProcessRequest (owrRequest); + } + + public void HandleRequest (IntPtr request) + { + OxideWorkerRequest owrRequest = new OxideWorkerRequest ( + new CausalityRequest (request)); + + Fivestops.Oxide.CThreadPool.QueueUserWorkItem ( + new WaitCallback (this.DispatchRequest), owrRequest); + } + + public static OxideApplicationHost CreateApplicationHost ( + string virtualdir, string basedir) + { + OxideApplicationHost o = (OxideApplicationHost) + ApplicationHost.CreateApplicationHost ( + typeof (OxideApplicationHost), virtualdir, basedir); + + return (o); + } + } +} diff --git a/mk4/mobility-client/modmono/src/OxideApplicationPool.cs b/mk4/mobility-client/modmono/src/OxideApplicationPool.cs new file mode 100644 index 0000000..5b3c469 --- /dev/null +++ b/mk4/mobility-client/modmono/src/OxideApplicationPool.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections; +using System.Runtime.Remoting; +using System.Runtime.Remoting.Lifetime; + +namespace Fivestops.Oxide +{ + class OxideApplicationPool + { + private Hashtable m_htApplications = new Hashtable(); + private ClientSponsor m_csSponsor = new ClientSponsor(); + + public void ProcessRequests() + { + while (true) + { + try + { + this.ProcessRequest (CausalityClient.GetRequest()); + } + catch (Exception e) + { + Console.WriteLine ("ex: {0}", e); + } + } + } + + private void ProcessRequest (IntPtr request) + { + OxideApplicationHost oahHost = this.GetHost ( + CausalityClient.GetTransactionVariable (request, "docroot")); + + oahHost.HandleRequest (request); + } + + private OxideApplicationHost GetHost (string docroot) + { + OxideApplicationHost oahHost = (OxideApplicationHost) + m_htApplications[docroot]; + + if (oahHost == null) + { + oahHost = OxideApplicationHost.CreateApplicationHost ( + "/", docroot); + + m_csSponsor.Register (oahHost); + + m_htApplications[docroot] = oahHost; + } + + return (oahHost); + } + } +} diff --git a/mk4/mobility-client/modmono/src/OxideMain.cs b/mk4/mobility-client/modmono/src/OxideMain.cs new file mode 100644 index 0000000..0644e39 --- /dev/null +++ b/mk4/mobility-client/modmono/src/OxideMain.cs @@ -0,0 +1,25 @@ +using System; +using System.Runtime.Remoting; +using System.Runtime.Remoting.Lifetime; + +namespace Fivestops.Oxide +{ + public class OxideMain + { + public static void Main (string[] argv) + { + try + { + CausalityClient.Init (int.Parse (argv[0])); + + OxideApplicationPool oapPool = new OxideApplicationPool(); + + oapPool.ProcessRequests(); + } + catch (Exception e) + { + Console.WriteLine ("ex:\n{0}", e); + } + } + } +} diff --git a/mk4/mobility-client/modmono/src/OxideThreadPool.cs b/mk4/mobility-client/modmono/src/OxideThreadPool.cs new file mode 100644 index 0000000..f73781c --- /dev/null +++ b/mk4/mobility-client/modmono/src/OxideThreadPool.cs @@ -0,0 +1,87 @@ + +namespace Fivestops.Oxide +{ + class OxideThreadPool + { + private static OxideThreadPool s_otpPool = null; + + private Queue m_qRequestQueue; + + private long m_lThreadsInUse = 0; + private long m_lCurrentThreads = 0; + + + static OxideThreadPool() + { + s_otpPool = new OxideThreadPool(); + } + + private OxideThreadPool() + { + m_qRequestQueue = Queue.Synchronized (new Queue()); + } + + private void QueueUserWorkItem (WaitCallback callback, object context) + { + OxideThreadPoolItem otpiItem = new OxideThreadPoolItem(); + + otpiItem.Callback = callback; + otpiItem.Context = context; + + m_qRequestQueue.Enqueue (otpiItem); + } + + public static void QueueUserWorkItem (WaitCallback callback) + { + s_otpPool.QueueUserWorkItem (callback, null); + } + + public static void QueueUserWorkItem (WaitCallback callback, object context) + { + s_otpPool.QueueUserWorkItem (callback, context); + } + + private void WorkerThread() + { + bool bWaitFor = false; + + try + { + Interlocked.Increment (ref m_lCurrentThreads); + + while (true) + { + try + { + OxideThreadPoolItem otpiItem = (OxideThreadPoolItem) m_qRequestQueue.Dequeue(); + + try + { + Interlocked.Increment (ref m_lThreadsInUse); + + otpiItem.Callback (otpiItem.Context); + } + finally + { + Interlocked.Decrement (ref m_lThreadsInUse); + } + } + catch (InvalidOperationException) + { + bWait = true; + } + } + } + finally + { + Interlocked.Decrement (ref m_lCurrentThreads); + } + } + + struct OxideThreadPoolItem + { + public WaitCallback Callback; + public object Context; + } + } +} diff --git a/mk4/mobility-client/modmono/src/OxideWorkerRequest.cs b/mk4/mobility-client/modmono/src/OxideWorkerRequest.cs new file mode 100644 index 0000000..7cae3fe --- /dev/null +++ b/mk4/mobility-client/modmono/src/OxideWorkerRequest.cs @@ -0,0 +1,267 @@ + +// #define DEBUG + +using System; +using System.Text; +using System.Web; +using System.IO; +using System.Web.Hosting; + +namespace Fivestops.Oxide +{ + public class OxideWorkerRequest : HttpWorkerRequest + { + CausalityRequest m_crRequest; + + public OxideWorkerRequest (CausalityRequest request) + { + if (request == null) + { + throw (new ArgumentNullException ("request")); + } + + m_crRequest = request; + + if (m_crRequest.Page == "/exit.w3wp.aspx") + { + Environment.Exit (1); + } + } + + public override void CloseConnection() + { + m_crRequest.Finish(); + } + + public override void EndOfRequest() + { + m_crRequest.Finish(); + } + + public override void FlushResponse (bool finalFlush) + { + // currently does nothing -- we send our data back as soon as we + // get it + } + + public override string GetAppPath() + { + return ((string) AppDomain.CurrentDomain.GetData (".hostingVirtualPath")); + } + + public override string GetAppPathTranslated() + { + return ((string) AppDomain.CurrentDomain.GetData (".appPath")); + } + + public override string GetFilePath() + { + string path = m_crRequest.GetVariable ("path"); + + string strAppPath = this.GetAppPathTranslated().TrimEnd ('/'); + + if (path.StartsWith (strAppPath)) + { + return (path.Substring (strAppPath.Length)); + } + else + { + return (m_crRequest.GetVariable ("uri")); + } + } + + public override string GetFilePathTranslated() + { + string path = m_crRequest.GetVariable ("path"); + + return (path); + } + + public override string GetHttpVerbName() + { + return (m_crRequest.GetVariable ("method")); + } + + public override string GetHttpVersion() + { + return (m_crRequest.GetVariable ("protocol")); + } + + public override string GetKnownRequestHeader (int index) + { + string strKey = HttpWorkerRequest.GetKnownRequestHeaderName (index); + + // temporarily not passing on Accept-Encoding until we are passing + // response headers back + if (strKey == "Accept-Encoding") + { + return (null); + } + + return (GetUnknownRequestHeader (strKey)); + } + + public override string GetLocalAddress() + { + return ("(unknown)"); + } + + public override int GetLocalPort() + { + return (0); + } + + public override string GetPathInfo() + { + return (m_crRequest.GetVariable ("path_info")); + } + + // we don't preload anything in this process until it's requested + public override byte[] GetPreloadedEntityBody() + { + return (new byte[0]); + } + + public override string GetProtocol() + { + if (this.IsSecure() == true) + { + return ("HTTPS"); + } + else + { + return ("HTTP"); + } + } + + public override string GetQueryString() + { + return (m_crRequest.Query); + } + + public override byte[] GetQueryStringRawBytes() + { + return (Encoding.UTF8.GetBytes (m_crRequest.Query)); + } + + public override string GetRawUrl() + { + string strUrl = this.GetUriPath(); + + if (this.GetPathInfo() != null && this.GetPathInfo() != string.Empty) + { + strUrl += this.GetPathInfo(); + } + + if (this.GetQueryString() != null && this.GetQueryString() != string.Empty) + { + strUrl += "?" + this.GetQueryString(); + } + + return (strUrl); + } + + public override string GetRemoteAddress() + { + return (m_crRequest.GetRemoteIP()); + } + + // we don't currently have the remote port. + public override int GetRemotePort() + { + return (0); + } + + public override string GetUriPath() + { + return (m_crRequest.GetVariable ("uri")); + } + + public override string GetUnknownRequestHeader (string name) + { + string strValue = m_crRequest.GetRequestHeader (name.ToLower()); + + return (strValue); + } + + public override bool HeadersSent() + { + return (m_crRequest.HeadersSent()); + } + + // THIS IS NOT WINDOWS AWARE + public override string MapPath (string virtualPath) + { + string strPath = this.GetAppPathTranslated(); + + // make sure we're dealing with a path within our application + if (virtualPath.StartsWith (this.GetAppPath()) == false) + { + return (null); + } + + if (virtualPath[0] == '/') + { + if (virtualPath.Length == 1) + { + return (strPath); + } + + virtualPath = virtualPath.Substring (1); + } + + return (Path.Combine (strPath, virtualPath)); + } + + public override void SendResponseFromMemory (byte[] data, int len) + { + if (m_crRequest.Write (data, len) == false) + { + // if we can't write, we'll assume the connection is dead. + HttpContext.Current.ApplicationInstance.CompleteRequest(); + } + } + + public override void SendResponseFromFile (IntPtr handle, long offset, long length) + { + throw (new NotImplementedException ()); + } + + public override void SendResponseFromFile (string filename, long offset, long length) + { + throw (new NotImplementedException ()); + } + + public override void SendStatus (int status, string description) + { + m_crRequest.SetStatus (status, description); + } + + public override void SendKnownResponseHeader (int index, string value) + { + string strKey = HttpWorkerRequest.GetKnownRequestHeaderName (index); + + this.SendUnknownResponseHeader (strKey, value); + } + + public override void SendUnknownResponseHeader (string key, string value) + { + m_crRequest.SetResponseHeader (key, value); + } + + public override int ReadEntityBody (byte[] buffer, int size) + { + return (m_crRequest.ReadEntityBody (buffer, size)); + } + + public override void SendCalculatedContentLength (int length) + { + this.SendUnknownResponseHeader ("Content-Length", length.ToString()); + } + + public override bool IsEntireEntityBodyIsPreloaded() + { + return (m_crRequest.IsEntireEntityLoaded()); + } + } +} diff --git a/mk4/modbeacon/CVS/Entries b/mk4/modbeacon/CVS/Entries new file mode 100644 index 0000000..c495212 --- /dev/null +++ b/mk4/modbeacon/CVS/Entries @@ -0,0 +1,5 @@ +/Makefile.in/1.3/Wed May 12 13:56:52 2004//Tmk4_mod6_rc2 +/beacon.c/1.8/Tue Jun 22 15:55:38 2004//Tmk4_mod6_rc2 +/beacon.xml/1.2/Wed May 12 15:09:20 2004//Tmk4_mod6_rc2 +/kstat.h/1.1.1.1/Mon Nov 17 21:05:41 2003//Tmk4_mod6_rc2 +D diff --git a/mk4/modbeacon/CVS/Repository b/mk4/modbeacon/CVS/Repository new file mode 100644 index 0000000..ded1fcd --- /dev/null +++ b/mk4/modbeacon/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/modbeacon diff --git a/mk4/modbeacon/CVS/Root b/mk4/modbeacon/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/modbeacon/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/modbeacon/CVS/Tag b/mk4/modbeacon/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/modbeacon/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/modbeacon/Makefile.in b/mk4/modbeacon/Makefile.in new file mode 100644 index 0000000..15cc885 --- /dev/null +++ b/mk4/modbeacon/Makefile.in @@ -0,0 +1,24 @@ +# $Header: /san01/cvs/ashpool/csrc/modbeacon/Attic/Makefile.in,v 1.3 2004/05/12 13:56:52 aleigh Exp $ + +include ../continuity/lib/env.mk + +SRCS=beacon.c +OBJS=beacon.o +OUT=beacon.so + +CFLAGS=-I../continuity/include $(CONT_FLAGS) + +world: install + +$(OUT): $(OBJS) + $(LD_SHARECMD) -o $(OUT) $(OBJS) +clean: + $(RM) $(OBJS) *~ $(OUT) + +install: $(OUT) + cp $(OUT) ../continuity/lib + cp beacon.xml ../continuity/lib + + +depend: + $(MAKEDEPEND) $(DEPFLAGS) -I ../continuity/include $(SRCS) diff --git a/mk4/modbeacon/beacon.c b/mk4/modbeacon/beacon.c new file mode 100644 index 0000000..628262d --- /dev/null +++ b/mk4/modbeacon/beacon.c @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2004 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Use, disclosure, copying, distribution, or transmission of this code without + * express permission is prohibited. + */ + +#include +#include + +struct tasSstat { + unsigned int tas_ctime; + struct tasSstat *tas_next; + + char tas_module[TA_STAT_STRLEN]; + int tas_instance; + char tas_name[TA_STAT_STRLEN]; + int tas_type; + char tas_class[TA_STAT_STRLEN]; + unsigned char tas_flags; + void *tas_data; + size_t tas_data_size; + unsigned int tas_ndata; +}; + +struct tasSctl { + struct tasSstat *chain; +}; + +int beaconFstatpage(httpTtrans *t, lstTset *set) +{ + tasTstat *p; + char *v1 = "TAS Chain empty.\n"; + char buf[1024]; + struct timeval tv; + const char *uri; + + uri = lstFset_get(t->vars, "uri"); + + if (strcmp(uri, "/.sc_stat") != 0) + return STATUS_PROCEED; + + lstFset_update(t->res_hdrs, "Content-Type", "text/plain"); + httpFset_status(t, 200, NULL); + httpFstart_response(t); + + p = tasFget_chain(); + + if (p == NULL) { + httpFwrite(t, v1, strlen(v1)); + return STATUS_EXIT; + } + while (1) { + gettimeofday(&tv, NULL); /* $$$ but accurate */ + + sprintf(buf, + "ta,%s.%d.%s,", + p->tas_module, p->tas_instance, p->tas_name); + + httpFwrite(t, buf, strlen(buf)); + + if (p->tas_type == TA_STAT_INT) { + int *ip; + ip = p->tas_data; + sprintf(buf, "%d", *ip); + httpFwrite(t, buf, strlen(buf)); + } + if (p->tas_type == TA_STAT_UINT) { + unsigned int *ip; + ip = p->tas_data; + sprintf(buf, "%u", *ip); + httpFwrite(t, buf, strlen(buf)); + } + sprintf(buf, ",%lu,%lu\n", tv.tv_sec, tv.tv_usec); + httpFwrite(t, buf, strlen(buf)); + + if (p->tas_next == NULL) + break; + p = p->tas_next; + } + + return STATUS_EXIT; +} + +static void beaconFthread(void) +{ + uint32_t pages_total, pages_free, phys_mem, availr_mem, free_mem; + uint32_t idle, user, kernel, wait; + uint32_t n_idle, n_user, n_kernel, n_wait; + uint32_t o_idle, o_user, o_kernel, o_wait; + uint32_t ibytes, obytes, ipkts, opkts; + + /* Since we are dealing with deltas, we will load the "old" values + * and do nothing about them. This will prevent an apparently huge + * spike appearing in the graphs when the first response from the server + * are the since-rollover values. + */ + sysFcpu_usage(&o_idle,&o_user,&o_kernel,&o_wait); + + while(1) { + sysFmem_usage(&pages_total,&pages_free, + &phys_mem,&availr_mem,&free_mem); + tasFstat_set("sys",0,"pagestotal",pages_total); + tasFstat_set("sys",0,"pagesfree",pages_free); + tasFstat_set("sys",0,"physmem",phys_mem); + tasFstat_set("sys",0,"availrmem",availr_mem); + tasFstat_set("sys",0,"freemem",free_mem); + + + sysFcpu_usage(&idle,&user,&kernel,&wait); + n_idle=idle-o_idle; + n_user=user-o_user; + n_kernel=kernel-o_kernel; + n_wait=wait-o_wait; + + tasFstat_set("cpu",0,"idle_time",n_idle); + tasFstat_set("cpu",0,"user_time",n_user); + tasFstat_set("cpu",0,"kernel_time",n_kernel); + tasFstat_set("cpu",0,"wait_time",n_wait); + tasFstat_set("cpu",0,"total_time",n_idle+n_user+n_kernel+n_wait); + + o_idle=idle; + o_user=user; + o_kernel=kernel; + o_wait=wait; + + sysFnet_usage(&obytes, &ibytes, &opkts, &ipkts); + tasFstat_set("net",0,"bytes_out",obytes); + tasFstat_set("net",0,"bytes_in",ibytes); + + thrFsleep(5000); + } +} + + +int beaconFinit(void *p, lstTset * o) +{ + pthread_t tid; + + logFmsg(0,"mod/beacon: System metrics beacon."); + logFmsg(0,"Copyright (c) 2004, Alex Leigh"); + + pthread_create(&tid,NULL,(void *(*)(void *))&beaconFthread,NULL); + + return STATUS_PROCEED; +} + +int tasFrts_stream(httpTtrans * t, lstTset * opts) +{ + tasTstat *p; + char *v1 = "TAS Chain empty.\n"; + char buf[1024]; + struct timeval tv; + char *uri; + + uri = lstFset_get(t->vars, "uri"); + if (strcmp(uri, "/continuity.rts") != 0) + return STATUS_PROCEED; + + lstFset_update(t->res_hdrs, "Content-Type", "text/plain"); + httpFset_status(t, 200, NULL); + httpFstart_response(t); + + p = tasFget_chain(); + + if (p == NULL) { + httpFwrite(t, v1, strlen(v1)); + return STATUS_EXIT; + } + while (1) { + p = tasFget_chain(); + + while (1) { + gettimeofday(&tv, NULL); /* $$$ but accurate */ + + sprintf(buf, + "ty=u&na=%s.%d.%s", + p->tas_module, p->tas_instance, p->tas_name); + + httpFwrite(t, buf, strlen(buf)); + + if (p->tas_type == TA_STAT_INT) { + int *ip; + ip = p->tas_data; + sprintf(buf, "&va=%d", *ip); + httpFwrite(t, buf, strlen(buf)); + } + if (p->tas_type == TA_STAT_UINT) { + unsigned int *ip; + ip = p->tas_data; + sprintf(buf, "&va=%u", *ip); + httpFwrite(t, buf, strlen(buf)); + } + sprintf(buf, "&ti=%lu.%lu\n", tv.tv_sec, tv.tv_usec); + httpFwrite(t, buf, strlen(buf)); + + if (p->tas_next == NULL) + break; + p = p->tas_next; + } + thrFsleep(1000); + } + return STATUS_EXIT; +} + diff --git a/mk4/modbeacon/beacon.xml b/mk4/modbeacon/beacon.xml new file mode 100644 index 0000000..abdcec5 --- /dev/null +++ b/mk4/modbeacon/beacon.xml @@ -0,0 +1,4 @@ + + beacon + beaconFinit + diff --git a/mk4/modbeacon/kstat.h b/mk4/modbeacon/kstat.h new file mode 100644 index 0000000..0cd3c42 --- /dev/null +++ b/mk4/modbeacon/kstat.h @@ -0,0 +1,23 @@ +#ifndef TA_KSTAT_H +#define TA_KSTAT_H + +#pragma ident "@(#) $Header: /san01/cvs/ashpool/csrc/modbeacon/Attic/kstat.h,v 1.1.1.1 2003/11/17 21:05:41 aleigh Exp $" + +/* + * These descriptions are assumptions and are not entirely + * accurate. Most solaris systems have an 8k page size. + */ + +struct taSmemuse { + unsigned int pagestotal; /* Total pages on the system */ + unsigned int pagesfree; /* Pages free on the system */ + unsigned int physmem; /* Physical Memory installed in the machine */ + unsigned int availrmem; /* Available physical memory, not including fscache */ + unsigned int freemem; /* Available physical memoroy, including fscache */ +}; +typedef struct taSmemuse taTmemuse; + +double kstatFget_load(void); + +#endif + diff --git a/mk4/modcommand/CVS/Entries b/mk4/modcommand/CVS/Entries new file mode 100644 index 0000000..3d1b31f --- /dev/null +++ b/mk4/modcommand/CVS/Entries @@ -0,0 +1,5 @@ +/Makefile.in/1.2/Wed May 12 13:49:25 2004//Tmk4_mod6_rc2 +/cmd.c/1.16/Tue May 11 15:36:17 2004//Tmk4_mod6_rc2 +/cmd.h/1.7/Tue May 11 15:36:17 2004//Tmk4_mod6_rc2 +/cmd.xml/1.2/Wed May 12 14:29:44 2004//Tmk4_mod6_rc2 +D diff --git a/mk4/modcommand/CVS/Repository b/mk4/modcommand/CVS/Repository new file mode 100644 index 0000000..4452104 --- /dev/null +++ b/mk4/modcommand/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/modcommand diff --git a/mk4/modcommand/CVS/Root b/mk4/modcommand/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/modcommand/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/modcommand/CVS/Tag b/mk4/modcommand/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/modcommand/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/modcommand/Makefile.in b/mk4/modcommand/Makefile.in new file mode 100644 index 0000000..8e08e9b --- /dev/null +++ b/mk4/modcommand/Makefile.in @@ -0,0 +1,24 @@ +# $Header: /san01/cvs/ashpool/csrc/modcommand/Attic/Makefile.in,v 1.2 2004/05/12 13:49:25 aleigh Exp $ + +include ../continuity/lib/env.mk + +SRCS=cmd.c +OBJS=cmd.o + +CFLAGS=-I../continuity/include $(CONT_FLAGS) + +world: install + +cmd.so: $(OBJS) + $(LD_SHARECMD) -o cmd.so $(OBJS) +clean: + $(RM) $(OBJS) *~ cmd.so + +install: cmd.so cmd.h + (rm -f ../continuity/lib/cmd.so ; cp cmd.so ../continuity/lib) + cp cmd.h ../continuity/include + cp cmd.xml ../continuity/lib + + +depend: + $(MAKEDEPEND) -I../continuity/include $(DEPFLAGS) $(SRCS) diff --git a/mk4/modcommand/cmd.c b/mk4/modcommand/cmd.c new file mode 100644 index 0000000..018b409 --- /dev/null +++ b/mk4/modcommand/cmd.c @@ -0,0 +1,430 @@ +/* $Id: cmd.c,v 1.16 2004/05/11 15:36:17 aleigh Exp $ */ + +/* + * Copyright (c) 1994, 2001 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Use, disclosure, copying, distribution, or transmission of this code without + * express permission is prohibited. + */ + +#include "cmd.h" + +static char cmdGhostname[64]; + +#define CMDLEN 256 + +struct cmdSop { + const char *op_name; + int (*op_func)(netTconn *conn, int argc, char **argv); + const char *helpmsg; + struct cmdSop *sub_ops; + struct cmdSop *next; +}; +/* typedef in cmd.h */ + +struct cmdSstate { + char cmd[CMDLEN]; + int len; +}; +typedef struct cmdSstate cmdTstate; + +#define CMDPROTO(x) static int x(netTconn *conn, int argc, char **argv) + +CMDPROTO(cmdFop_quit); +CMDPROTO(cmdFop_show_version); +CMDPROTO(cmdFop_show_time); +CMDPROTO(cmdFop_reload); +CMDPROTO(cmdFop_halt); + +cmdTop *cmdGops = NULL; +lstTset *cmdGusers=NULL; + +cmdTop *cmdFroot(void) { + return cmdGops; +} + +void cmdFbind_stub(cmdTop *parent, + const char *cmd, + const char *helpmsg) { + cmdTop *newop; + + newop=(cmdTop *)malloc(sizeof(cmdTop)); + newop->op_name=strFcopy(cmd); + newop->sub_ops=NULL; + newop->helpmsg=strFcopy(helpmsg); + + if(parent->sub_ops==NULL) { + newop->next=NULL; + parent->sub_ops=newop; + } else { + newop->next=parent->sub_ops; + parent->sub_ops=newop; + } +} + +void cmdFbind_command(cmdTop *parent, + const char *cmd, + int(*op_func)(netTconn *conn, int argc, char **argv), const char *helpmsg) { + cmdTop *newop; + + newop=(cmdTop *)malloc(sizeof(cmdTop)); + newop->op_func=op_func; + newop->op_name=strFcopy(cmd); + newop->sub_ops=NULL; + newop->helpmsg=strFcopy(helpmsg); + + if(parent->sub_ops==NULL) { + newop->next=NULL; + parent->sub_ops=newop; + } else { + newop->next=parent->sub_ops; + parent->sub_ops=newop; + } +} + +int cmdFinit(lstTset *opt) +{ + cmdTop *op; + cmdTop *newop; + + logFmsg(0,"mod/cmd: Command Interpreter"); + logFmsg(0,"Copyright (c) 2004, Alex Leigh"); + + gethostname(cmdGhostname,64); + + cmdGusers=lstFset_init(); + + newop=(cmdTop *)malloc(sizeof(cmdTop)); + memFclear((void *)newop,sizeof(cmdTop)); + newop->op_name=strFcopy("root"); + cmdGops=newop; + + cmdFbind_command(cmdGops,"quit",cmdFop_quit, "Disconnect session."); + cmdFbind_command(cmdGops,"reload",cmdFop_reload, "Reload this Continuity instance."); + cmdFbind_command(cmdGops,"halt",cmdFop_halt, "Halt this Continuity instance."); + + cmdFbind_stub(cmdGops,"show", "Show information."); + op=cmdFmatch("show",cmdGops); + cmdFbind_command(op,"version",cmdFop_show_version, "Show version information."); + cmdFbind_command(op,"time",cmdFop_show_time, "Show current time."); + + cmdFbind_stub(op,"dl", "Dynamic Loader"); + op=cmdFmatch("dl",op); + cmdFbind_command(op,"loads",dlFop_show_dl_loads, "Show current module loads."); + cmdFbind_command(op,"symbols",dlFop_show_dl_symbols, "Show currently mapped funcions."); + + return STATUS_OK; +} + +static void cmdFecho_on(netTconn *conn) +{ + char off_string[] = + { + (char) IAC, + (char) WONT, + (char) TELOPT_ECHO, + (char) TELOPT_NAOFFD, + (char) TELOPT_NAOCRD, + (char) 0, + }; + + netFconn_write(conn, off_string, sizeof(off_string)); +} + +static void cmdFecho_off(netTconn *conn) +{ + char off_string[] = + { + (char) IAC, + (char) WILL, + (char) TELOPT_ECHO, + (char) TELOPT_NAOFFD, + (char) TELOPT_NAOCRD, + (char) 0, + }; + + netFconn_write(conn, off_string, sizeof(off_string)); +} + +static cmdTstate *cmdFstate_init(void) { + cmdTstate *s; + + s=(cmdTstate *)malloc(sizeof(cmdTstate)); + assert(s!=NULL); + + memFclear(s,sizeof(cmdTstate)); + + return s; +} + +static int cmdFgather(netTconn *conn, cmdTstate *state) +{ + char c; + ssize_t ret; + size_t ignore=0; + + while(1) { + ret=read(conn->sd,&c,1); + if(ret==0) { + return -1; + } + + if(ret!=1) { + return -1; + } + + if(ignore>0) { + ignore--; + continue; + } + + switch(c) { + case '\r': + continue; + case '\n': + state->cmd[state->len]=0; + logFmsg(3,"cmd: %s", state->cmd); + state->len=0; + return 0; + case (char)IAC: + ignore+=2; + continue; + } + + // logFmsg(3,"read char: %c %u", c, c); + + state->cmd[state->len]=c; + state->len++; + } +} + +static int cmdFuser_auth(const char *un, const char *pw) { + assert(un!=NULL); + assert(pw!=NULL); + + char *goodpw=lstFset_get(cmdGusers,un); + + if(goodpw==NULL) return 0; + + logFmsg(3,"%s/%s", goodpw, pw); + + if(strcmp(goodpw,pw)!=0) return 0; + + return 1; +} + +cmdTop *cmdFmatch(const char *cmd, cmdTop *ops) { + int partials=0; + cmdTop *partial_op, *op; + + assert(cmd!=NULL); + assert(ops!=NULL); + + // logFmsg(3,"searching for cmd: ->%s<-", cmd); + + size_t clen=strlen(cmd); + + for(op=ops->sub_ops;op!=NULL;op=op->next) { + + // logFmsg(3,"searching for %s: eval %s", cmd, op->op_name); + + if(strcmp(cmd,op->op_name)==0) { + return op; + } + + if(strncmp(cmd,op->op_name,clen)==0) { + partials++; + partial_op=op; + } + } + + if(partials==0) { + /* Command not found */ + return NULL; + } else { + if(partials==1) { + return partial_op; + } + } + + /* Ambiguous expansion */ + return NULL; +} + +static void cmdFdo_help(netTconn *conn, cmdTop *op) { + + netFconn_writef(conn,"\r\nHelp\r\n----\r\n"); + + for(;op!=NULL;op=op->next) { + netFconn_writef(conn, "%s\t%s\r\n", op->op_name, op->helpmsg); + } +} + +static void cmdFloop(netTconn *conn, cmdTstate *state) +{ + char *stack[32]; + const cmdTop *op; + int argc; + + while(1) { + netFconn_writef(conn,"%s -> ", cmdGhostname); + + if(cmdFgather(conn,state)==-1) { + return; + } + + argc=strFsplit(state->cmd, stack, 32, ' ', '"'); + + cmdTop *p; + + p=cmdGops; + + for(int i=0;i%s<-", stack[i]); + + if(strcmp(stack[i],"?")==0) { + cmdFdo_help(conn,p->sub_ops); + continue; + } + + op=cmdFmatch(stack[i],p); + + if(op!=NULL) { + if(op->sub_ops!=NULL) { + p=op; + continue; + } + + if(op->op_func(conn,argc-i,&stack[i])==STATUS_EXIT) { + return; + } else { + break; + } + } else { + netFconn_writef(conn,"Invalid command.\r\n"); + break; + } + } + } +} + + +void cmdFhandler(netTconn *conn) +{ + cmdTstate *state=cmdFstate_init(); + char username[16]; + + assert(conn!=NULL); + assert(state!=NULL); + + while(1) { + netFconn_writef(conn,"\r\nlogin: "); + + if(cmdFgather(conn,state)==-1) { + break; + } + + strncpy(username,state->cmd,16); + + cmdFecho_off(conn); + netFconn_writef(conn,"Password: "); + + if(cmdFgather(conn,state)==-1) { + break; + } + + cmdFecho_on(conn); + + if(cmdFuser_auth(username,state->cmd)==0) { + netFconn_writef(conn,"login denied.\r\n"); + continue; + } + + logFmsg(3,"logged in."); + netFconn_writef(conn,"\r\nLogin accepted.\r\n"); + netFconn_writef(conn,"\r\n%s\r\n", BUILD_STRING); + + cmdFloop(conn,state); + break; + } + + logFmsg(3,"Shutting down connection."); + + netFconn_close(conn); +} + +static int cmdFop_quit(netTconn *conn, int argc, char **argv) +{ + netFconn_writef(conn,"Goodbye.\r\n"); + + return STATUS_EXIT; +} + +static int cmdFop_show_version(netTconn *conn, int argc, char **argv) { + netFconn_writef(conn,"\r\nVersion\r\n-------\r\n"); + op_show_version(conn); + return STATUS_OK; +} + +static int cmdFop_reload(netTconn *conn, int argc, char **argv) { + if(argc<2) { + netFconn_writef(conn,"Usage: RELOAD YES\r\n"); + return STATUS_OK; + } + + if(strcasecmp(argv[1],"yes")!=0) { + netFconn_writef(conn,"Usage: RELOAD YES\r\n"); + return STATUS_OK; + } + + netFconn_writef(conn,"Reloading instance...\r\n"); + + exit(0); +} + +static int cmdFop_halt(netTconn *conn, int argc, char **argv) { + if(argc<2) { + netFconn_writef(conn,"Usage: HALT YES\r\n"); + return STATUS_OK; + } + + if(strcasecmp(argv[1],"yes")!=0) { + netFconn_writef(conn,"Usage: HALT YES\r\n"); + return STATUS_OK; + } + + netFconn_writef(conn,"Halting instance...\r\n"); + + /* Instruct cdog to die if we are running under it */ + exit(5); +} + +static int cmdFop_show_time(netTconn *conn, int argc, char **argv) { + netFconn_writef(conn,"%s\r\n", utlFcommonlog_time()); + return STATUS_OK; +} + +static int cmdFop_show_uptime(netTconn *conn, int argc, char **argv) { + netFconn_writef(conn,"Uptime\r\n------\r\n"); + return STATUS_OK; +} + +int cmdFadd_user(void *p, lstTset *opt) { + const char *un, *pw; + + un=lstFset_get(opt,"user"); + pw=lstFset_get(opt,"password"); + + if(un!=NULL && pw!=NULL) { + lstFset_add(cmdGusers,un,pw); + } else { + logFmsg(2,"Failed."); + exit(5); + } + + return STATUS_OK; +} diff --git a/mk4/modcommand/cmd.h b/mk4/modcommand/cmd.h new file mode 100644 index 0000000..f8770fc --- /dev/null +++ b/mk4/modcommand/cmd.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 1994, 2001 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Use, disclosure, copying, distribution, or transmission of this code without + * express permission is prohibited. + */ + +#ifndef _CMD_H +#define _CMD_H + +#include +#include + +typedef struct cmdSop cmdTop; + +void cmdFbind_stub(cmdTop *parent,const char *cmd, const char *helpmsg); +void cmdFbind_command(cmdTop *parent, + const char *cmd, + int(*op_func)(netTconn *conn, int argc, char **argv), + const char *helpmsg); +cmdTop *cmdFroot(void); +cmdTop *cmdFmatch(const char *cmd, cmdTop *ops); +int cmdFadd_user(void *p, lstTset *opt); +#endif + diff --git a/mk4/modcommand/cmd.xml b/mk4/modcommand/cmd.xml new file mode 100644 index 0000000..8efa137 --- /dev/null +++ b/mk4/modcommand/cmd.xml @@ -0,0 +1,4 @@ + + cmd + cmdFinit + diff --git a/mk4/moddb/CVS/Entries b/mk4/moddb/CVS/Entries new file mode 100644 index 0000000..153c976 --- /dev/null +++ b/mk4/moddb/CVS/Entries @@ -0,0 +1,5 @@ +/Makefile.in/1.3/Wed May 12 13:57:25 2004//Tmk4_mod6_rc2 +/db.c/1.6/Fri May 14 06:20:33 2004//Tmk4_mod6_rc2 +/db.h/1.5/Fri May 14 06:20:33 2004//Tmk4_mod6_rc2 +/db.xml/1.1/Wed May 12 13:58:08 2004//Tmk4_mod6_rc2 +D diff --git a/mk4/moddb/CVS/Repository b/mk4/moddb/CVS/Repository new file mode 100644 index 0000000..7204c42 --- /dev/null +++ b/mk4/moddb/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/moddb diff --git a/mk4/moddb/CVS/Root b/mk4/moddb/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/moddb/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/moddb/CVS/Tag b/mk4/moddb/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/moddb/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/moddb/Makefile.in b/mk4/moddb/Makefile.in new file mode 100644 index 0000000..2bc5c25 --- /dev/null +++ b/mk4/moddb/Makefile.in @@ -0,0 +1,24 @@ +# $Header: /san01/cvs/ashpool/csrc/moddb/Attic/Makefile.in,v 1.3 2004/05/12 13:57:25 aleigh Exp $ + +include ../continuity/lib/env.mk + +SRCS=db.c +OBJS=db.o + +CFLAGS=-I../continuity/include $(CONT_FLAGS) + +world: install + +db.so: $(OBJS) + $(LD_SHARECMD) -o db.so $(OBJS) +clean: + $(RM) $(OBJS) *~ db.so + +install: db.so db.h + (rm -f ../continuity/lib/db.so ; cp db.so ../continuity/lib) + cp db.h ../continuity/include + cp db.xml ../continuity/lib + + +depend: + $(MAKEDEPEND) $(DEPFLAGS) -I ../continuity/include $(SRCS) diff --git a/mk4/moddb/db.c b/mk4/moddb/db.c new file mode 100644 index 0000000..05778da --- /dev/null +++ b/mk4/moddb/db.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 1994, 2001 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Disclosure, copying, distribution, or transmission of this code without + * express permission is prohibited. + */ + +#include +#include "db.h" + +static dbTvector *vector = NULL; + +void dbFvector_register(dbTvector * vec) +{ + vector = vec; +} + +void *dbFopen(const char *user, const char *password, const char *service) +{ + return (*vector->open_fn) (user, password, service); +} + +int dbFclose(void *conn) +{ + return (*vector->close_fn) (conn); +} + +lstTset *dbFselect(void *conn, const char *sql) +{ + return (*vector->select_fn) (conn, sql); +} + +void dbFinit(void) +{ + (*vector->init_fn) (); +} + +int dbFgetrow(void *conn, lstTset * row) +{ + return (*vector->getrow_fn) (conn, row); +} + +int dbFdml(void *conn, const char *sql) +{ + return (*vector->dml_fn) (conn, sql); +} diff --git a/mk4/moddb/db.h b/mk4/moddb/db.h new file mode 100644 index 0000000..344770e --- /dev/null +++ b/mk4/moddb/db.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 1994, 2001 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Disclosure, copying, distribution, or transmission of this code without + * express permission is prohibited. + */ + +#ifndef _DB_H +#define _DB_H + +struct dbSvector { + void (*init_fn)(void); + void *(*open_fn)(const char *user, const char *password, const char *service); + int (*close_fn)(void *conn); + + lstTset *(*select_fn)(void *conn, const char *sql); + int (*getrow_fn)(void *conn, lstTset *row); + + int (*dml_fn)(void *conn, const char *sql); +}; +typedef struct dbSvector dbTvector; + +void dbFvector_register(dbTvector *vec); +void *dbFopen(const char *user, const char *password, const char *service); +int dbFclose(void *conn); +void dbFinit(void); +lstTset *dbFselect(void *conn, const char *sql); +int dbFgetrow(void *conn, lstTset *row); +int dbFdml(void *conn, const char *sql); + +#endif + diff --git a/mk4/moddb/db.xml b/mk4/moddb/db.xml new file mode 100644 index 0000000..fe21915 --- /dev/null +++ b/mk4/moddb/db.xml @@ -0,0 +1,3 @@ + + db + diff --git a/mk4/moddynamo/CMLDRP.c b/mk4/moddynamo/CMLDRP.c new file mode 100644 index 0000000..80d24fb --- /dev/null +++ b/mk4/moddynamo/CMLDRP.c @@ -0,0 +1,1485 @@ +/* + * Copyright (C) 1997 Art Technology Group, Inc. + * All Rights Reserved. No use, copying or distribution of this + * work may be made except in accordance with a valid license + * agreement from Art Technology Group. This notice must be + * included on all copies, modifications and derivatives of this + * work. + * + * Art Technology Group (ATG) MAKES NO REPRESENTATIONS OR WARRANTIES + * ABOUT THE SUITABILITY OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. ATG SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, + * MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. + * + * "Dynamo" is a trademark of Art Technology Group, Inc. + */ + +/* + CMLDRP.c - routines for CMLDRP subsystem + ("Connection-Module Load-Distribution Request Protocol", or something) + */ + +#ifndef WIN32 +/* NT */ +#include +#include +#include +#include +#include +#endif + +/* #define DEBUG */ + +#include /* for sprintf */ +#include + +#include + +#include "DRPClient.h" +#include "CMLDRP.h" + +#ifdef _DRP_MTHREAD +#include "threadabstr.h" +#endif + +#define kSilentCMLDRPLogInterval 150 /* seconds */ + + + +/* static prototypes */ +static int generateCMLDRPIdentifier(CMLDRP_Block * pBlock, + unsigned short iHTTPPort); +static int dispatchResponseMetaData(CMLDRP_Block * pBlock, + int iBytesReceived); +static int dispatchResponseData(CMLDRP_Block * pBlock, int iBytesReceived); +static int cmldrpUpdate(CMLDRP_Block * pBlock); +static int selectNextCMLDRPServer(CMLDRP_Block * pBlock); +static int internalizeCMLDRPServerInfo(CMLDRP_Block * pBlock, + int iNumServers, + const CMLDRP_ServerInfo * iServers); +static int openUDPSocket(CMLDRP_Block * pBlock, const char *iBindAddress); + +/* NOTE: Currently not used so not declared. - Frank Kim, 12/28/99 (lmd 3/24/00) */ +#if 0 +static int compareDRPServerRecords_ipPort(const void *iRec1, + const void *iRec2); +#endif + +#ifdef _DRP_MTHREAD +static int connectToNextCMLDRPServer(CMLDRP_Block * pBlock); +static void closeCMLDRPConnection(CMLDRP_Block * pBlock); +static int startCMLDRPThread(CMLDRP_Block * pBlock); +static kThread_returnType cmldrpThreadFunction(kThread_argType iArg); + +static Thread_t gCMLDRPThread = kThread_InvalidThread; +RWLock gLoadDataLock; + +#define kDefaultMaxHandlers 100 /* a maximum of 100 handler threads */ +#define kDefaultHandlersTimeout 30000 /* wait at most 30 seconds to acquire mutex */ +#define kDefaultBackoffInterval 5 +/* wait at most 5 seconds once limit has exceeded before testing next time */ +RWLock gHandlerCountLock; +int gEnforceMaxHandlers = 0; /* By default do not enforce the max handlers */ +int gMaxHandlers = kDefaultMaxHandlers; +int gHandlerCount = 0; +int gExceededLimit = 0; +time_t gBackoffInterval = kDefaultBackoffInterval; /* in seconds */ +time_t gLastTimeThreadLimitReported = 0; +time_t gLastTimeExceededLimitReached = 0; +#endif + +/* global variables */ + +CMLDRP_Block gCMLDRPBlock; + +drpServerRecord gDrpServers[kMaxDRPRecords]; +drpServerRecord *gDrpServerPtrs[kMaxDRPRecords]; +int gNumDrpServers; + +DebugInfo gDebugInfo = { 0, /* numRequestThreads */ + 0, /* numActiveRequests */ + 0, /* numWaitingOnReadLock */ + 0, /* numWaitingOnPool */ + 0, /* numWaitingToConnect */ + 0, /* numSendingRequest */ + 0 +}; /* numWaitingForResponse */ + +unsigned short gCMLDRP_Shutdown; +unsigned int gCMLDRP_InfoVersion; +unsigned short gCMLDRP_UpdateNow; +unsigned short gCMLDRP_ManagerRotationEnabled = 1; + +#ifdef _DRP_MTHREAD +unsigned short gCMLDRP_UseTcp = 0; +int gCMLDRP_TcpTimeout = kCMLDRP_DefaultTcpTimeout; +unsigned short gCMLDRP_ThreadIsRunning = 0; +#endif + +#ifdef _CPOOL +extern int gCP_Enabled; +#endif + +/** + * cmldrpInitialize + * Initializes the CMLDRP subsystem and initiates the first attempt to + * obtain DRP server information from a CMLDRP server (in the multiprocess + * case) or starts the CMLDRP thread (in the multithreaded case). + * iNumServers: number of CMLDRP server info blocks in iServers + * iServers: array of CMLDRP_ServerInfo objects + * iBindAddress: address to which CMLDRP subsystem should bind its socket + * (NULL: bind to any appropriate local address) + * iHTTPPort: main service port of the host HTTP server (for purposes of + * identifying this CMLDRP client to the CMLDRP server). + * iLogFunction: http-server-API-specific logging routine + * iLogShellData: opaque shellData object to be passed to iLogFunction + * return: 0 == success; !0 == failure + */ +int +cmldrpInitialize(int iNumServers, CMLDRP_ServerInfo * iServers, + const char *iBindAddress, unsigned short iHTTPPort, + LogMessage_fn iLogFunction, void *iLogShellData) +{ + int returnValue = 0; + + memset(&gCMLDRPBlock, 0, sizeof(gCMLDRPBlock)); + + gCMLDRPBlock.logFunction = iLogFunction; + gCMLDRPBlock.logShellData = iLogShellData; + + gCMLDRPBlock.nextServerToContact = NULL; + gCMLDRPBlock.lastTimeSilenceReported = 0; + gCMLDRPBlock.sock = kInvalidSocket; + +#ifdef _DRP_MTHREAD + gCMLDRPBlock.inputStream = NULL; + gCMLDRPBlock.outputStream = NULL; +#endif + + gCMLDRPBlock.timeout.tv_sec = kCMLDRP_DefaultTimeoutSec; + gCMLDRPBlock.timeout.tv_usec = kCMLDRP_DefaultTimeoutUsec; + + gCMLDRPBlock.nextUpdateTime = time(NULL); + +#ifdef _DRP_MTHREAD + if (0 == gCMLDRP_UseTcp) { + returnValue = openUDPSocket(&gCMLDRPBlock, iBindAddress); + if (returnValue) + goto CMLDRP_INIT_EXIT; + } +#else + returnValue = openUDPSocket(&gCMLDRPBlock, iBindAddress); + if (returnValue) + goto CMLDRP_INIT_EXIT; +#endif + + + gCMLDRPBlock.httpPort = iHTTPPort; + + returnValue = generateCMLDRPIdentifier(&gCMLDRPBlock, iHTTPPort); + if (returnValue) + goto CMLDRP_INIT_EXIT; + + returnValue = internalizeCMLDRPServerInfo(&gCMLDRPBlock, iNumServers, + iServers); + if (returnValue) + goto CMLDRP_INIT_EXIT; + + gCMLDRPBlock.nextServerToContactIdx = 0; + + gNumDrpServers = 0; + + gCMLDRPBlock.cmldrpVersion = kCMLDRP_RequestVersion; + + gCMLDRP_Shutdown = 0; + gCMLDRP_UpdateNow = 0; + gCMLDRP_InfoVersion = 0; + +#ifdef _DRP_MTHREAD + if (initializeRWLock(&gLoadDataLock)) { + gCMLDRPBlock.logFunction(gCMLDRPBlock.logShellData, kLog_Error, + kLogMessage_CannotCreateRWLock, NULL, + NULL); + returnValue = -1; + goto CMLDRP_INIT_EXIT; + } + if (initializeRWLock(&gHandlerCountLock)) { + gCMLDRPBlock.logFunction(gCMLDRPBlock.logShellData, kLog_Error, + kLogMessage_CannotCreateRWLock, NULL, + NULL); + returnValue = -1; + goto CMLDRP_INIT_EXIT; + } + returnValue = startCMLDRPThread(&gCMLDRPBlock); +#else + cmldrpUpdate(&gCMLDRPBlock); /* discard return value */ +#endif + + CMLDRP_INIT_EXIT: + + return returnValue; +} + +void cmldrpSetDebug(int flag) +{ + gCMLDRPBlock.debugEnabled = flag; +} + +void cmldrpSetManagerRotationEnabled(int flag) +{ + gCMLDRP_ManagerRotationEnabled = flag; +} + +#ifdef _DRP_MTHREAD +/** + * startCMLDRPThread + * starts up the CMLDRP client thread that will periodically refresh + * DRP server info for the entire DRP Client in the current process. + * return: 0 == success; !0 == failure + */ +static int startCMLDRPThread(CMLDRP_Block * pBlock) +{ + int returnValue = 0; + + gCMLDRPThread = + thread_startNewThread(kThread_defaultStackSize, + cmldrpThreadFunction, + (kThread_argType) pBlock); + if (gCMLDRPThread == kThread_InvalidThread) { + gCMLDRPBlock.logFunction(gCMLDRPBlock.logShellData, kLog_Error, + kLogMessage_CannotStartCMLDRPThread, NULL, + NULL); + returnValue = -1; + } + + return returnValue; +} + + +/** + * cmldrpThreadFunction + * the routine run by the CMDLRP client thread. + * iArg: pointer to a cmldrpBlock object (already initialized). + */ +static kThread_returnType cmldrpThreadFunction(kThread_argType iArg) +{ + CMLDRP_Block *cmldrpBlock = (CMLDRP_Block *) iArg; + int result; + short sleepy = 0; + + +#ifdef _DRP_MTHREAD + gCMLDRP_ThreadIsRunning = 1; +#endif + while (!gCMLDRP_Shutdown) { + result = cmldrpUpdate(cmldrpBlock); + if (result == 0) + gCMLDRP_UpdateNow = 0; /* clear force-update flag */ + else { + /* update() failed; set next polltime to minimum polltime + and update next manager to contact */ + cmldrpBlock->nextUpdateTime = + time(NULL) + kCMLDRP_MinimumPollInterval; + selectNextCMLDRPServer(cmldrpBlock); + } + + sleepy = 1; + while (sleepy) { + thread_sleep(kCMLDRP_Sleeptime); + if ((time(NULL) >= cmldrpBlock->nextUpdateTime) + || gCMLDRP_UpdateNow || gCMLDRP_Shutdown) + sleepy = 0; /* i.e. terminate while (sleepy) loop, + return to top of while (! shutdown) loop */ + } + } + +#ifdef _DRP_MTHREAD + gCMLDRP_ThreadIsRunning = 0; +#endif + + thread_return(0); +} +#else /* i.e. ndef _DRP_MTHREAD */ + +/** + * cmldrpUpdate_MP (_MP: multi-process) + * If appropriate, forces CMLDRP subsystem to refresh DRP server information + * from the CMLDRP server. for use in multi-process CMs. + * return: 0 == success; !0 == failure + */ +int cmldrpUpdate_MP(CMLDRP_Block * pBlock) +{ + int returnValue = 0; + int i = 0; + + /* Loop until we find an CMLDRP Server that is available. */ + while (((time(NULL) >= pBlock->nextUpdateTime) || gCMLDRP_UpdateNow) + && (i < pBlock->numCMLDRPServers)) { + returnValue = cmldrpUpdate(pBlock); + if (returnValue == 0) { + /* Success. */ + gCMLDRP_UpdateNow = 0; + return 0; + } else { + /* Current CMLDRP Server is available. Select next one. */ + pBlock->nextUpdateTime = + time(NULL) + kCMLDRP_MinimumPollInterval; + selectNextCMLDRPServer(pBlock); + i++; + } + } + + return returnValue; +} +#endif + + +/** + * internalizeCMLDRPServerInfo + * Stores contact information for CMLDRP servers in a CMLDRP_Block object + * (for use during the initialization phase). + * return: 0 == success; !0 == failure + */ +static int +internalizeCMLDRPServerInfo(CMLDRP_Block * pBlock, int iNumServers, + const CMLDRP_ServerInfo * iServers) +{ + int returnValue = 0; + int s; + + for (s = 0, pBlock->numCMLDRPServers = 0; s < iNumServers; s++) { + pBlock->cmldrpServers[pBlock->numCMLDRPServers].sin_family = + AF_INET; + pBlock->cmldrpServers[pBlock->numCMLDRPServers].sin_port = + htons(iServers[s].port); + pBlock->cmldrpServers[pBlock->numCMLDRPServers].sin_addr.s_addr = + hostToInetAddr(iServers[s].host); + + if (pBlock->cmldrpServers[pBlock->numCMLDRPServers].sin_addr. + s_addr != INADDR_NONE) + pBlock->numCMLDRPServers++; + else { + pBlock->logFunction(pBlock->logShellData, kLog_Error, + kLogMessage_CantResolveCMLDRPHost, + iServers[s].host, NULL); + } + } + + pBlock->nextServerToContact = + &(pBlock->cmldrpServers[pBlock->nextServerToContactIdx]); + + if (pBlock->numCMLDRPServers < 1) { + pBlock->logFunction(pBlock->logShellData, kLog_Error, + kLogMessage_NoGoodCMLDRPServers, NULL, NULL); + returnValue = -1; + } + + return returnValue; +} + + +/** + * generateCMLDRPIdentifier + * Construct an identification string that will uniquely identify this + * CMLDRP client entity + * CMLDRP identifier has the form: + * ::: + * where and reflect the IP and port describing the host HTTP + * server; is the id of the execution context + * of the CMLDRP client entity; serves to uniquely identify + * CMLDRP entities across time. + */ +static int +generateCMLDRPIdentifier(CMLDRP_Block * pBlock, unsigned short iHTTPPort) +{ + int returnValue = 0; + char hostname[MAXHOSTNAMELEN]; + struct hostent *hostinfo; + struct in_addr inAddr; + + if (gethostname(hostname, MAXHOSTNAMELEN)) { + returnValue = -1; + goto GENERATE_CMLDRP_ID_EXIT; + } + + hostinfo = gethostbyname(hostname); + if (hostinfo) { + memcpy(&inAddr, (void *) hostinfo->h_addr, hostinfo->h_length); + pBlock->identifierLength = (char) +#if defined(SOLARIS2) && !defined(_LP64) && !defined(_I32LPx) + sprintf(pBlock->identifier, "%s:%u:%ld:%ld", +#else + sprintf(pBlock->identifier, "%s:%u:%d:%ld", +#endif + inet_ntoa(inAddr), iHTTPPort, getpid(), time(NULL)); + } else { + returnValue = -1; + goto GENERATE_CMLDRP_ID_EXIT; + } + + GENERATE_CMLDRP_ID_EXIT: + + return returnValue; +} + +/** + * outputLength + * The number of bytes waiting to be sent in the io buffer + */ +static int outputLength(CMLDRP_Block * pBlock) +{ + return (sizeof(pBlock->cmldrpVersion) + + sizeof(pBlock->sequenceNumber) + 1 + pBlock->identifierLength); +} + + +/** + * sendCmldrpRequest_Udp + * Send a CMLDRP request via UDP + * return: 0 == success; !0 == failure + */ +int sendCmldrpRequestUdp(CMLDRP_Block * pBlock) +{ + + /* send request buffer */ + if (sendto(pBlock->sock, pBlock->ioBuffer, + outputLength(pBlock), + 0, + (struct sockaddr *) pBlock->nextServerToContact, + sizeof(*(pBlock->nextServerToContact))) + == SOCKET_ERROR) { + return -1; + } + return 0; +} + +#ifdef _DRP_MTHREAD +/** + * sendCmldrpRequest_Tcp + * Send a CMLDRP request via TCP + * return: 0 == success; !0 == failure + */ +int sendCmldrpRequestTcp(CMLDRP_Block * pBlock) +{ + IOStatus status; + int returnValue = 0; + + status = writeToOutputStream(pBlock->outputStream, + pBlock->ioBuffer, outputLength(pBlock)); + if (status == IOStatusOk) + status = flushOutputStream(pBlock->outputStream); + + if (IOStatusOk != status) { + char buf[180]; + const char *ioStatusString; + struct in_addr *inAddr; + struct sockaddr_in *addr; + + addr = pBlock->nextServerToContact; + inAddr = (struct in_addr *) &addr->sin_addr.s_addr; + + ioStatusString = getIOStatusString(status); + + sprintf(buf, + "CMLDRP(TCP) Error writing to Load Manager=%s:%d, io status=%s", + inet_ntoa(*inAddr), ntohs(addr->sin_port), ioStatusString); + + gCMLDRPBlock.logFunction(gCMLDRPBlock.logShellData, kLog_Error, + kLogMessage_OneString, buf, NULL); + + returnValue = -1; + } + return returnValue; +} +#endif + +/** + * checkResponseType + * Check that the response type for this was set + * return: 0 == success; !0 == failure + */ +static int checkResponseType(CMLDRP_Block * pBlock) +{ + unsigned short responseType; + struct sockaddr_in *contactServer = pBlock->nextServerToContact; + + /* make sure the response has the response indicator set */ + memcpy(&responseType, &pBlock->ioBuffer[kCMLDRP_ResponseTypeOffset], + sizeof(responseType)); + if (ntohs(responseType) != kCMLDRP_ResponseType) { + char portNumber[8]; + struct in_addr *inAddr; + + sprintf(portNumber, "%d", ntohs(contactServer->sin_port)); + inAddr = (struct in_addr *) &contactServer->sin_addr.s_addr; + gCMLDRPBlock.logFunction(gCMLDRPBlock.logShellData, kLog_Warn, + kLogMessage_BadCMLDRPResponseType, + inet_ntoa(*inAddr), portNumber); + return -1; + } + return 0; +} + + +/** + * receiveCmldrpResponseUdp + * Receive a CMLDRP response via UDP + * return: 0 == success; !0 == failure + */ +int receiveCmldrpResponseUdp(CMLDRP_Block * pBlock) +{ + int returnValue = 0; + fd_set readSet; + int nfds; + unsigned short requestSequence = pBlock->sequenceNumber; + unsigned short responseSequence = !requestSequence; + /*unsigned short requestType = kCMLDRP_RequestType; */ + struct sockaddr_in *contactServer = pBlock->nextServerToContact; + + do { + /* receive into response buffer */ + FD_ZERO(&readSet); + FD_SET(pBlock->sock, &readSet); + nfds = (int) pBlock->sock + 1; + if (select(nfds, &readSet, NULL, NULL, &pBlock->timeout) > 0) { + /* ready to read */ + size_t serverAddrSize = sizeof(*(pBlock->nextServerToContact)); + int bytesReceived = + recvfrom(pBlock->sock, pBlock->ioBuffer, + kCMLDRP_IOBufferSize, 0, + (struct sockaddr *) pBlock->nextServerToContact, + &serverAddrSize); + if ((bytesReceived == SOCKET_ERROR) || (bytesReceived <= 0)) { + returnValue = -1; + goto CMLDRP_RESPONSE_EXIT; + } + + returnValue = checkResponseType(pBlock); + + if (returnValue) + goto CMLDRP_RESPONSE_EXIT; + + /* check sequence number - if it's a match, use the response data, + otherwise discard and see if another packet arrived from the + CMLDRP server */ + memcpy(&responseSequence, + &pBlock->ioBuffer[kCMLDRP_ResponseSequenceOffset], + sizeof(responseSequence)); + responseSequence = ntohs(responseSequence); + if (responseSequence == requestSequence) { + /* dispatchRepsonseMetaData: will internalize CMLDRP flags, next + CMLDRP server to contact, etc; returns !0 if OK to dispatch + remaining response data (i.e. DRP server contact info) */ + if (dispatchResponseMetaData(pBlock, bytesReceived)) { + returnValue = + dispatchResponseData(pBlock, bytesReceived); + if (returnValue == 0) + /* increment info version so service threads can see there's new + load data available */ + gCMLDRP_InfoVersion++; + } + } + } else { + /* not ready to read */ + char portNumber[8]; + struct in_addr *inAddr; + + if (time(NULL) > + pBlock->lastTimeSilenceReported + + kSilentCMLDRPLogInterval) { + /* we've been trying to contact this CMLDRP server for more than + k..Interval seconds (or this is the first failure) */ + sprintf(portNumber, "%d", ntohs(contactServer->sin_port)); + inAddr = + (struct in_addr *) &contactServer->sin_addr.s_addr; + if (pBlock->lastTimeSilenceReported > 0) + gCMLDRPBlock.logFunction(gCMLDRPBlock.logShellData, + kLog_Warn, + kLogMessage_NoCMLDRPResponsePeriod, + inet_ntoa(*inAddr), + portNumber); + else + gCMLDRPBlock.logFunction(gCMLDRPBlock.logShellData, + kLog_Warn, + kLogMessage_NoCMLDRPResponseFirst, + inet_ntoa(*inAddr), + portNumber); + pBlock->lastTimeSilenceReported = time(NULL); + } + returnValue = -1; + goto CMLDRP_RESPONSE_EXIT; + } + } while (responseSequence != requestSequence); + + CMLDRP_RESPONSE_EXIT: + + return returnValue; +} + +#ifdef _DRP_MTHREAD +/** + * receiveCmldrpResponseTcp + * Send a CMLDRP response via TCP + * return: 0 == success; !0 == failure + */ +int receiveCmldrpResponseTcp(CMLDRP_Block * pBlock) +{ + int returnValue = 0; + IOStatus status; + int read; + int bytesReceived = 0; + + status = readFromInputStream(pBlock->inputStream, + pBlock->ioBuffer, + kCMLDRP_BaseResponseSize, &read); + + if (IOStatusOk == status) { + unsigned short numRecords; + int recordsLength; + + bytesReceived = kCMLDRP_BaseResponseSize; + + /* Calculate the number of Dynamo records expected */ + memcpy(&numRecords, + &pBlock->ioBuffer[kCMLDRP_ResponseNumRecsOffset], + sizeof(numRecords)); + numRecords = ntohs(numRecords); + recordsLength = numRecords * kCMLDRP_LoadRecordSize; + + /* Read the Dynamo records */ + status = readFromInputStream(pBlock->inputStream, + &pBlock-> + ioBuffer + [kCMLDRP_ResponseRecordOffset], + recordsLength, &read); + if (IOStatusOk == status) + bytesReceived += recordsLength; + } + + if (IOStatusOk != status) { + char buf[180]; + const char *ioStatusString = getIOStatusString(status); + struct in_addr *inAddr; + struct sockaddr_in *addr; + + addr = pBlock->nextServerToContact; + inAddr = (struct in_addr *) &addr->sin_addr.s_addr; + + sprintf(buf, + "CMLDRP(TCP) Error reading from Load Manager=%s:%d, io status=%s", + inet_ntoa(*inAddr), ntohs(addr->sin_port), ioStatusString); + + gCMLDRPBlock.logFunction(gCMLDRPBlock.logShellData, kLog_Error, + kLogMessage_OneString, buf, NULL); + + returnValue = -1; + } + + if (0 == returnValue) + returnValue = checkResponseType(pBlock); + + if (0 == returnValue) { + +#ifdef DEBUG + { + char buf[20]; + int i; + + for (i = 0; i < bytesReceived; i++) { + sprintf(buf, "byte[%d] == %u", i, pBlock->ioBuffer[i]); + gCMLDRPBlock.logFunction(gCMLDRPBlock.logShellData, + kLog_Warn, kLogMessage_OneString, + buf, NULL); + } + } +#endif + + if (dispatchResponseMetaData(pBlock, bytesReceived)) { + returnValue = dispatchResponseData(pBlock, bytesReceived); + if (returnValue == 0) + /* increment info version so service threads can see there's new + load data available */ + gCMLDRP_InfoVersion++; + } + } + + return returnValue;; +} +#endif + +/** + * cmldrpUpdate + * Attempt to update locally held DRP server load information by + * contacting a CMLDRP server + * return: 0 == success; !0 == failure + */ +int cmldrpUpdate(CMLDRP_Block * pBlock) +{ + int returnValue = 0; + unsigned short requestSequence = pBlock->sequenceNumber; + unsigned short requestType = kCMLDRP_RequestType; + +#ifdef _DRP_MTHREAD + if (gCMLDRP_UseTcp) { + if (connectToNextCMLDRPServer(pBlock)) { + returnValue = -1; + goto CMLDRP_UPDATE_EXIT; + } + } +#endif + + /* set up request buffer */ + *((unsigned short *) &pBlock->ioBuffer[kCMLDRP_RequestVersionOffset]) = + htons(pBlock->cmldrpVersion); + *((unsigned short *) &pBlock->ioBuffer[kCMLDRP_RequestTypeOffset]) = + htons(requestType); + *((unsigned short *) &pBlock-> + ioBuffer[kCMLDRP_RequestSequenceOffset]) = htons(requestSequence); + *((unsigned short *) &pBlock-> + ioBuffer[kCMLDRP_RequestIDLengthOffset]) = +htons(pBlock->identifierLength); + strncpy(&(pBlock->ioBuffer[kCMLDRP_RequestIDOffset]), + pBlock->identifier, pBlock->identifierLength); + +#ifdef _DRP_MTHREAD + if ((gCMLDRP_UseTcp == 0) ? + sendCmldrpRequestUdp(pBlock) : sendCmldrpRequestTcp(pBlock)) +#else + if (sendCmldrpRequestUdp(pBlock)) +#endif + { + returnValue = -1; + goto CMLDRP_UPDATE_EXIT; + } +#ifdef _DRP_MTHREAD + if (0 == gCMLDRP_UseTcp) + returnValue = receiveCmldrpResponseUdp(pBlock); + else + returnValue = receiveCmldrpResponseTcp(pBlock); +#else + returnValue = receiveCmldrpResponseUdp(pBlock); +#endif + + CMLDRP_UPDATE_EXIT: + +#ifdef _DRP_MTHREAD + if (gCMLDRP_UseTcp) + closeCMLDRPConnection(pBlock); +#endif + + pBlock->sequenceNumber++; + + return returnValue; +} + + +/** + * dispatchResponseMetaData + * parse general information from the CMLDRP server's response (i.e. only + * information not pertaining to DRP servers). + * return: 0 == do NOT dispatch remaining response data; + * >0 == do dispatch remaining response data; + * <0 == error + */ +static int +dispatchResponseMetaData(CMLDRP_Block * pBlock, int iBytesReceived) +{ + int returnValue = 0; + unsigned short cmldrpFlags; + unsigned long nextManagerHost; + unsigned short nextManagerPort; + unsigned short numRecords; + + if (iBytesReceived < kCMLDRP_BaseResponseSize) { + returnValue = -1; + +#ifdef DEBUG + gCMLDRPBlock.logFunction(gCMLDRPBlock.logShellData, kLog_Info, + kLogMessage_OneString, + "dispatchResponseMetaData received to view bytes", + NULL); +#endif + goto DISPATCH_META_DATA_EXIT; + } + + /* extract cmldrp flags from response */ + memcpy(&cmldrpFlags, &pBlock->ioBuffer[kCMLDRP_ResponseFlagsOffset], + sizeof(cmldrpFlags)); + cmldrpFlags = ntohs(cmldrpFlags); + + /* extract next-manager-to-contact info from response */ + memcpy(&nextManagerHost, + &pBlock->ioBuffer[kCMLDRP_ResponseNextHostOffset], + sizeof(nextManagerHost)); + memcpy(&nextManagerPort, + &pBlock->ioBuffer[kCMLDRP_ResponseNextPortOffset], + sizeof(nextManagerPort)); + nextManagerPort = ntohs(nextManagerPort); + + /* extract number of DRP records and check against bytes received */ + memcpy(&numRecords, &pBlock->ioBuffer[kCMLDRP_ResponseNumRecsOffset], + sizeof(numRecords)); + numRecords = ntohs(numRecords); + + if ((numRecords * kCMLDRP_LoadRecordSize + kCMLDRP_BaseResponseSize != + iBytesReceived) || (numRecords > kMaxDRPRecords)) { + returnValue = -1; + +#ifdef DEBUG + gCMLDRPBlock.logFunction(gCMLDRPBlock.logShellData, kLog_Info, + kLogMessage_OneString, + "dispatchResponseMetaData bad load record size", + NULL); +#endif + goto DISPATCH_META_DATA_EXIT; + } + + /* set some local fields w/ response data */ + pBlock->cmldrpFlags = cmldrpFlags; + + /* + * This is an option put in for kodak, but it might be useful generally. + * If this option is set to false, we ignore the load manager that the + * current LM wants us to poll and just keep on using our own heuristics. + * This feature is there so that if we have more than one load manager, we + * can revert back to using the original primary after it comes back up. + * + * Kodak, though, has a proxy server so the IP address that the LM thinks + * it is, is not the right one. + */ + if (gCMLDRP_ManagerRotationEnabled) { + /* set next CMLDRP server to contact */ + pBlock->tempCMLDRPServer.sin_family = AF_INET; + pBlock->tempCMLDRPServer.sin_port = ntohs(nextManagerPort); + pBlock->tempCMLDRPServer.sin_addr.s_addr = nextManagerHost; + if (memcmp(pBlock->nextServerToContact, &pBlock->tempCMLDRPServer, + sizeof(pBlock->tempCMLDRPServer))) { + /* only reset lastTimeSilenceReported if nextServerToContact changes */ + pBlock->lastTimeSilenceReported = 0; + } + pBlock->nextServerToContact = &pBlock->tempCMLDRPServer; + } + + /* if CMLDRP server indicates it is finished w/ initialization, return + >0, to force internalization of DRP server response data */ + if (cmldrpFlags & kCMLDRPFlags_Initialized) + returnValue = 1; + else { + /* CMLDRP server still initializing; set next polltime to minimum + polltime */ + pBlock->nextUpdateTime = time(NULL) + kCMLDRP_MinimumPollInterval; + +#ifdef DEBUG + gCMLDRPBlock.logFunction(gCMLDRPBlock.logShellData, kLog_Info, + kLogMessage_OneString, + "setting nextUpdateTime - not initialized", + NULL); +#endif + } + + DISPATCH_META_DATA_EXIT: + + return returnValue; +} + + + +/** + * dispatchResponseData + * Copy data from a CMLDRP server's response into local structures + * return: 0 == success; !0 == failure + */ +static int dispatchResponseData(CMLDRP_Block * pBlock, int iBytesReceived) +{ + int returnValue = 0; + unsigned short cmldrpVersion; + unsigned short pollInterval; + unsigned short numRecords; + int l; + int recordOffset; + int r; + + if (iBytesReceived < kCMLDRP_BaseResponseSize) { + returnValue = -1; + goto DISPATCH_RESP_DATA_EXIT; + } + + memcpy(&cmldrpVersion, + &pBlock->ioBuffer[kCMLDRP_ResponseVersionOffset], + sizeof(cmldrpVersion)); + cmldrpVersion = ntohs(cmldrpVersion); + + memcpy(&pollInterval, + &pBlock->ioBuffer[kCMLDRP_ResponseIntervalOffset], + sizeof(pollInterval)); + pollInterval = ntohs(pollInterval); + + memcpy(&numRecords, &pBlock->ioBuffer[kCMLDRP_ResponseNumRecsOffset], + sizeof(numRecords)); + numRecords = ntohs(numRecords); + + pBlock->pollInterval = pollInterval; + pBlock->nextUpdateTime = time(NULL) + pollInterval; + +#ifdef _DRP_MTHREAD + { + int result; + do { + result = + getWriteLock(&gLoadDataLock, kRWL_DefaultWriteTimeout); + } while (result != 0 && !gCMLDRP_Shutdown); + if (gCMLDRP_Shutdown) + return 0; + } +#endif + + /* at this point we've decided the data packet is legit */ + /* mark all known servers inactive; after we've absorbed all the + per-drp-server data (below), all servers marked as active will have + data from the CMLDRP server, and any servers not mentioned by + CMLDRP server will be marked inactive */ + for (r = 0; r < gNumDrpServers; r++) { + gDrpServers[r].flags &= ~kDrpServerFlags_Active; + } + + for (l = 0, recordOffset = kCMLDRP_ResponseRecordOffset; + l < numRecords; l++, recordOffset += kCMLDRP_LoadRecordSize) { + drpServerRecord record; + drpServerRecord *recordPtr; + drpServerRecord **match; + + memset(&record, 0, sizeof(record)); + + memcpy(&record.inetaddr, + &pBlock->ioBuffer[recordOffset + kCMLDRP_RecordHostOffset], + sizeof(record.inetaddr)); + memcpy(&record.port, + &pBlock->ioBuffer[recordOffset + kCMLDRP_RecordPortOffset], + sizeof(record.port)); + record.port = ntohs(record.port); + memcpy(&record.probability, + &pBlock->ioBuffer[recordOffset + kCMLDRP_RecordProbOffset], + sizeof(record.probability)); + record.probability = ntohs(record.probability); + memcpy(&record.flags, + &pBlock->ioBuffer[recordOffset + kCMLDRP_RecordFlagsOffset], + sizeof(record.flags)); + record.flags = ntohs(record.flags); + /* + * Mark this server as active. We don't have + */ + record.flags |= kDrpServerFlags_Active; + + /* look up record in list of record ptrs */ + recordPtr = &record; + match = bsearch(&recordPtr, gDrpServerPtrs, gNumDrpServers, + sizeof(recordPtr), compareDRPServerRecPtrs_ipPort); + if (match) { + (*match)->probability = record.probability; + (*match)->flags = record.flags; + } else { + drpServerRecord *newServer = &(gDrpServers[gNumDrpServers]); + newServer->probability = record.probability; + newServer->flags = record.flags; + newServer->inetaddr = record.inetaddr; + newServer->port = record.port; + newServer->sock = kInvalidSocket; + + gDrpServerPtrs[gNumDrpServers] = newServer; + + gNumDrpServers++; + + /* must now sort new record into the list of pointers */ + qsort(gDrpServerPtrs, gNumDrpServers, sizeof(recordPtr), + compareDRPServerRecPtrs_ipPort); + +#ifdef _CPOOL + /* initialize the connection pool for this server */ + if (gCP_Enabled) { + newServer->pool = malloc(sizeof(connectionPool)); + initializeCP(newServer->pool); + } +#endif + } + } + +#ifdef _DRP_MTHREAD + releaseWriteLock(&gLoadDataLock); +#endif + + if (gCMLDRPBlock.debugEnabled) { + char buf[1024]; + int i; + + if (pBlock->nextServerToContact != NULL) { + struct in_addr *inAddr = + (struct in_addr *) &pBlock->nextServerToContact->sin_addr. + s_addr; + sprintf(buf, + "updating %d servers - next lm=%s:%d%s - num request threads=%d", + gNumDrpServers, inet_ntoa(*inAddr), + ntohs(pBlock->nextServerToContact->sin_port), + (gCMLDRP_ManagerRotationEnabled == + 0) ? " (load manager rotation disabled)" : "", + gDebugInfo.numRequestThreads); + } else + sprintf(buf, + "updating %d servers - next lm=null - num request threads=%d", + gNumDrpServers, gDebugInfo.numRequestThreads); + gCMLDRPBlock.logFunction(gCMLDRPBlock.logShellData, kLog_Info, + kLogMessage_OneString, buf, NULL); + + sprintf(buf, + "num active requests=%d - num waiting on lock=%d - num waiting on pool=%d - num waiting to connect=%d - num sending request=%d, num waiting for response=%d", + gDebugInfo.numActiveRequests, + gDebugInfo.numWaitingOnReadLock, + gDebugInfo.numWaitingOnPool, + gDebugInfo.numWaitingToConnect, + gDebugInfo.numSendingRequest, + gDebugInfo.numWaitingForResponse); + gCMLDRPBlock.logFunction(gCMLDRPBlock.logShellData, kLog_Info, + kLogMessage_OneString, buf, NULL); + + for (i = 0; i < gNumDrpServers; i++) { + sprintf(buf, "server %ld.%ld.%ld.%ld port=%d prob=%d flags=%d", + gDrpServerPtrs[i]->inetaddr & 0xff, + (gDrpServerPtrs[i]->inetaddr >> 8) & 0xff, + (gDrpServerPtrs[i]->inetaddr >> 16) & 0xff, + (gDrpServerPtrs[i]->inetaddr >> 24) & 0xff, + gDrpServerPtrs[i]->port, + gDrpServerPtrs[i]->probability, + gDrpServerPtrs[i]->flags); + gCMLDRPBlock.logFunction(gCMLDRPBlock.logShellData, kLog_Info, + kLogMessage_OneString, buf, NULL); + } + } + + DISPATCH_RESP_DATA_EXIT: + + return returnValue; +} + + +/** + * compareDRPServerRecords_ipPort + * (for use with qsort, bsearch) + * compares two drpServerRecord objects first by IP address, then by port. + * return: <0 : iRec1 < iRec2 + * 0 : iRec1 == iRec2 + * >0 : iRec1 > iRec2 + */ +/* NOTE: Currently not used so not defined. - Frank Kim, 12/28/99 (lmd 3/24/00)*/ +#if 0 +int compareDRPServerRecords_ipPort(const void *iRec1, const void *iRec2) +{ + drpServerRecord *rec1 = (drpServerRecord *) iRec1; + drpServerRecord *rec2 = (drpServerRecord *) iRec2; + + if (rec1->inetaddr < rec2->inetaddr) + return -1; + if (rec1->inetaddr > rec2->inetaddr) + return 1; + + if (rec1->port < rec2->port) + return -1; + if (rec1->port > rec2->port) + return 1; + + return 0; +} +#endif + +/** + * compareDRPServerRecPtrs_ipPort + * (for use with qsort, bsearch) + * compares two _pointers to_ drpServerRecord objects first by IP address, + * then by port. + * return: <0 : *iRec1 < *iRec2 + * 0 : *iRec1 == *iRec2 + * >0 : *iRec1 > *iRec2 + */ +int compareDRPServerRecPtrs_ipPort(const void *iPtr1, const void *iPtr2) +{ + drpServerRecord **ptr1 = (drpServerRecord **) iPtr1; + drpServerRecord **ptr2 = (drpServerRecord **) iPtr2; + + if ((*ptr1)->inetaddr < (*ptr2)->inetaddr) + return -1; + if ((*ptr1)->inetaddr > (*ptr2)->inetaddr) + return 1; + + if ((*ptr1)->port < (*ptr2)->port) + return -1; + if ((*ptr1)->port > (*ptr2)->port) + return 1; + + return 0; +} + + +/** + * openUDPSocket + * Establish a UDP datagram socket for use in obtaining load information + * from CMLDRP server(s). + * pBlock: CMLDRP information block + * iBindAddress: if present, bind the datagram socket to the address + * indicated; if NULL, bind to any appropriate network interface + * return: 0 == success; !0 == failure + */ +static int openUDPSocket(CMLDRP_Block * pBlock, const char *iBindAddress) +{ + int returnValue = 0; + struct sockaddr_in clientAddr; /* host of current process */ + + if ((pBlock->sock = socket(AF_INET, SOCK_DGRAM, 0)) == kInvalidSocket) { + returnValue = -1; + goto OPEN_UDP_EXIT; + } + + memset(&clientAddr, 0, sizeof(clientAddr)); + clientAddr.sin_family = AF_INET; + clientAddr.sin_port = htons(0); + if (iBindAddress) { + /* Parse out the potential "name:port" value */ + char tmpAddress[256]; + char *port; + strcpy(tmpAddress, iBindAddress); + port = strchr(tmpAddress, ':'); + if (port != NULL) { + *port = '\0'; + port++; + clientAddr.sin_port = (short) atoi(port); + clientAddr.sin_port = htons(clientAddr.sin_port); + } + /* bind to specific address (for multi-homed hosts) */ + clientAddr.sin_addr.s_addr = hostToInetAddr(tmpAddress); + + { + char buf[256]; + sprintf(buf, "Binding to specified local address: %s:%d", + tmpAddress, (int) ntohs(clientAddr.sin_port)); + pBlock->logFunction(pBlock->logShellData, kLog_Info, + kLogMessage_OneString, buf, NULL); + } + } else { + /* bind to any local address (for single-homed hosts, or if user d/n + care which network interface is used) */ + clientAddr.sin_addr.s_addr = htonl(INADDR_ANY); + } + + if (bind(pBlock->sock, (struct sockaddr *) &clientAddr, + sizeof(clientAddr))) { + returnValue = -1; + goto OPEN_UDP_EXIT; + } + + OPEN_UDP_EXIT: + + return returnValue; +} + +#ifdef _DRP_MTHREAD +/** + * connectToNextCMLDRPServer + * Connect to a CMLDRP server using TCP + * pBlock: CMLDRP information block + * return: 0 == success; !0 == failure + */ +int connectToNextCMLDRPServer(CMLDRP_Block * pBlock) +{ + struct sockaddr_in *addr = pBlock->nextServerToContact; + IOStatus status; + int returnValue = 0; + +#ifdef WIN32 + status = createSocketIOStreamsFromAddressWithTimeout((*addr), + gCMLDRP_TcpTimeout, + &(pBlock-> + inputStream), + &(pBlock-> + outputStream)); +#else + status = createSocketIOStreamsFromAddressWithBlocking((*addr), + &(pBlock-> + inputStream), + &(pBlock-> + outputStream)); +#endif + + if (IOStatusOk != status || + pBlock->inputStream == NULL || pBlock->outputStream == NULL) { + + if (time(NULL) > + pBlock->lastTimeSilenceReported + kSilentCMLDRPLogInterval) { + char buf[180]; + const char *ioStatusString = getIOStatusString(status); + struct in_addr *inAddr; + + inAddr = (struct in_addr *) &addr->sin_addr.s_addr; + + sprintf(buf, + "CMLDRP(TCP) Failure to connect via TCP to Load Manager=%s:%d, io status=%s", + inet_ntoa(*inAddr), + ntohs(addr->sin_port), ioStatusString); + + gCMLDRPBlock.logFunction(gCMLDRPBlock.logShellData, kLog_Error, + kLogMessage_OneString, buf, NULL); + pBlock->lastTimeSilenceReported = time(NULL); + } + returnValue = -1; + } + + return returnValue; +} + +/** + * closeCMLDRPConnection + * Close a TCP connection to a CMLDRP server + * pBlock: CMLDRP information block + */ +void closeCMLDRPConnection(CMLDRP_Block * pBlock) +{ + + if (pBlock->inputStream) + destroyInputStream(pBlock->inputStream); + + if (pBlock->outputStream) + destroyOutputStream(pBlock->outputStream); + return; +} +#endif + +/** + * selectNextCMLDRPServer + * Determines which known CMLDRP server should be next to contact; to be + * invoked in case of lack of response from the current CMLDRP server. + * return: 0 == success; !0 == failure + */ +int selectNextCMLDRPServer(CMLDRP_Block * pBlock) +{ + int returnValue = 0; + +#ifdef DEBUG + char dbgBuf[64]; + sprintf(dbgBuf, "num of CMLDRPServers: %d", pBlock->numCMLDRPServers); + pBlock->logFunction(pBlock->logShellData, kLog_Info, + kLogMessage_OneString, dbgBuf, NULL); + sprintf(dbgBuf, "next Server to Contact index: %d", + pBlock->nextServerToContactIdx); + pBlock->logFunction(pBlock->logShellData, kLog_Info, + kLogMessage_OneString, dbgBuf, NULL); +#endif + + pBlock->nextServerToContactIdx = + (pBlock->nextServerToContactIdx + 1) % pBlock->numCMLDRPServers; + if (pBlock->numCMLDRPServers > 1) + pBlock->lastTimeSilenceReported = 0; + + pBlock->nextServerToContact = + &(pBlock->cmldrpServers[pBlock->nextServerToContactIdx]); + + return returnValue; +} + + +/** + * getDrpServerRecord + * Given a list of DRP server records and an address-port combination, + * finds the server record (if any) in the list with that addr-port. + * return: NULL if no matching record found + */ +drpServerRecord **getDrpServerRecord(const drpServerRecord ** iServerPtrs, + int iNumServers, unsigned long iAddr, + unsigned short iPort) +{ + drpServerRecord record; + drpServerRecord *recordPtr = &record; + + memset(&record, 0, sizeof(record)); + record.inetaddr = iAddr; + record.port = iPort; + + return bsearch(&recordPtr, iServerPtrs, iNumServers, sizeof(recordPtr), + compareDRPServerRecPtrs_ipPort); +} + + +/** + * parseDynamoManagers + * Given list of Dynamo Managers (i.e. CMDLRP servers), builds and returns + * a list of CMLDRP_ServerInfo objects containing contact information for + * the CMLDRP servers specified. + * iDynamoManagers: expected format is: + * {host}:{port},{host}:{port},... + * oNumServers: on exit, contains the number of server records in the + * list returned. + * + * NB: modifies iDynamoManagers in place + * NB: allocates data + */ +CMLDRP_ServerInfo *parseDynamoManagers(char *iDynamoManagers, + int *oNumServers) +{ + int numCommas; + char *tempPtr; + char *nextPtr; + char *portPtr; + CMLDRP_ServerInfo *serverData = NULL; + + /* first: get max number of servers in list by counting commas */ + for (tempPtr = iDynamoManagers, numCommas = 0; tempPtr;) { + tempPtr = strchr(tempPtr, kChar_Comma); + if (tempPtr) { + tempPtr++; + numCommas++; + } + } + + serverData = (CMLDRP_ServerInfo *) + malloc(sizeof(CMLDRP_ServerInfo) * (numCommas + 1)); + + /* second: populate the server records */ + + tempPtr = iDynamoManagers; + *oNumServers = 0; + + while (tempPtr && (*tempPtr != kChar_Null)) { + nextPtr = strchr(tempPtr, kChar_Comma); + if (nextPtr) + *nextPtr++ = kChar_Null; /* terminate this host[:port] entry */ + + portPtr = strchr(tempPtr, kChar_Colon); + if (portPtr) + *portPtr++ = kChar_Null; /* terminate this host entry */ + + serverData[*oNumServers].host = (char *) + malloc(sizeof(char) * (strlen(tempPtr) + 1)); + strcpy(serverData[*oNumServers].host, tempPtr); + serverData[*oNumServers].port = + (portPtr ? atoi(portPtr) : kCMLDRP_DefaultCMLDRPPort); + + (*oNumServers)++; + + tempPtr = nextPtr; + } + + return serverData; +} + + +/** + * cmldrpShutdown() + * Cause the CMLDRP thread, if active, to stop + * + * On ISAPI, the inetinfo process would die during shutdown sometimes + * without the loop and the IsRunning flag. This seems to fix this problem. + */ +void cmldrpShutdown(void) +{ + gCMLDRP_Shutdown = 1; + +#ifdef _DRP_MTHREAD + do { + thread_sleep(kCMLDRP_Sleeptime * 2); + } while (gCMLDRP_ThreadIsRunning); +#endif +} + +#ifdef _DRP_MTHREAD +void setEnforceMaxHandlers(int flag) +{ + gEnforceMaxHandlers = flag; +} + +void setMaxHandlers(int count) +{ + gMaxHandlers = count; +} + +void setBackoffInterval(time_t interval) +{ + gBackoffInterval = interval; +} + +/** + * Returns 0 if this thread can be a handler, otherwize + * it can return non-zero + */ +int acquireHandler() +{ + int returnValue = -1; + + if (!gEnforceMaxHandlers) { + return 0; + } else { + if (0 == getWriteLock(&gHandlerCountLock, kDefaultHandlersTimeout)) { + + if (gExceededLimit) { + time_t now = time(NULL); + + /* Log an error at intervals */ + if (now > + gLastTimeThreadLimitReported + + kSilentCMLDRPLogInterval) { + char threadLimitReached[80]; + + sprintf(threadLimitReached, + "Dymamo handler limit reached = %d, backoff interval = %d seconds", + gMaxHandlers, gBackoffInterval); + gCMLDRPBlock.logFunction(gCMLDRPBlock.logShellData, + kLog_Error, + kLogMessage_OneString, + threadLimitReached, NULL); + gLastTimeThreadLimitReported = now; + } + + /* At intervals check to re-test the exceeded limit */ + /* Log an error at intervals */ + if (now > + (gLastTimeExceededLimitReached + gBackoffInterval)) { + if (gLastTimeExceededLimitReached > 0) { + char limitOver[80]; + sprintf(limitOver, + "Dymamo backoff interval over. limit = %d, backoff interval = %d seconds", + gMaxHandlers, gBackoffInterval); + gCMLDRPBlock.logFunction(gCMLDRPBlock.logShellData, + kLog_Info, + kLogMessage_OneString, + limitOver, NULL); + gExceededLimit = 0; + } + } + } + + if (!gExceededLimit) { + if (gHandlerCount < gMaxHandlers) { + gHandlerCount++; + returnValue = 0; + } else { + gLastTimeExceededLimitReached = time(NULL); + gExceededLimit = 1; + } + } + + releaseWriteLock(&gHandlerCountLock); + } + } + return returnValue; +} + +/** + * Release a handler. + */ +void releaseHandler() +{ + if (gEnforceMaxHandlers != 0) { + if (0 == getWriteLock(&gHandlerCountLock, kDefaultHandlersTimeout)) { + gHandlerCount--; + releaseWriteLock(&gHandlerCountLock); + } + } +} + +#endif diff --git a/mk4/moddynamo/CMLDRP.h b/mk4/moddynamo/CMLDRP.h new file mode 100644 index 0000000..bf62354 --- /dev/null +++ b/mk4/moddynamo/CMLDRP.h @@ -0,0 +1,279 @@ +/* + * Copyright (C) 1997 Art Technology Group, Inc. + * All Rights Reserved. No use, copying or distribution of this + * work may be made except in accordance with a valid license + * agreement from Art Technology Group. This notice must be + * included on all copies, modifications and derivatives of this + * work. + * + * Art Technology Group (ATG) MAKES NO REPRESENTATIONS OR WARRANTIES + * ABOUT THE SUITABILITY OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. ATG SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, + * MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. + * + * "Dynamo" is a trademark of Art Technology Group, Inc. + */ + +/* + CMLDRP.h - interface for CMLDRP subsystem + ("Connection-Module Load-Distribution Request Protocol", or something) + */ + + +#ifndef _CMLDRP_H_ +#define _CMLDRP_H_ + +#include + +#ifdef WIN32 +/* NT */ +#include +#else +/* UNIXen */ +#include +#include +#include +#include +#include +#ifdef _IRIX +#include +#endif +#ifdef SOLARIS2_6 +#include +#endif +#endif + +#include "DRPTypes.h" +#include "DRPClient.h" + +#ifdef _DRP_MTHREAD +#include "rwLocks.h" + +extern RWLock gLoadDataLock; /* defined in CMLDRP.c */ +void setEnforceMaxHandlers(int flag); +void setMaxHandlers(int count); +void setBackoffInterval(time_t interval); +int acquireHandler(); +void releaseHandler(); + +#include "io.h" /* libw3 io.h */ +#define kCMLDRP_DefaultTcpTimeout 10000 /* milliseconds */ +#endif + + +#define kCMLDRP_DefaultTimeoutSec 3 +#define kCMLDRP_DefaultTimeoutUsec 0 + + +/* + * These intervals used to be 1 second for the minimum poll interval and + * 250 msec for the SleepTime. I believe that this is because of the + * forceUpdateCM stuff in DRPClient.c which does not work anyway. + * + * Instead, I think we should sleep slightly longer than the min poll + * interval so that we end up waking up, polling, sleeping, waking up polling + * etc. + */ +#define kCMLDRP_MinimumPollInterval 2 /* seconds */ + +#define kCMLDRP_Sleeptime 2500 /* milliseconds */ + +#define kCMLDRP_MaxIdentifierLength 48 /* includes some extra */ +#define kCMLDRP_MaxHttpHostLength 18 + + +#define kCMLDRP_IOBufferSize 1064 /* 1018 is large enough for 100 records */ +#define kCMLDRP_MaxCMLDRPRecords kMaxDRPRecords +#define kCMLDRP_BaseResponseSize 18 +#define kCMLDRP_LoadRecordSize 10 + + +#define kCMLDRP_RequestVersion 1 + + +/* offsets into request buffer */ +#define kCMLDRP_RequestVersionOffset 0 +#define kCMLDRP_RequestTypeOffset 2 +#define kCMLDRP_RequestSequenceOffset 4 +#define kCMLDRP_RequestIDLengthOffset 6 +#define kCMLDRP_RequestIDOffset 8 + +/* offsets into response buffer */ +#define kCMLDRP_ResponseVersionOffset 0 +#define kCMLDRP_ResponseTypeOffset 2 +#define kCMLDRP_ResponseSequenceOffset 4 +#define kCMLDRP_ResponseFlagsOffset 6 +#define kCMLDRP_ResponseNextHostOffset 8 +#define kCMLDRP_ResponseNextPortOffset 12 +#define kCMLDRP_ResponseIntervalOffset 14 +#define kCMLDRP_ResponseNumRecsOffset 16 +#define kCMLDRP_ResponseRecordOffset 18 + +/* offsets into load records in a buffer */ +#define kCMLDRP_RecordHostOffset 0 +#define kCMLDRP_RecordPortOffset 4 +#define kCMLDRP_RecordProbOffset 6 +#define kCMLDRP_RecordFlagsOffset 8 + + +#define kCMLDRP_RequestType 0xDABA +#define kCMLDRP_ResponseType 0xABBA + + +#define kCMLDRP_DefaultCMLDRPPort 8890 + + +#define kDrpServerFlags_Active 0x0002 +#define kDrpServerFlags_AcceptingNewSessions 0x0001 +#define kDrpServerFlags_Overloaded 0x0004 +#define kDrpServerFlags_SeemsDown 0x0008 + +#define kCMLDRPFlags_Initialized 0x0001 + + +#ifndef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN 256 +#endif + +#ifndef SOCKET_ERROR +#define SOCKET_ERROR -1 +#endif + +/* +** The standard C library function getpid() returns the current +** process id. In the WIN32 API the equivalent function is _getpid(). +*/ + +#ifdef WIN32 +#ifndef getpid +#define getpid _getpid +#endif +#endif + +typedef struct _CMLDRP_ServerInfo CMLDRP_ServerInfo; +typedef struct _CMLDRP_Block CMLDRP_Block; + +/* CMLDRP_ServerInfo: associates the host name with a port for a single + CMLDRP server */ +struct _CMLDRP_ServerInfo { + char * host; + unsigned short port; +}; + + +/* CMLDRP_Block: block of data maintained by the CMLDRP subsystem; in the + multithreaded case, an instance of this block will be associated with + the CMLDRP thread via thread-local-storage (see threadabstr.h) */ +struct _CMLDRP_Block { + socket_t sock; /* used for UDP port */ + +#ifdef _DRP_MTHREAD + InputStream *inputStream; /* used for TCP input stream */ + OutputStream *outputStream; /* used for TCP output stream */ +#endif + + /* numCMDLRPServers is number of records in cmldrpServers field; + cmldrpServers is the ordered collection of CMDLRP server info passed + in at init time + nextServerToContactIdx is index into cmldrpServers indicating next + CMLDRP server to contact for load info; a value of -1 indicates + that the 1st (0th) server should be used next + tempCMLDRPServer is a temporary storage place to hold CMLDRP server + contact info received from a CMLDRP server that is not already + present in the cmldrpServers field + nextServerToContact points to the sockaddr_in describing the next + CMLDRP server to contact for load information; could be pointing + at tempCMLDRPServer or into cmldrpServers + lastTimeSilenceReported indicates the time (in seconds since the epoch) + at which the CMLDRP system last logged the unavailability of the + server indicated by nextServerToContact or nextServerToContactIdx; + NB: this value MUST be reset to zero whenever nextServerToContact[Idx] + is updated. + */ + struct sockaddr_in cmldrpServers[kCMLDRP_MaxCMLDRPRecords]; + int numCMLDRPServers; + int nextServerToContactIdx; + struct sockaddr_in tempCMLDRPServer; + struct sockaddr_in * nextServerToContact; + time_t lastTimeSilenceReported; + + struct timeval timeout; + + char identifier[kCMLDRP_MaxIdentifierLength]; + unsigned short identifierLength; + + char httpHost[kCMLDRP_MaxHttpHostLength]; + unsigned short httpPort; + + unsigned short pollInterval; + + time_t nextUpdateTime; + + unsigned char ioBuffer[kCMLDRP_IOBufferSize]; + + unsigned short cmldrpVersion; + unsigned short cmldrpFlags; + + unsigned short sequenceNumber; + + LogMessage_fn logFunction; + void * logShellData; + + char debugEnabled; +}; + +extern CMLDRP_Block gCMLDRPBlock; +extern drpServerRecord gDrpServers[]; /* NB: not sorted */ +extern drpServerRecord * gDrpServerPtrs[]; /* NB: sorted by IP:addr */ +extern int gNumDrpServers; + +int cmldrpInitialize(int iNumServers, CMLDRP_ServerInfo * iServers, + const char * iBindAddress, unsigned short iHTTPPort, + LogMessage_fn iLogFunction, void * iLogShellData); +void cmldrpShutdown(); + +void cmldrpSetDebug(int pFlag); + +void cmldrpSetManagerRotationEnabled(int flag); + +/* signals shutdown to the CMLDRP thread (MT only) */ +extern unsigned short gCMLDRP_Shutdown; + +/* current version of DRP server load info */ +extern unsigned int gCMLDRP_InfoVersion; + +/* signals forced-update to CMLDRP thread (MT only) */ +extern unsigned short gCMLDRP_UpdateNow; + + +drpServerRecord ** getDrpServerRecord(const drpServerRecord ** iServerPtrs, + int iNumServers, unsigned long iAddr, + unsigned short iPort); +int compareDRPServerRecPtrs_ipPort(const void * iPtr1, const void * iPtr2); + +CMLDRP_ServerInfo * parseDynamoManagers(char * iDynamoManagers, + int * oNumServers); + +#ifndef _DRP_MTHREAD +int cmldrpUpdate_MP(CMLDRP_Block * pBlock); +#endif + + + +typedef struct _DebugInfo DebugInfo; + +/* _DebugInfo: information useful during debugging */ +struct _DebugInfo { + int numRequestThreads; + int numActiveRequests; + int numWaitingOnReadLock; + int numWaitingOnPool; + int numWaitingToConnect; + int numSendingRequest; + int numWaitingForResponse; +}; + +#endif + diff --git a/mk4/moddynamo/CVS/Entries b/mk4/moddynamo/CVS/Entries new file mode 100644 index 0000000..2008d03 --- /dev/null +++ b/mk4/moddynamo/CVS/Entries @@ -0,0 +1,23 @@ +/CMLDRP.c/1.2/Thu Mar 18 15:04:15 2004//Tmk4_mod6_rc2 +/CMLDRP.h/1.1/Fri Dec 12 15:08:04 2003//Tmk4_mod6_rc2 +/DRPClient.c/1.2/Thu Mar 18 15:04:15 2004//Tmk4_mod6_rc2 +/DRPClient.h/1.1/Fri Dec 12 15:08:04 2003//Tmk4_mod6_rc2 +/DRPServerIO.c/1.2/Thu Mar 18 15:04:15 2004//Tmk4_mod6_rc2 +/DRPServerIO.h/1.1/Fri Dec 12 15:08:04 2003//Tmk4_mod6_rc2 +/DRPTypes.h/1.1/Fri Dec 12 15:08:04 2003//Tmk4_mod6_rc2 +/DynSock.c/1.2/Thu Mar 18 15:04:15 2004//Tmk4_mod6_rc2 +/DynSock.h/1.1/Fri Dec 12 15:08:04 2003//Tmk4_mod6_rc2 +/Makefile/1.4/Tue Jun 22 14:36:14 2004//Tmk4_mod6_rc2 +/cmVersion.h/1.1/Fri Dec 12 15:08:04 2003//Tmk4_mod6_rc2 +/hook.c/1.12/Thu Mar 18 15:04:15 2004//Tmk4_mod6_rc2 +/io.c/1.2/Thu Mar 18 15:04:15 2004//Tmk4_mod6_rc2 +/io.h/1.1/Fri Dec 12 15:08:04 2003//Tmk4_mod6_rc2 +/pageroute.c/1.2/Thu Mar 18 15:04:15 2004//Tmk4_mod6_rc2 +/pageroute.h/1.1/Fri Dec 12 15:08:04 2003//Tmk4_mod6_rc2 +/rwLocks.h/1.1/Fri Dec 12 15:08:04 2003//Tmk4_mod6_rc2 +/sockerrs.c/1.2/Thu Mar 18 15:04:15 2004//Tmk4_mod6_rc2 +/sockerrs.h/1.1/Fri Dec 12 15:08:04 2003//Tmk4_mod6_rc2 +/system.h/1.1/Fri Dec 12 15:08:04 2003//Tmk4_mod6_rc2 +/threadabstr.c/1.2/Thu Mar 18 15:04:15 2004//Tmk4_mod6_rc2 +/threadabstr.h/1.1/Fri Dec 12 15:08:04 2003//Tmk4_mod6_rc2 +D diff --git a/mk4/moddynamo/CVS/Repository b/mk4/moddynamo/CVS/Repository new file mode 100644 index 0000000..837e5b0 --- /dev/null +++ b/mk4/moddynamo/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/moddynamo diff --git a/mk4/moddynamo/CVS/Root b/mk4/moddynamo/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/moddynamo/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/moddynamo/CVS/Tag b/mk4/moddynamo/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/moddynamo/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/moddynamo/DRPClient.c b/mk4/moddynamo/DRPClient.c new file mode 100644 index 0000000..1345da3 --- /dev/null +++ b/mk4/moddynamo/DRPClient.c @@ -0,0 +1,3050 @@ +/* + * Copyright (C) 1997 Art Technology Group, Inc. + * All Rights Reserved. No use, copying or distribution of this + * work may be made except in accordance with a valid license + * agreement from Art Technology Group. This notice must be + * included on all copies, modifications and derivatives of this + * work. + * + * Art Technology Group (ATG) MAKES NO REPRESENTATIONS OR WARRANTIES + * ABOUT THE SUITABILITY OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. ATG SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, + * MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. + * + * "Dynamo" is a trademark of Art Technology Group, Inc. + */ + +/* + DRPClient.c - DRP client functionality + */ + +/* #define DEBUG */ + + +#ifdef WIN32 +/* NT */ +#include + +#define EINTR WSAEINTR +#define ETIMEDOUT WSAETIMEDOUT + +#else +/* UNIXen */ +#include +#include +#include +#include +#include +#include + +#ifndef _DRP_MTHREAD +# include +#endif + +#define closesocket(s) close(s) /* to match NT closesocket() routine */ +#endif + + +#include +#include +#include +#include + + +#include "DRPClient.h" +#include "DRPServerIO.h" + +#include "CMLDRP.h" + +#include "pageroute.h" + +#include "rwLocks.h" + +extern int errno; +extern DebugInfo gDebugInfo; + +#ifdef _CPOOL +extern unsigned short gCP_Enabled; +#endif + +/* The number of seconds that singly threaded web servers wait to poll the CM */ +#define kSingleThreadPollSeconds 60 + +static time_t gLastUpdateTime = 0; + +int gRetryServerAfterFailure = 0; + +/* static globals */ + +#define kDefaultSessionCookieName "sessionid" + +/** + * This is the name used for both cookies and query arguments + */ +static char *gSessionCookieName = kDefaultSessionCookieName; +static int gSessionCookieNameLength = 9; + +/* Name and port number of the server to redirect requests to in the case + * of total dynamo failure. + */ +static char *gFailoverServer = NULL; + +/** + * Used for URL arguments + */ +#define kDefaultSessionParamName "$sessionid$" + +#define kDynServerName "dyn_server" +#define kDynServerLength 10 + +static char *gSessionParamName = kDefaultSessionParamName; +static int gSessionParamNameLength = 11; + +#define kCookieHeaderName "cookie" + + +/* 0 == no info known re: DRP servers; + !0 == info has been obtained from DM */ +/* drpContextBlock * a */ +#define serverInfoAvailable(a) (gCMLDRP_InfoVersion != 0) + + +/* r: drpServerRecord * + evaluates to: 0 == server not known to be active; !0 == server active */ +#define serverActive(r) \ + ((r) && ((r)->flags & kDrpServerFlags_Active)) + +/* r: drpServerRecord * + evaluates to: 0 == server not accepting new sessions */ +#define serverAcceptingNewSessions(r) \ + ((r) && ((r)->flags & kDrpServerFlags_AcceptingNewSessions)) + +/* r: drpServerRecord * + evaluates to: 1 == server is known to be overloaded */ +#define serverOverloaded(r) \ + ((r) && ((r)->flags & kDrpServerFlags_Overloaded)) + +/* r: drpServerRecord * + evaluates to: 1 == server seems to be down */ +#define serverSeemsDown(r) \ + ((r) && ((r)->flags & kDrpServerFlags_SeemsDown)) + +/* clear DRP server's active flag + r: drpServerRecord * + */ +#define markServerInactive(r) \ + ((r)->flags &= ~kDrpServerFlags_Active) + + +/* Set the DRP servers seems down flag + r: drpServerRecord * + */ +#define markServerSeemsDown(r) \ + ((r)->flags |= kDrpServerFlags_SeemsDown) + + +/* 0: parameter p requires a single response object; + !0: parameter p requires a list (indexed) of responses (e.g. headers) */ +#define paramDemandsListResponse(p) \ + ((p.name.type == kDefined) && ((p.name.value.defined == kParameters) || \ + (p.name.value.defined == kHeaders))) + +/* 0: parameter p requires a DRP 4-byte Integer response; + !0: parameter p requires a string-type response */ +#define paramDemandsIntResponse(p) \ + ((p.name.type == kDefined) && ((p.name.value.defined == kContentLength) || \ + (p.name.value.defined == kServerPort))) + +/* establish the DRP server record pointed to by recPtr as the "current + server" for context-block pCB */ +#define setCurrentServer(pCB,recPtr) \ + (pCB)->currentServer = (recPtr) + + +/* static function prototypes */ +static DrpServiceStatus forceUpdateFromDM(drpContextBlock * pCB); + +static DrpServiceStatus drpService_sid(drpContextBlock * pCB); +static DrpServiceStatus drpService_load(drpContextBlock * pCB); +static DrpServiceStatus drpService_route(drpContextBlock * pCB); +static int isStaticallyRoutedRequest(drpContextBlock * pCB); +static int getDrpServerInfoFromSid(drpContextBlock * pCB, + unsigned long *oAddr, + unsigned short *oPort); +static DrpServiceStatus tryServer(drpContextBlock * pCB, + drpServerRecord * drpServer); +static DrpServiceStatus drpService_server(drpContextBlock * pCB); +#ifdef _CPOOL +static int pooledConnectToCurrentServer(drpContextBlock * pCB); +#endif +static int connectedToCurrentServer(drpContextBlock * pCB); +static int connectToCurrentServer(drpContextBlock * pCB); +static DrpServiceStatus sendBeginRequest(drpContextBlock * pCB); +static DrpServiceStatus handleDrpServerRequest(drpContextBlock * pCB); + +static DrpServiceStatus handleGetParameters(drpContextBlock * pCB); +static DrpServiceStatus handleReadData(drpContextBlock * pCB); +static DrpServiceStatus handleWriteData(drpContextBlock * pCB); +static DrpServiceStatus handleFlush(drpContextBlock * pCB); +static DrpServiceStatus handleClose(drpContextBlock * pCB); +static DrpServiceStatus handleHeader(drpContextBlock * pCB); +static DrpServiceStatus handleReplyPacket(drpContextBlock * pCB); + +static DrpServiceStatus doSendHeader(drpContextBlock * pCB); + +static DrpServiceStatus handleGetAllHeaders(drpContextBlock * pCB); + +static int getSessionID(drpContextBlock * pCB); + +static DrpServiceStatus batchHeaders(drpContextBlock * pCB); +static DrpServiceStatus dispatchHeaders(drpContextBlock * pCB); + +static DrpServiceStatus sendParameter(drpContextBlock * pCB, + drpByte iDefinedParam, + drpIdentifier * iIdentParam); + +static int copyGlobalDrpServerInfo(drpContextBlock * pCB); + +#if 0 +/* obsoleted - see end of file */ +static DrpServiceStatus handleGetAllParameters(drpContextBlock * pCB); +static void getNextQueryArg(char *pBuffer, int namePtr, int *oValPtr, + int *oNextPtr); +#endif + +#if 0 +/* useful for debugging */ +void debugPrint(const char *message) +{ + FILE *debugOut = fopen("d:\\debug.log", "a"); + if (debugOut != NULL) { + fputs(message, debugOut); + fclose(debugOut); + } +} +#endif + +/** + * drpInitialize + * initialize the DRP2 subsystem for a connection module instance. should + * be invoked once for each process (not thread) containing a CM instance, + * before any DRP2 service is performed. + */ +void drpInitialize(void) +{ + +#ifdef _DRP_MTHREAD + srand((unsigned) time(NULL)); + +#else + + /* need a better seed for multiple processes otherwise each process + will start with the same seed or a similar seed. */ + +#ifdef WIN32 + /* use the millisecond part of the time as the seed. */ + struct _SYSTEMTIME tp; + GetSystemTime(&tp); + srand(tp.wMilliseconds); + +#else + /* use the microsecond part of the time as the seed. */ + unsigned int seed = 0; + struct timeval tp; + int ret = gettimeofday(&tp, 0); + if (!ret) { + seed = (unsigned int) tp.tv_usec; + } else { + /* this should never happen. use ftime instead. */ + struct timeb tb; + ret = ftime(&tb); + if (!ret) { + seed = (unsigned int) tb.millitm; + } else { + /* we should REALLY never get here. */ + seed = (unsigned int) time(0); + } + } + srand(seed); + +#endif /* ifdef WIN32 */ + +#endif /* ifdef _DRP_MTHREAD */ +} + + +/** + * drpReset + * Reset a DRP Context Block between service requests + * pCB: context block to reset + * note: the context block object should be byte-cleared to 0 when created + * by the shell + */ +void drpReset(drpContextBlock * pCB) +{ + pCB->serviceStatus = kIdle; + + /* Was this request targeted with dyn_server=... */ + pCB->isTargetedRequest = 0; + + /* reset request logging to off */ + pCB->isLoggedRequest = 0; + + /* reset debugging to off */ + pCB->debugEnabled = 0; + + /* create or reset internal buffers */ + if (!pCB->ioBuffer.buffer) + createGrowBuffer(&(pCB->ioBuffer), kMainBufferSize); + else + clearGrowBuffer_m((&pCB->ioBuffer)); + + if (!pCB->ioBuffer2.buffer) + createGrowBuffer(&(pCB->ioBuffer2), kMinorBufferSize); + else + clearGrowBuffer_m((&pCB->ioBuffer2)); + + if (!pCB->headers.buffer) + createGrowBuffer(&(pCB->headers), kMinorBufferSize); + else + clearGrowBuffer_m((&pCB->headers)); + + if (!pCB->headers2.buffer) + createGrowBuffer(&(pCB->headers2), kMinorBufferSize); + else + clearGrowBuffer_m((&pCB->headers2)); + + if (!pCB->statusBuffer.buffer) + createGrowBuffer(&(pCB->statusBuffer), kMinorBufferSize); + else + clearGrowBuffer_m((&pCB->statusBuffer)); + + /* create or reset socket IO buffers */ + if (!pCB->recvBuf.data) { + pCB->recvBuf.capacity = kSockBufSize; + pCB->recvBuf.data = (char *) malloc(pCB->recvBuf.capacity); + } else { + pCB->recvBuf.curPtr = 0; + pCB->recvBuf.used = 0; + } + + if (!pCB->sendBuf.data) { + pCB->sendBuf.capacity = kSockBufSize; + pCB->sendBuf.data = (char *) malloc(pCB->sendBuf.capacity); + } else { + pCB->sendBuf.curPtr = 0; + pCB->sendBuf.used = 0; + } + + pCB->statusSetByServer = 0; + pCB->statusSentToAgent = 0; + pCB->statusCode = 0; + pCB->statusMesg.type = kNull; + pCB->sessionID[0] = '\0'; +} + +/** + * drpSetFailoverServer + * Set the hostname and port number of the server to redirect requests to + * in the event of a total application failure. + */ +void drpSetFailoverServer(const char *newServer) +{ + if (gFailoverServer != NULL) + free(gFailoverServer); + if (newServer == NULL) + gFailoverServer = NULL; + else + gFailoverServer = (char *) strdup(newServer); +} + +/** + * drpSetSessionCookieName + * Set the session cookie name used by this server. + */ +void drpSetSessionCookieName(const char *pCookieName) +{ + if (pCookieName) { + gSessionCookieName = (char *) strdup(pCookieName); + gSessionCookieNameLength = strlen(pCookieName); + } +} + +/** + * drpService + * Service the current request + * return: 0 == success; !0 == failure (details in pCB->serviceStatus) + */ +int drpService(drpContextBlock * pCB) +{ + int returnValue = kDrpServiceOk; + +#ifdef _DRP_MTHREAD + int acquiredHandler = 1; + /* first: check to see if we are not exceeding our handler limit */ + if (acquireHandler() != 0) { + returnValue = kDrpServiceFailover; + acquiredHandler = 0; + goto DRP_SVC_EXIT; + } +#endif + +#ifndef _DRP_MTHREAD + /* + * In non-multi-threaded servers, we need to poll the load manager + * periodically to update the server table. + */ + if (time(NULL) > gLastUpdateTime + kSingleThreadPollSeconds) { + forceUpdateFromDM(pCB); + } +#endif + + /* next: check to see if we should update local copy of drp-server + info from the CMLDRP system */ + if ((pCB->drpServerInfoVersion != gCMLDRP_InfoVersion) || + (!serverInfoAvailable(pCB))) { + int status = copyGlobalDrpServerInfo(pCB); + if (status != 0 && pCB->debugEnabled) + pCB->logMessage(pCB->shellData, kLog_Info, + kLogMessage_OneString, + "can't global global server info", NULL); + } + + pCB->serviceStatus = kConnectingToServer; + + if (!serverInfoAvailable(pCB)) { + if (pCB->debugEnabled) + pCB->logMessage(pCB->shellData, kLog_Info, + kLogMessage_OneString, + "no serverInfo available", NULL); + /* copyGlobalServerInfo will have attempted to force a data update + if no server info available, so don't do so here */ + + /* if no server info is available, probably the load manager is down + * or some other catastrophic failure. try to fail over to a different + * server. + */ + getSessionID(pCB); /* extract session ID information, if any */ + returnValue = kDrpServiceFailover; + + pCB->logMessage(pCB->shellData, kLog_Error, + kLogMessage_NoDRPServerAvailable, NULL, NULL); + goto DRP_SVC_EXIT; + } + + /* if there is a session ID cookie, route to the server that it came + * from. + */ + if (getSessionID(pCB)) { + returnValue = drpService_sid(pCB); + /* errors will be logged by drpService_sid() */ + if (returnValue != kDrpServiceOk && pCB->isTargetedRequest) { + if (pCB->debugEnabled) + pCB->logMessage(pCB->shellData, kLog_Error, + kLogMessage_OneString, + "aborting failed to deliver request to specic dyn_server", + NULL); + goto DRP_SVC_EXIT; + } + if (returnValue != kDrpServiceOk && pCB->debugEnabled) { + char buf[256]; + sprintf(buf, + "failed sending request to session server with sessionId=%s", + pCB->sessionID); + pCB->logMessage(pCB->shellData, kLog_Error, + kLogMessage_OneString, buf, NULL); + } + } + + /* there is no session ID cookie; if this is one of the URLs that + * must be hashed to a particular server, do it. + */ + else if (isStaticallyRoutedRequest(pCB)) { + returnValue = drpService_route(pCB); + /* errors will be logged by drpService_load() */ + } + + /* if the request wasn't serviced by either SID redirection or static + * routing then service it by load. + */ + if (pCB->serviceStatus < kServicingRequest) { + returnValue = drpService_load(pCB); + /* errors will be logged by drpService_load() */ + } + + DRP_SVC_EXIT: + + /* If a total application failover has occurred, try to redirect the + * request to a different application server. + */ + if ((gFailoverServer != NULL) && (returnValue == kDrpServiceFailover)) { + drpIdentifier paramName; + growBuffer requestUrl; + growBuffer failoverUrl; + growBuffer name; + growBuffer value; + + /* we should verify that this is a redirectable method (ie, not POST) + * here + */ + + createGrowBuffer(&requestUrl, kMinorBufferSize); + createGrowBuffer(&failoverUrl, kMinorBufferSize); + createGrowBuffer(&name, kMinorBufferSize); + createGrowBuffer(&value, kMinorBufferSize); + + /* extract the request URL information + */ + paramName.name.type = kDefined; + paramName.name.value.defined = kPathInfo; + paramName.hasIndex = 0; + pCB->getParameter(pCB->shellData, ¶mName, &requestUrl); + + concatenate(&failoverUrl, "http://"); + concatenate(&failoverUrl, gFailoverServer); + if (requestUrl.buffer[0] != '/') + concatenate(&failoverUrl, "/"); + concatenate(&failoverUrl, requestUrl.buffer); + + /* if there's no session ID information already in the URL, try to add + * it. + */ + if (!strstr(requestUrl.buffer, "$sessionid$") && + (strlen(pCB->sessionID) > 0)) { + concatenate(&failoverUrl, ";$sessionid$"); + concatenate(&failoverUrl, pCB->sessionID); + } + + /* assemble the HTTP header and send it on its way + */ + pCB->statusCode = kFailoverStatusCode; /* Moved Temporarily */ + pCB->statusSetByServer = 1; + /*pCB->statusMesg = kFailoverStatusMessage; -- gotta convert this */ + setGrowBuffer(&name, "Location"); + pCB->setResponseHeader(pCB->shellData, &name, &failoverUrl); + setGrowBuffer(&name, "Content-Type"); + setGrowBuffer(&value, "text/html"); + pCB->setResponseHeader(pCB->shellData, &name, &value); + returnValue = doSendHeader(pCB); + + /* Emit a reasonable error page. + */ + if (returnValue == kDrpServiceOk) { + setGrowBuffer(&value, "\n"); + concatenate(&value, "Application Error\n"); + concatenate(&value, "

Application Error

\n"); + concatenate(&value, + "A recoverable application error has occurred. If you would like to continue, please use "); + concatenate(&value, ""); + concatenate(&value, failoverUrl.buffer); + concatenate(&value, ".\n"); + concatenate(&value, "\n"); + concatenate(&value, "\n"); + returnValue = + pCB->writeToAgent(pCB->shellData, &value, value.used); + } + + /* emit redirection page HTML here */ + if (returnValue != kDrpServiceOk) + returnValue = handleFlush(pCB); + handleClose(pCB); + + destroyGrowBuffer(&requestUrl); + destroyGrowBuffer(&failoverUrl); + destroyGrowBuffer(&name); + destroyGrowBuffer(&value); + } +#ifdef _DRP_MTHREAD + if (acquiredHandler) { + releaseHandler(); + } +#endif + + return returnValue; +} + + +#ifdef _DRP_MTHREAD +#define kSleepTime_WaitingForUpdate 250 /* msec */ +#define kWaitTime_WaitingForUpdate 1 /* sec */ +#else +#define kSleepTime_WaitingForUpdate 1 /* sec */ +#define kWaitTime_WaitingForUpdate 1 /* sec */ +#endif + + + +/** + * noteDrpServerSeemsDown + * Update the global flags for a Drp server to note + * that it seems to be down + * return: 0 == success; !0 == failure + */ +static int noteDrpServerSeemsDown(drpContextBlock * pCB) +{ + /* NB: must obtain write lock on global drp server info in order + to update a global flag for this server. This is an expensive + operation only to be undertaken in extreme cases where the + drp server seems to be down + */ + if (!getWriteLock(&gLoadDataLock, kRWL_DefaultReadTimeout)) { + drpServerRecord *drpServer = pCB->currentServer; + drpServerRecord **globalRecord; + + /* Find and update the location in the global server list */ + globalRecord = + getDrpServerRecord((const drpServerRecord **) gDrpServerPtrs, + gNumDrpServers, drpServer->inetaddr, + drpServer->port); + + if (globalRecord != NULL) { + markServerSeemsDown((*globalRecord)); + (*globalRecord)->probability = 0; + /* Update the info version so that all the handler threads will now + * pick up this information + */ + gCMLDRP_InfoVersion++; + } +#ifdef _DRP_MTHREAD + releaseWriteLock(&gLoadDataLock); +#endif + return 0; + } + return -1; +} + + +/** + * copyGlobalDrpServerInfo + * Copy drp server information from the CMLDRP system's global vars. + * return: 0 == success; !0 == failure + */ +static int copyGlobalDrpServerInfo(drpContextBlock * pCB) +{ + int returnValue = 0; + + if (gCMLDRP_InfoVersion == 0) { + /* no DRP server info available yet */ + forceUpdateFromDM(pCB); + + /* did the data get updated? */ + if (gCMLDRP_InfoVersion == 0) { + if (pCB->debugEnabled) { + pCB->logMessage(pCB->shellData, kLog_Info, + kLogMessage_OneString, + "No drp servers in the global list", NULL); + } + goto COPY_GLOBAL_INFO_EXIT; + } + } + + /* NB: must obtain read lock on global drp server info! */ + if (!getReadLock(&gLoadDataLock, kRWL_DefaultReadTimeout)) { + int s; + short newServers = 0; + + /* + * Only set the probability to 0 once we've gotten the read lock. If + * we fail to get the read lock, at least we can go on and use the old + * cached version of the hosts + */ + pCB->totalProb = 0; + + /* update information for all drp servers known to the local thread */ + for (s = 0; s < pCB->numDrpServers; s++) { + pCB->drpServers[s].probability = gDrpServers[s].probability; + pCB->drpServers[s].flags = gDrpServers[s].flags; + if (pCB->drpServers[s].flags & kDrpServerFlags_Active) + pCB->totalProb += pCB->drpServers[s].probability; + } + + /* establish new information for all drp servers not yet known to + local thread (i.e. newly obtained by the CMLDRP thread since last + update from local thread) */ + while (gNumDrpServers > pCB->numDrpServers) { + int idx = pCB->numDrpServers; + + newServers++; + + pCB->drpServers[idx].inetaddr = gDrpServers[idx].inetaddr; + pCB->drpServers[idx].port = gDrpServers[idx].port; + pCB->drpServers[idx].probability = + gDrpServers[idx].probability; + pCB->drpServers[idx].flags = gDrpServers[idx].flags; + pCB->drpServers[idx].sock = kInvalidSocket; + + pCB->drpServerPtrs[idx] = &pCB->drpServers[idx]; + + if (pCB->drpServers[idx].flags & kDrpServerFlags_Active) + pCB->totalProb += pCB->drpServers[idx].probability; + +#ifdef _CPOOL + pCB->drpServers[idx].pool = gDrpServers[idx].pool; +#endif + + pCB->numDrpServers++; + } + + /* update local drp server information version */ + pCB->drpServerInfoVersion = gCMLDRP_InfoVersion; + +#ifdef _DRP_MTHREAD + releaseReadLock(&gLoadDataLock); +#endif + + /* sort locally stored servers by IP:port */ + if (newServers) { + qsort(pCB->drpServerPtrs, pCB->numDrpServers, + sizeof(drpServerRecord *), + compareDRPServerRecPtrs_ipPort); + } + } else { + if (pCB->debugEnabled) { + pCB->logMessage(pCB->shellData, kLog_Info, + kLogMessage_OneString, + "Failed to copy server info - using stale server info", + NULL); + } + returnValue = -1; + } + + COPY_GLOBAL_INFO_EXIT: + + return returnValue; +} + + +/** + * forceUpdateFromDM + * (DM == "Dynamo Manager", i.e. CMLDRP server) + * force communication w/ a DM to update DRP server information; + * wait for DRP server info to be updated before returning + * return: 0 == success; !0 == failure (update did not occur) + */ +static DrpServiceStatus forceUpdateFromDM(drpContextBlock * pCB) +{ + int returnValue = kDrpServiceError; + time_t waketime; + unsigned int infoVersion = gCMLDRP_InfoVersion; + + /* setting this flag forces CMLDRP system to attempt to update its + globally-held drp server information */ + gCMLDRP_UpdateNow = 1; + + gLastUpdateTime = time(NULL); + + waketime = gLastUpdateTime + kWaitTime_WaitingForUpdate; + do { +#ifdef _DRP_MTHREAD + /* multithreaded case: wait for the CMLDRP thread to get its data */ + thread_sleep(kSleepTime_WaitingForUpdate); +#else + /* multiprocess case: invoke CMLDRP communication directly */ + returnValue = cmldrpUpdate_MP(&gCMLDRPBlock); +#endif + if (gCMLDRP_InfoVersion != infoVersion) { + returnValue = kDrpServiceOk; + break; /* out of do/while loop */ + } + } while (time(NULL) < waketime); + + return returnValue; +} + + +/** + * getSessionID + * Obtain a session ID from the current request, if one is available. + * + * Note: this routine also looks for the dyn_server=IPADDR:PORT option. + * If it exists, it sets pCB->isTargetedRequest and stores the targeted + * IP address and IP port in the request. + * return: 0 == no session ID found; !0 == session ID placed in pCB + */ +static int getSessionID(drpContextBlock * pCB) +{ + int returnValue = 0; /* assume no session ID */ + drpIdentifier cookieHeaderName; + drpIdentifier pathInfoParamName; + drpIdentifier queryParamName; + int result; + + pCB->isTargetedRequest = 0; + + /* first check in Dynamo URI args */ + pathInfoParamName.name.type = kDefined; + pathInfoParamName.name.value.defined = kPathInfo; + pathInfoParamName.hasIndex = 0; + + result = pCB->getParameter(pCB->shellData, &pathInfoParamName, + &pCB->ioBuffer); + if (result == 0) { + /* got some URL params */ + char *sidStart; + char *searchStart = pCB->ioBuffer.buffer; + + pCB->ioBuffer.buffer[pCB->ioBuffer.used] = kChar_Null; + + /* + * The URL parameter string is of the form: + * + * ;$name1$value1;$name2$value2 + */ + do { + sidStart = strchr(searchStart, kChar_Semicolon); + if (sidStart) { + sidStart++; /* Skip the semicolon */ + if (!strncmp + (sidStart, gSessionParamName, + gSessionParamNameLength)) { + char *sidEnd; + int sidLen; + sidStart += gSessionParamNameLength; + /* find the ending semicolon, if any */ + sidEnd = strchr(sidStart, kChar_Semicolon); + if (sidEnd == NULL) + sidEnd = &sidStart[strlen(sidStart)]; + sidLen = sidEnd - sidStart; + if (sidLen < kMaxSessionIDLength) { + strncpy(pCB->sessionID, sidStart, sidLen); + pCB->sessionID[sidLen] = '\0'; + returnValue = 1; + break; + } + } + searchStart = sidStart + 1; + } + } while (sidStart != NULL); + } + + /* now check the dynamo query arguments for dyn_sid and dyn_server */ + queryParamName.name.type = kDefined; + queryParamName.name.value.defined = kQueryString; + queryParamName.hasIndex = 0; + + result = pCB->getParameter(pCB->shellData, &queryParamName, + &pCB->ioBuffer); + if (result == 0) { + /* got some Query params */ + char *sidStart; + char *searchStart = pCB->ioBuffer.buffer; + + pCB->ioBuffer.buffer[pCB->ioBuffer.used] = kChar_Null; + + sidStart = searchStart; + /* + * The Query parameter string is of the form: + * + * name1=value1&name2=value2 + */ + do { + if (!strncmp + (sidStart, gSessionCookieName, gSessionCookieNameLength)) { + char *sidEnd; + int sidLen; + sidStart += gSessionCookieNameLength + 1; + sidEnd = strchr(sidStart, kChar_Ampersand); + if (sidEnd == NULL) + sidEnd = &sidStart[strlen(sidStart)]; + sidLen = sidEnd - sidStart; + if (sidLen < kMaxSessionIDLength) { + strncpy(pCB->sessionID, sidStart, sidLen); + pCB->sessionID[sidLen] = '\0'; + returnValue = 1; + } + } else + if (!strncmp(sidStart, kDynServerName, kDynServerLength)) { + unsigned long serverAddr = 0; + char *sep; + int i; + + sidStart += kDynServerLength + 1; + + pCB->isTargetedRequest = 1; + + for (i = 0; i < 4; i++) { + char tmpbuf[128]; + char searchChar; + if (i == 3) + searchChar = kChar_Colon; + else + searchChar = kChar_Dot; + sep = strchr(sidStart, searchChar); + if (sep != NULL) { + serverAddr <<= 8; + strncpy(tmpbuf, sidStart, sep - sidStart); + tmpbuf[sep - sidStart] = '\0'; + serverAddr |= atoi(tmpbuf); + sidStart = sep + 1; + } + /* + * Bad IP address format + */ + else { + pCB->isTargetedRequest = 0; + break; + } + } + if (pCB->isTargetedRequest) { + pCB->targetedServerPort = atoi(sidStart); + if (pCB->targetedServerPort == 0) { + pCB->isTargetedRequest = 0; + } else { + /* + * Convert this from host to network byte order + */ + pCB->targetedServerAddr = htonl(serverAddr); + returnValue = 1; + if (pCB->debugEnabled) { + char buf[128]; + sprintf(buf, + "specific dyn_server=%lu.%lu.%lu.%lu:%hu", + pCB->targetedServerAddr & 0xff, + (pCB->targetedServerAddr >> 8) & 0xff, + (pCB->targetedServerAddr >> 16) & 0xff, + (pCB->targetedServerAddr >> 24) & 0xff, + pCB->targetedServerPort); + pCB->logMessage(pCB->shellData, kLog_Info, + kLogMessage_OneString, buf, + NULL); + } + } + } + } + searchStart = strchr(sidStart, kChar_Ampersand); + /* + * Skip the ampersand + */ + sidStart = searchStart + 1; + } while (searchStart != NULL); + } + + if (returnValue == 0) { + /* SID not found in dynamo url args; try cookie header */ + cookieHeaderName.hasIndex = 0; + cookieHeaderName.name.type = kAscii; + cookieHeaderName.name.numChars = strlen(kCookieHeaderName) + 1; + cookieHeaderName.name.value.ascii = kCookieHeaderName; + + result = pCB->getParameter(pCB->shellData, &cookieHeaderName, + &pCB->ioBuffer); + if (result == 0) { + /* there is something in the cookie header */ + char *sidStart; + + pCB->ioBuffer.buffer[pCB->ioBuffer.used] = kChar_Null; + sidStart = strstr(pCB->ioBuffer.buffer, gSessionCookieName); + if (sidStart) { + sidStart += gSessionCookieNameLength; + if (*sidStart == kChar_Equals) { + char *sidEnd; + int sidLen; + sidStart++; /* now sidStart points at 1st char in sid */ + /* This is a special char that represents an invalid session id */ + if (*sidStart != '-') { + sidEnd = strchr(sidStart, kChar_Semicolon); + if (sidEnd == NULL) + sidEnd = &sidStart[strlen(sidStart)]; + sidLen = sidEnd - sidStart; + if (sidLen < kMaxSessionIDLength) { + strncpy(pCB->sessionID, sidStart, sidLen); + pCB->sessionID[sidLen] = '\0'; + returnValue = 1; + } + } + } + } + } + } + + return returnValue; +} + +/** + * getShellParameter + * Helper function used to extract a shell parameter into a growBuffer. + * return: 0 on success, !0 on failure. + */ +int getShellParameter(drpContextBlock * pCB, int whichParam, + growBuffer * retBuf) +{ + drpIdentifier paramName; + int retValue; + + paramName.name.type = kDefined; + paramName.name.value.defined = whichParam; + paramName.hasIndex = 0; + retValue = pCB->getParameter(pCB->shellData, ¶mName, retBuf); + if (retValue == 0) { + if (retBuf->buffer[0] == '\0') /* failed if buffer is empty */ + retValue = -1; + } + return retValue; +} + +/** + * isStaticallyRoutedRequest + * See if the URI of the incoming request exists in the statically routed + * page table. + * returns 1 (true) if so, 0 (false) if not. + */ +int isStaticallyRoutedRequest(drpContextBlock * pCB) +{ + growBuffer buf; + int returnValue; + + if (createGrowBuffer(&buf, 1024) == NULL) + return 0; /* fails due to lack of memory */ + if (getShellParameter(pCB, kRequestURI, &buf) == 0) + returnValue = isStaticallyRoutedPage(buf.buffer); + else + returnValue = 0; /* no URI found */ + destroyGrowBuffer(&buf); + return returnValue; +} + +/** + * drpService_sid + * Use the session-ID from the current request to determine the DRP server + * with which to communicate; contact that server and use it to service + * the request + * return: 0 == success; !0 == failure + */ +static DrpServiceStatus drpService_sid(drpContextBlock * pCB) +{ + int returnValue = kDrpServiceOk; + unsigned long serverAddr; + unsigned short serverPort; + int result; + + /* get IP:port of requested DRP server from session id (SID stored + in context block) */ + if (pCB->isTargetedRequest) { + result = 0; + serverAddr = pCB->targetedServerAddr; + serverPort = pCB->targetedServerPort; + } else { + result = getDrpServerInfoFromSid(pCB, &serverAddr, &serverPort); + } + if (result == 0) { + drpServerRecord **serverRecord; + serverRecord = + getDrpServerRecord((const drpServerRecord **) pCB-> + drpServerPtrs, pCB->numDrpServers, + serverAddr, serverPort); + if (!serverRecord) { + if (pCB->debugEnabled) { + char buf[1024]; + sprintf(buf, + "Unable to find dynamo server with addr=%lu.%lu.%lu.%lu port=%hu", + serverAddr & 0xff, (serverAddr >> 8) & 0xff, + (serverAddr >> 16) & 0xff, + (serverAddr >> 24) & 0xff, serverPort); + pCB->logMessage(pCB->shellData, kLog_Error, + kLogMessage_OneString, buf, NULL); + } + /* most likely case: this session was started by another context + with more current info about avail drp servers, which this + context does not yet have; obtain that info */ + returnValue = forceUpdateFromDM(pCB); + serverRecord = + getDrpServerRecord((const drpServerRecord **) pCB-> + drpServerPtrs, pCB->numDrpServers, + serverAddr, serverPort); + } + + /* now, if server still not active, we can't use it */ + if ((!serverRecord) || (!serverActive((*serverRecord)))) + returnValue = kDrpServiceNoServer; + else + returnValue = tryServer(pCB, *serverRecord); + } + + return returnValue; +} + +/** + * drpService_load + * Use load-balancing to determine the DRP server with which to communicate + * to service the current request; contact that server and use it to + * complete service + * return: 0 == success; !0 == failure + */ +static DrpServiceStatus drpService_load(drpContextBlock * pCB) +{ + int returnValue = -1; + unsigned int randNum; + int s; + drpServerRecord *drpServer; + + if (pCB->debugEnabled && pCB->totalProb <= 0) { + char buf[256]; + sprintf(buf, "total probability is: %d numServers=%d", + pCB->totalProb, pCB->numDrpServers); + pCB->logMessage(pCB->shellData, kLog_Info, kLogMessage_OneString, + buf, NULL); + for (s = 0; s < pCB->numDrpServers; s++) { + + sprintf(buf, + "probability for server: %lu.%lu.%lu.%lu " + "port=%hu flags=%hu is: %hu", + pCB->drpServers[s].inetaddr & 0xff, + (pCB->drpServers[s].inetaddr >> 8) & 0xff, + (pCB->drpServers[s].inetaddr >> 16) & 0xff, + (pCB->drpServers[s].inetaddr >> 24) & 0xff, + pCB->drpServers[s].port, + pCB->drpServers[s].flags, + pCB->drpServers[s].probability); + pCB->logMessage(pCB->shellData, kLog_Info, + kLogMessage_OneString, buf, NULL); + } + } + + while (pCB->totalProb > 0) { + /* get a random number from 1 to totalProb (sum of all active DRP server + weights); walk through the list of DRP servers to find the + drp server record corresponding to the random number by weight */ + + drpServer = NULL; + randNum = (rand() % pCB->totalProb) + 1; /* 1..totalProb */ + + for (s = 0; (s < pCB->numDrpServers) && (randNum > 0); s++) { + if (serverActive(&pCB->drpServers[s])) { + if (serverAcceptingNewSessions(&pCB->drpServers[s]) && + !serverOverloaded(&pCB->drpServers[s]) && + !serverSeemsDown(&pCB->drpServers[s]) && + randNum <= pCB->drpServers[s].probability) { + drpServer = &pCB->drpServers[s]; + break; /* out of "for (s = 0..." loop */ + } + /* + * Only subtract the probablity if this server is in the list + */ + randNum -= MIN(pCB->drpServers[s].probability, randNum); + } + } + + if (drpServer) { + returnValue = tryServer(pCB, drpServer); + if (returnValue == 0) + break; /* out of "while pCb->totalProb > 0" */ + else if (gRetryServerAfterFailure) + break; + } else { + pCB->logMessage(pCB->shellData, kLog_Error, + kLogMessage_NoDRPServerAvailable, NULL, NULL); + + /* all servers failed; tell the HTTP server to try to fail over + * to a different dynamo cluster. + */ + returnValue = kDrpServiceFailover; + break; + } + } + + /* + * This is a last ditch effort to find a server to try. If the load + * manager mistakenly polled a dynamo and saw that it was down, it + * would get removed from the list. If we have no dynamos in the list, + * then and this "retry mode" is turned on, we go through the list + * and retry each server until we find one that works. + */ + if (returnValue != kDrpServiceOk && pCB->totalProb == 0) { + if (pCB->debugEnabled) + pCB->logMessage(pCB->shellData, kLog_Info, + kLogMessage_OneString, + "total prob is 0 retrying server list", NULL); + for (s = 0; s < pCB->numDrpServers; s++) { + /* + * Unless the server has been explicitly marked as inactive, overloaded + * or down. + */ + if (serverActive(&pCB->drpServers[s]) && + serverAcceptingNewSessions(&pCB->drpServers[s]) && + !serverOverloaded(&pCB->drpServers[s]) && + !serverSeemsDown(&pCB->drpServers[s])) { + drpServer = &pCB->drpServers[s]; + + returnValue = tryServer(pCB, drpServer); + if (returnValue == kDrpServiceOk) { + if (pCB->debugEnabled) + pCB->logMessage(pCB->shellData, kLog_Info, + kLogMessage_OneString, + "successfully retried server", + NULL); + break; + } + } + } + + /* we didn't find any dynamos that work; tell the HTTP server + * to fail over, if possible. + */ + if (returnValue != kDrpServiceOk) + returnValue = kDrpServiceFailover; + } + + + return returnValue; +} + +/** + * drpService_route + * Use a deterministic algorithm to route to determine the DRP server with + * which to communicate to service the current request; contact that + * server and use it to complete service. + * + * The selection algorithm uses a string hash value plus the two high-order + * octets in the client IP address. The latter adjustment is done as + * a way to better distribute the load amongst the servers. Only the + * high-order octets are used because AOL (and possibly other) clients can + * shift IP addresses between requests, but it is extremely unlikely that + * they will shift between B-class networks. + * + * In case of server failure the next working server in the server table + * is used instead. This fallback has a window where two requests that + * should go to the same server will go to different servers if the + * selected server should fail or return to service between requests. + * For Ad Station's use this is felt to be acceptable. + * + * return: 0 == success; !0 == failure + */ +static DrpServiceStatus drpService_route(drpContextBlock * pCB) +{ + int hashValue; + int firstServerNum; + int serverNum; + growBuffer buf; + int returnValue = -1; + int octetValue = 0; + int ipValue = 0; + int dotCount = 0; + + /* no servers, no routing. + */ + if (pCB->numDrpServers == 0) { + pCB->logMessage(pCB->shellData, kLog_Error, + kLogMessage_NoDRPServerAvailable, NULL, NULL); + return kDrpServiceNoServer; + } + + if (createGrowBuffer(&buf, 1024) == NULL) + return kDrpServiceNoMemory; /* memory allocation failure */ + + /* calculate a hash value for the User-Agent field, if known + */ + if (getShellParameter(pCB, kUserAgent, &buf) != 0) + hashValue = 0; + else + hashValue = getStringHashValue(buf.buffer); + + /* adjust the hash value using the 2 high-order bytes of the IP address + * for better load balancing. + */ + if (getShellParameter(pCB, kRemoteAddr, &buf) == 0) { + char *p = &buf.buffer[0]; + + /* parse the first two octets of the dotted IP address into a value. + */ + while (*p != '\0') { + if ((*p >= '0') && (*p <= '9')) + octetValue = (octetValue * 10) + (*p - '0'); + else if (*p == '.') { + ipValue = (ipValue << 8) + octetValue; + if (++dotCount == 2) /* only first two octets */ + break; + octetValue = 0; + } + p++; + } + + hashValue += ipValue; + } + + /* use the hash to determine the first server to try. + */ + serverNum = firstServerNum = hashValue % pCB->numDrpServers; + + for (;;) { + + /* if the server is thought to be responding, try it. + */ + if (pCB->drpServers[serverNum].probability != 0) { + returnValue = tryServer(pCB, &pCB->drpServers[serverNum]); + if (returnValue == 0) /* request went through */ + goto cleanup; + } + + /* try the next server in the table + */ + serverNum = (serverNum + 1) % pCB->numDrpServers; + + /* if we've tried all servers in the table, we're SOL. + */ + if (serverNum == firstServerNum) { + pCB->logMessage(pCB->shellData, kLog_Error, + kLogMessage_NoDRPServerAvailable, NULL, NULL); + goto cleanup; + } + } + + cleanup: + destroyGrowBuffer(&buf); + return returnValue; +} + +/** + * tryServer + * Attempts to service the request with the given server, adjusting + * the server probabilities if the request fails. + * return: 0 == success; !0 == failure + */ +static DrpServiceStatus tryServer(drpContextBlock * pCB, + drpServerRecord * drpServer) +{ + int returnValue; + + setCurrentServer(pCB, drpServer); + + /* drpService_server actually attempts the service */ + returnValue = drpService_server(pCB); + + /* if the attempt failed, log it and return. + */ + if (returnValue != 0) { + char portString[8]; + struct in_addr *inAddr; + + sprintf(portString, "%d", drpServer->port); + inAddr = (struct in_addr *) &drpServer->inetaddr; + pCB->logMessage(pCB->shellData, kLog_Warn, + kLogMessage_DRPServerUnavailable, + inet_ntoa(*inAddr), portString); + /* + * mark server as unavailable, restart loop and + * factor this server's unavailability into random number range + */ + if (!gRetryServerAfterFailure) { + /* + * Don't do this twice - some of the error conditions already do this + * apparently. + */ + if (serverActive(drpServer)) { + markServerInactive(drpServer); + pCB->totalProb -= drpServer->probability; + } + } + returnValue = kDrpServiceError; + } + + return returnValue; +} + +/** + * drpService_server + * Use the current server to service the current request + * return: 0 == success; !0 == failure (details in pCB->serviceStatus) + */ +static DrpServiceStatus drpService_server(drpContextBlock * pCB) +{ + int returnValue = kDrpServiceOk; + +#ifdef _CPOOL + connectionPool *pool; +#endif + + /* If we think this server is down we will return a failure */ + if (serverSeemsDown(pCB->currentServer)) { + return kDrpServiceFailover; + } + + if (!connectedToCurrentServer(pCB)) { + +#ifdef _CPOOL + /* Hold on to the pool pointer in case we fail to connect + to this server compeletely in which case + pCB->currentServer will be set to NULL. + */ + pool = pCB->currentServer->pool; + returnValue = pooledConnectToCurrentServer(pCB); +#else + returnValue = connectToCurrentServer(pCB); +#endif + + if (returnValue) { + /* NB: don't log error; connectToCurrentServer will have done so */ + goto DRP_SVC_SERVER_EXIT; + } + } + + returnValue = sendBeginRequest(pCB); + + if (!pCB->isLoggedRequest) { + while ((pCB->serviceStatus < kServiceComplete) + && (returnValue == 0)) { + returnValue = handleDrpServerRequest(pCB); + } + } + /* + * We don't get any replies here + */ + else + pCB->serviceStatus = kServiceComplete; + + DRP_SVC_SERVER_EXIT: + +#ifdef _CPOOL + + /* Unless the Connection Pool is disabled, or the checkout + operation timed out, a connection has to be checked back + into the connection pool. + */ + if (gCP_Enabled && (returnValue != kCP_OperationTimedOut)) { + int result; + + if (pCB->currentServer) + result = checkinCP(pCB->currentServer->pool, + pCB->currentServer->sock); + /* Case where the current server has been set to + NULL + */ + else + result = checkinCP(pool, kInvalidSocket); + + switch (result) { + case kCP_CheckedIn:{ + if (pCB->currentServer) + pCB->currentServer->sock = kInvalidSocket; +/* + if (pCB->debugEnabled) { + char buf[100]; + sprintf(buf, "Checked In: pool %x : Available in pool = %d", + pool, + getAvailableCP(pool)); + pCB->logMessage(pCB->shellData, + kLog_Info, + kLogMessage_OneString, + buf, + NULL); + } +*/ + break; + } + case kCP_OperationTimedOut:{ +/* + if (pCB->debugEnabled) { + char buf[100]; + sprintf(buf, "Check In timed out: pool %x", pool); + pCB->logMessage(pCB->shellData, + kLog_Info, + kLogMessage_OneString, + buf, + NULL); + } +*/ + break; + } + case kCP_Full:{ +/* + if (pCB->debugEnabled) { + char buf[100]; + sprintf(buf, "Connection pool full: %x", pool); + pCB->logMessage(pCB->shellData, kLog_Info, + kLogMessage_OneString, + buf, + NULL); + } +*/ + break; + } + } + } +#endif + + return returnValue; +} + + +/** + * connectedToCurrentServer + * Determine whether this execution context has an active socket + * connection to the context block's current DRP server + * return: 0 == NOT connected; !0 == connected + */ +static int connectedToCurrentServer(drpContextBlock * pCB) +{ + int returnValue = 0; /* assume not */ + + if (pCB->currentServer && (pCB->currentServer->sock != kInvalidSocket)) { + fd_set checkSet; + int nfds; + struct timeval timeout; + + nfds = ((int) pCB->currentServer->sock) + 1; + + timeout.tv_sec = 0; + timeout.tv_usec = 0; + + FD_ZERO(&checkSet); + FD_SET(pCB->currentServer->sock, &checkSet); + if (select(nfds, &checkSet, NULL, NULL, &timeout)) { + /* socket has data ready to read; this is bad -- either we're out + of synch with server on the DRP protocol, or the conn has been + dropped by the server -- in either case, we should close it */ + closesocket(pCB->currentServer->sock); + pCB->currentServer->sock = kInvalidSocket; +/* + if (pCB->debugEnabled) { + char buf[256]; + sprintf(buf,"Closed bad connection to: %d.%d.%d.%d sock=%d", + pCB->currentServer->inetaddr & 0xff, + (pCB->currentServer->inetaddr >> 8) & 0xff, + (pCB->currentServer->inetaddr >> 16) & 0xff, + (pCB->currentServer->inetaddr >> 24) & 0xff, + pCB->currentServer->sock); + pCB->logMessage(pCB->shellData, kLog_Info, + kLogMessage_OneString, buf, NULL); + } +*/ + } else { + returnValue = 1; + } + } + + return returnValue; +} + + +#ifdef _CPOOL +/** + * pooledConnectToCurrentServer + * Establish a socket connection to the context block's current DRP server, + * or retrieve an existing socket connection from the connection pool. + * Note that this can block if the number of sockets managed by the + * connection pool exceeds + * return: 0 == success; !0 == failure + */ +static int pooledConnectToCurrentServer(drpContextBlock * pCB) +{ + int checkOutResult; + + /* If the connection pool is enabled first try to check + out a socket from the pool. + */ + if (gCP_Enabled) { + + gDebugInfo.numWaitingOnPool++; + checkOutResult = checkoutCP(pCB->currentServer->pool, + &(pCB->currentServer->sock)); + gDebugInfo.numWaitingOnPool--; + + switch (checkOutResult) { + case kCP_CheckedOut:{ + if (connectedToCurrentServer(pCB)) { +/* + if (pCB->debugEnabled) { + char buf[100]; + sprintf(buf, "Checked Out: pool %x : Available in pool = %d", + pCB->currentServer->pool, + getAvailableCP(pCB->currentServer->pool)); + pCB->logMessage(pCB->shellData, + kLog_Info, + kLogMessage_OneString, + buf, + NULL); + } +*/ + return 0; + } else { + /* We either got an invalid socket, or one that no + longer applies to this server. + */ + pCB->currentServer->sock = kInvalidSocket; + break; + } + } + case kCP_OperationTimedOut:{ + /* An attempt to get a socket from the connection pool was + timed out so we want to note that this is a sign that the + server seems to be down. + */ + + if (pCB->debugEnabled) { + char buf[100]; + sprintf(buf, "Check Out timed out: pool %x", + pCB->currentServer->pool); + pCB->logMessage(pCB->shellData, kLog_Info, + kLogMessage_OneString, buf, NULL); + } + noteDrpServerSeemsDown(pCB); + return kCP_OperationTimedOut; + } + } + } + /* + Where we actually attempt to connect. + */ + return connectToCurrentServer(pCB); +} +#endif + +/** + * connectToCurrentServer + * Establish a socket connection to the context block's current DRP server + * return: 0 == success; !0 == failure + */ +static int connectToCurrentServer(drpContextBlock * pCB) +{ + int returnValue = 0; + int onFlag = 1; + struct sockaddr_in addr; + time_t timeBefore = 0; + +#ifdef DEBUG + { + char buf[64]; + sprintf(buf, "max connect timeout is %d", pCB->maxConnectTimeout); + pCB->logMessage(pCB->shellData, kLog_Info, kLogMessage_OneString, + buf, NULL); + } +#endif + + timeBefore = time(NULL); + + gDebugInfo.numWaitingToConnect++; + + trysocketagain: + pCB->currentServer->sock = socket(AF_INET, SOCK_STREAM, 0); + if (pCB->currentServer->sock == kInvalidSocket) { + char errorNumber[12]; + + /* couldn't create a socket */ + sprintf(errorNumber, "%d", net_error()); + pCB->logMessage(pCB->shellData, kLog_Error, + kLogMessage_CannotCreateSocket, errorNumber, NULL); + returnValue = -1; + goto CONNECT_CURRENT_EXIT; + } else { + /* turn on keep-alive; ignore result */ + setsockopt(pCB->currentServer->sock, SOL_SOCKET, SO_KEEPALIVE, + (char *) &onFlag, sizeof(onFlag)); + /* turn off the nagle-algorithm, so that the system will send + teeny-weeny packets without farting around */ + setsockopt(pCB->currentServer->sock, IPPROTO_TCP, TCP_NODELAY, + (char *) &onFlag, sizeof(onFlag)); + + addr.sin_family = AF_INET; + addr.sin_port = htons(pCB->currentServer->port); + addr.sin_addr.s_addr = pCB->currentServer->inetaddr; + + tryagain: + returnValue = connect(pCB->currentServer->sock, + (struct sockaddr *) &addr, + sizeof(struct sockaddr)); + if (returnValue) { + char errorNumber[12]; + + int errorNum = net_error(); + if (errorNum == EINTR) + goto tryagain; + + if (errorNum == ETIMEDOUT) { + closesocket(pCB->currentServer->sock); + pCB->currentServer->sock = kInvalidSocket; + + if (pCB->debugEnabled) { + char buf[256]; + sprintf(buf, + "got ETIMEDOUT on connect to server: %lu.%lu.%lu.%lu sock=%d", + pCB->currentServer->inetaddr & 0xff, + (pCB->currentServer->inetaddr >> 8) & 0xff, + (pCB->currentServer->inetaddr >> 16) & 0xff, + (pCB->currentServer->inetaddr >> 24) & 0xff, + pCB->currentServer->sock); + pCB->logMessage(pCB->shellData, kLog_Info, + kLogMessage_OneString, buf, NULL); + } + if ((timeBefore > 0) && + (time(NULL) > (timeBefore + pCB->maxConnectTimeout))) { + noteDrpServerSeemsDown(pCB); + return kDrpServiceFailover; + } + goto trysocketagain; + } + + /* couldn't connect to current DRP server */ + sprintf(errorNumber, "%d", net_error()); + + if (!gRetryServerAfterFailure) { + /* Be sure not to do this twice for the same server! */ + if (serverActive(pCB->currentServer)) { + markServerInactive(pCB->currentServer); + pCB->totalProb -= pCB->currentServer->probability; + } + } + + /* + * Need to nuke this socket or else we'll wrongly think we are still + * connected! + */ + closesocket(pCB->currentServer->sock); + pCB->currentServer->sock = kInvalidSocket; + + pCB->logMessage(pCB->shellData, kLog_Error, + kLogMessage_CannotConnect, errorNumber, NULL); + pCB->currentServer = NULL; + goto CONNECT_CURRENT_EXIT; + } +/* + else if (pCB->debugEnabled) { + char buf[256]; + sprintf(buf,"Created new connection to: %d.%d.%d.%d sock=%d", + pCB->currentServer->inetaddr & 0xff, + (pCB->currentServer->inetaddr >> 8) & 0xff, + (pCB->currentServer->inetaddr >> 16) & 0xff, + (pCB->currentServer->inetaddr >> 24) & 0xff, + pCB->currentServer->sock); + pCB->logMessage(pCB->shellData, kLog_Info, + kLogMessage_OneString, buf, NULL); + } +*/ + } + + CONNECT_CURRENT_EXIT: + + gDebugInfo.numWaitingToConnect--; + + return returnValue; +} + + +/** + * sendBeginRequest + * Send BeginRequest packet to DRP server to start DRP service cycle + * return: 0 == success; !0 == failure + */ +static DrpServiceStatus sendBeginRequest(drpContextBlock * pCB) +{ + int returnValue = kDrpServiceOk; + drpByte beginType; + drpByte _0 = 0; + + gDebugInfo.numSendingRequest++; + + /* + * Use a different header byte if we are logging, not servicing + * this request + */ + if (pCB->isLoggedRequest) + beginType = kBeginLogRequest; + else + beginType = kBeginRequest; + + returnValue = sendByte(pCB, pCB->currentServer->sock, &beginType); + + /* also send: Method, PathInfo, ContentLength, PathTranslated, + Querystring, RequestURI, ServletPath, and all Headers */ + + /* method */ + if (returnValue == kDrpServiceOk) + returnValue = sendParameter(pCB, kMethod, NULL); + + /* path-info */ + if (returnValue == kDrpServiceOk) + returnValue = sendParameter(pCB, kPathInfo, NULL); + + /* content-length */ + if (returnValue == kDrpServiceOk) + returnValue = sendParameter(pCB, kContentLength, NULL); + + /* content-type */ + if (returnValue == kDrpServiceOk) + returnValue = sendParameter(pCB, kContentType, NULL); + + /* path-translated */ + if (returnValue == kDrpServiceOk) + returnValue = sendParameter(pCB, kPathTranslated, NULL); + + /* query-string */ + if (returnValue == kDrpServiceOk) + returnValue = sendParameter(pCB, kQueryString, NULL); + + /* request-uri */ + if (returnValue == kDrpServiceOk) + returnValue = sendParameter(pCB, kRequestURI, NULL); + + /* servlet-path */ + if (returnValue == kDrpServiceOk) + returnValue = sendParameter(pCB, kServletPath, NULL); + + /* + * In 3.0, we only send these values for logged requests. Turns out + * to be pretty common to want them and fairly slow to make the drp + * server come back to get them. Just send them all then.. + */ + if (returnValue == kDrpServiceOk) + returnValue = sendParameter(pCB, kScheme, NULL); + if (returnValue == kDrpServiceOk) + returnValue = sendParameter(pCB, kRemoteAddr, NULL); + if (returnValue == kDrpServiceOk) + returnValue = sendParameter(pCB, kServerName, NULL); + if (returnValue == kDrpServiceOk) + returnValue = sendParameter(pCB, kServerPort, NULL); + + /* + * In D4.0, I'm sending this as well. Now all of the headers should + * be there to avoid unnecessary GET_PARAMETERS calls + */ + if (returnValue == kDrpServiceOk) + returnValue = sendParameter(pCB, kProtocol, NULL); + + /* all headers */ + if (returnValue == kDrpServiceOk) + returnValue = handleGetAllHeaders(pCB); + + /* terminate NV-pair list */ + if (returnValue == kDrpServiceOk) + returnValue = sendByte(pCB, pCB->currentServer->sock, &_0); + + /* also send: block of data from agent (browser), if available */ + if (returnValue == kDrpServiceOk && !pCB->isLoggedRequest) { + int result; + + result = + pCB->readFromAgent(pCB->shellData, &pCB->ioBuffer, + pCB->ioBuffer.avail); + if (result == 0) { + returnValue = sendLong(pCB, pCB->currentServer->sock, + (drpInt *) & pCB->ioBuffer.used); + if (returnValue == kDrpServiceOk) + returnValue = sendBuffer(pCB, pCB->currentServer->sock, + &pCB->ioBuffer); + } else { + drpInt _0L = (drpInt) 0; + returnValue = sendLong(pCB, pCB->currentServer->sock, &_0L); + } + } + + if (returnValue == 0) { + returnValue = send_flush(pCB, pCB->currentServer->sock, 0); + } + + gDebugInfo.numSendingRequest--; + + return returnValue; +} + + +/** + * sendParameter + * find the value for a requested parameter and send the response to + * DRP server. (name-value pair is sent to DRP server, so this routine + * can be invoked several times to construct a DRP name-value pair list + * which must be terminated by the caller.) + * iParameter: if (0 < iParameter < kDefinedPlaceholder), the parameter + * sought is defined string iParameter; otherwise, iIdentParam + * iIdentParam: used as lookup paramete if iParameter does not correspond + * to a known defined string value + * return: 0 == success; !0 == failure + */ +static DrpServiceStatus +sendParameter(drpContextBlock * pCB, drpByte iDefinedParam, + drpIdentifier * iIdentParam) +{ + int returnValue = 0; + drpIdentifier paramName; + drpIdentifier *paramPtr = NULL; + drpByte _1 = 1; + + if ((iDefinedParam > 0) && (iDefinedParam < kDefinedPlaceholder)) { + /* we're looking up a defined-string parameter, iDefinedParam */ + + paramName.hasIndex = 0; + paramName.name.type = kDefined; + paramName.name.value.defined = iDefinedParam; + paramPtr = ¶mName; + } else if (iIdentParam) { + /* we're looking up a string parameter, iIdentParam */ + paramPtr = iIdentParam; + } else { + /* no good lookup parameter passed to us */ + returnValue = -1; + } + + returnValue = + pCB->getParameter(pCB->shellData, paramPtr, &pCB->ioBuffer2); + if (returnValue == 0) { + /* send "1" (indicating parameter pair follows) */ + returnValue = sendByte(pCB, pCB->currentServer->sock, &_1); + /* send the defined-string parameter name */ + if (returnValue == 0) + returnValue = + sendIdentifier(pCB, pCB->currentServer->sock, paramPtr); + /* send the parameter value */ + if (returnValue == 0) { + if (paramDemandsIntResponse((*paramPtr))) { + pCB->ioBuffer2.buffer[pCB->ioBuffer2.used] = kChar_Null; + returnValue = + sendIntTLiteral(pCB, pCB->currentServer->sock, + atol(pCB->ioBuffer2.buffer)); + } else { + returnValue = + sendAsciiTLiteral(pCB, pCB->currentServer->sock, + &pCB->ioBuffer2); + } + } + } + + return returnValue; +} + + +/** + * handleDrpServerRequest + * Receive and handle (i.e. respond appropriately to) one DRP packet + * from the current DRP server + * return: 0 == success; !0 == failure + * also: pCB->serviceStatus may change to reflect checkpoints in + * DRP cycle + */ +static DrpServiceStatus handleDrpServerRequest(drpContextBlock * pCB) +{ + int returnValue = kDrpServiceOk; + drpByte packetType; + + gDebugInfo.numWaitingForResponse++; + returnValue = recvByte(pCB, pCB->currentServer->sock, &packetType); + + if (returnValue == 0) { + switch (packetType) { + case kReply: + returnValue = handleReplyPacket(pCB); + break; + case kGetParameters: + returnValue = handleGetParameters(pCB); + break; + case kReadDataStream: + returnValue = handleReadData(pCB); + break; + + default: + /* unknown/unexpected packet type */ + returnValue = kDrpServiceProtocolError; + { + char packetTypeNumber[128]; + sprintf(packetTypeNumber, "value=%d status=%d", packetType, + pCB->serviceStatus); + pCB->logMessage(pCB->shellData, kLog_Error, + kLogMessage_InternalProtoError, + packetTypeNumber, NULL); + } + break; + } + } + gDebugInfo.numWaitingForResponse--; + return returnValue; +} + + +/** + * handleReplyPacket + * Receive and handle reply packet information (may include HTTP status + * information, reply headers, response data, etc); reply with success + * status to DRP server if requested by server. + * return: 0 == success; !0 == failure + */ +static DrpServiceStatus handleReplyPacket(drpContextBlock * pCB) +{ + /* This is error code for reads from dynamo */ + int returnValue = kDrpServiceOk; + drpByte sendHeader = 0; + drpByte flushData = 0; + drpByte closeData = 0; + drpByte endRequest = 0; + drpByte replyExpected = 0; + /* This has the return value of writes to the client */ + int result = 0; + drpByte _0 = 0; + drpByte _1 = 1; + + /* receive reply flags - should we flush, close, etc */ + returnValue = recvByte(pCB, pCB->currentServer->sock, &sendHeader); + if (returnValue == kDrpServiceOk) + returnValue = recvByte(pCB, pCB->currentServer->sock, &flushData); + if (returnValue == kDrpServiceOk) + returnValue = recvByte(pCB, pCB->currentServer->sock, &closeData); + if (returnValue == kDrpServiceOk) + returnValue = recvByte(pCB, pCB->currentServer->sock, &endRequest); + if (returnValue == kDrpServiceOk) + returnValue = + recvByte(pCB, pCB->currentServer->sock, &replyExpected); + + if ((sendHeader) && (returnValue == kDrpServiceOk)) { + /* also receive and handle header info */ + result = handleHeader(pCB); + } + + if (returnValue == kDrpServiceOk) { + /* also receive and send output data block */ + if (result == 0) { + returnValue = handleWriteData(pCB); + if (returnValue != kDrpServiceOk) { + result = -1; + /* + * Don't let this error cause the server to think that the request + * failed. + */ + returnValue = kDrpServiceOk; + /* + * We had to close the socket so the protocol is done. + */ + if (pCB->currentServer->sock == kInvalidSocket) { + pCB->serviceStatus = kServiceComplete; + return returnValue; + } + } + } + } + + /* handle miscellaneous reply flags */ + if (result == 0 && flushData) + result = handleFlush(pCB); + if (result == 0 && closeData) + result |= handleClose(pCB); + if (replyExpected) { + /* send 1 (success) or 0 (failure) in reply to DRP server */ + returnValue = sendByte(pCB, pCB->currentServer->sock, + ((result == 0) ? &_1 : &_0)); + if (returnValue == 0) + /* force the send */ + returnValue = send_flush(pCB, pCB->currentServer->sock, 0); + } + if (endRequest) { + + pCB->serviceStatus = kServiceComplete; + + if (endRequest == 2) { + closesocket(pCB->currentServer->sock); + pCB->currentServer->sock = kInvalidSocket; + } +#ifdef _CPOOL + if (gCP_Enabled) { + + if (endRequest == 2) { + /* + This is an incompatable configuration - we are pooling + connections on the CM side, but a DRPServer is closing + connections. + Therefore output an error message and disable pooling. + */ + if (pCB->debugEnabled) + pCB->logMessage(pCB->shellData, kLog_Info, + kLogMessage_OneString, + "DRPServer dropped connection when connection pool was enabled", + NULL); + gCP_Enabled = 0; + } + } +#endif /* _CPOOL */ + } + return returnValue; +} + + +/** + * handleGetParameters + * Satisfy a Get-Parameters DRP server request in progress. This routine + * (with subroutines) receives the DRP identifier-list from the drp server + * and responds with a full DRP name-value pair list (with terminator). + * return: 0 == success; !0 == failure + */ +static DrpServiceStatus handleGetParameters(drpContextBlock * pCB) +{ + int returnValue = kDrpServiceOk; + drpByte identDelim; + drpByte _0 = 0; + + if (pCB->serviceStatus < kExaminingRequest) + pCB->serviceStatus = kExaminingRequest; + /* as long as identDelim byte is 1, we've got more identifiers to + read from the list sent by the DRP server */ + returnValue = recvByte(pCB, pCB->currentServer->sock, &identDelim); + while ((identDelim == 1) && (returnValue == 0)) { + drpIdentifier paramName; + + returnValue = + recvIdentifier(pCB, pCB->currentServer->sock, ¶mName, + &pCB->ioBuffer); + if (returnValue == kDrpServiceOk) { + if (paramName.name.type == kDefined) { + /* special handling of defined-string requested parameters: + these parameters are divided into four groups; whenever a request + is made for a single element from any group, the values for + the entire group should be sent in response (the first group + is to be sent with the begin-request packet) */ + + switch (paramName.name.value.defined) { + case kMethod: + case kPathInfo: + case kContentLength: + case kPathTranslated: + case kQueryString: + case kRequestURI: + case kServletPath: + case kHeaders: + /* group 1 */ + returnValue = sendParameter(pCB, kMethod, NULL); + if (returnValue == kDrpServiceOk) + returnValue = sendParameter(pCB, kPathInfo, NULL); + if (returnValue == kDrpServiceOk) + returnValue = + sendParameter(pCB, kContentLength, NULL); + if (returnValue == kDrpServiceOk) + returnValue = + sendParameter(pCB, kPathTranslated, NULL); + if (returnValue == kDrpServiceOk) + returnValue = + sendParameter(pCB, kQueryString, NULL); + if (returnValue == kDrpServiceOk) + returnValue = + sendParameter(pCB, kRequestURI, NULL); + if (returnValue == kDrpServiceOk) + returnValue = + sendParameter(pCB, kServletPath, NULL); + if (returnValue == kDrpServiceOk) + returnValue = handleGetAllHeaders(pCB); + break; + + case kContentType: + case kAuthType: + /* group 2 */ + returnValue = sendParameter(pCB, kContentType, NULL); + if (returnValue == kDrpServiceOk) + returnValue = sendParameter(pCB, kAuthType, NULL); + break; + + case kRemoteAddr: + case kRemoteHost: + case kRemoteUser: + /* group 3 */ + returnValue = sendParameter(pCB, kRemoteAddr, NULL); + if (returnValue == kDrpServiceOk) + returnValue = + sendParameter(pCB, kRemoteHost, NULL); + if (returnValue == kDrpServiceOk) + returnValue = + sendParameter(pCB, kRemoteUser, NULL); + break; + + case kProtocol: + case kServerName: + case kServerPort: + case kScheme: + /* group 4 */ + returnValue = sendParameter(pCB, kProtocol, NULL); + if (returnValue == kDrpServiceOk) + returnValue = + sendParameter(pCB, kServerName, NULL); + if (returnValue == kDrpServiceOk) + returnValue = + sendParameter(pCB, kServerPort, NULL); + if (returnValue == kDrpServiceOk) + returnValue = sendParameter(pCB, kScheme, NULL); + break; + + case kParameters: + /* will never be requested by DRP 2.01 server */ + break; + + default: /* eh? what's that? */ + break; + } + } else { + /* sendParameter() takes care of sending result back to DRP server, + excluding final terminating 0 byte; passing kDefinedPlaceholder + (an invalid defined string) forces sendParameter to use paramName + as its lookup parameter */ + returnValue = + sendParameter(pCB, kDefinedPlaceholder, ¶mName); + } + } + + returnValue = recvByte(pCB, pCB->currentServer->sock, &identDelim); + } + + /* finish the NV-Pair response */ + if (returnValue == kDrpServiceOk) + returnValue = sendByte(pCB, pCB->currentServer->sock, &_0); + + if (returnValue == kDrpServiceOk) + /* force the send */ + returnValue = send_flush(pCB, pCB->currentServer->sock, 0); + + return returnValue; +} + + +/** + * handleGetAllHeaders + * Satisfy the DRP server's request for all Headers. this routine sends + * a single DRP2 name-value pair for each request header; it does _not_ + * send the terminator for the name-value pair list, so caller must. + * return: 0 == success; !0 == failure + */ +static DrpServiceStatus handleGetAllHeaders(drpContextBlock * pCB) +{ + int returnValue = kDrpServiceOk; + drpByte _1 = 1; + int headerNum = 0; + + do { + returnValue = + pCB->getNthHeader(pCB->shellData, headerNum, &pCB->ioBuffer, + &pCB->ioBuffer2); + if ((pCB->ioBuffer.used > 0) && (returnValue == 0)) { + /* send byte: NV-Pair follows */ + returnValue = sendByte(pCB, pCB->currentServer->sock, &_1); + if (returnValue == 0) { + /* send indexed NV pair: ("headername"[headernum], header-name) */ + returnValue = + sendIntIndexedPair(pCB, pCB->currentServer->sock, + kHeaderName, headerNum, + pCB->ioBuffer.buffer); + /* send byte: NV-Pair follows */ + returnValue = sendByte(pCB, pCB->currentServer->sock, &_1); + if (returnValue == kDrpServiceOk) + /* send indexed NV pair: ("headerval"[headernum], header-val) */ + returnValue = + sendIntIndexedPair(pCB, pCB->currentServer->sock, + kHeaderVal, headerNum, + pCB->ioBuffer2.buffer); + } + } + headerNum++; + } while ((pCB->ioBuffer.used > 0) && (returnValue == kDrpServiceOk)); + + /* do _not_ send 0x00 (NV-Pair terminating byte); caller will handle */ + + return returnValue; +} + + +/** + * handleReadData + * Satisfy a Read-Data DRP server request in progress. This routine + * receives the maximum requested bytes value (4 bytes) from the drp + * server, and sends the data packet with agent data (or failure indicator). + * return: 0 == success; !0 == failure + */ +static DrpServiceStatus handleReadData(drpContextBlock * pCB) +{ + int returnValue = kDrpServiceOk; + size_t length; + drpByte _1 = 1; + drpByte _0 = 0; + size_t bytesToPipe = 0; + + if (pCB->serviceStatus < kServicingRequest) + pCB->serviceStatus = kServicingRequest; + returnValue = + recvLong(pCB, pCB->currentServer->sock, (drpInt *) & length); + if ((length > 0) && (returnValue == kDrpServiceOk)) { + int result; + + /* NB: don't propagate a non-zero return from readFromAgent as an + error return from handleReadData (which will be interpreted as a + DRP-server related error) */ + + bytesToPipe = MIN(length, pCB->ioBuffer.avail); + pCB->ioBuffer.used = 0; + result = pCB->readFromAgent(pCB->shellData, &pCB->ioBuffer, + bytesToPipe); + if (result == 0) { + returnValue = sendByte(pCB, pCB->currentServer->sock, &_1); + if (returnValue == kDrpServiceOk) + returnValue = sendLong(pCB, pCB->currentServer->sock, + (drpInt *) & pCB->ioBuffer.used); + if (returnValue == kDrpServiceOk) + returnValue = sendBuffer(pCB, pCB->currentServer->sock, + &pCB->ioBuffer); + } else { + /* send failure byte */ + sendByte(pCB, pCB->currentServer->sock, &_0); + } + } else { + /* send failure byte */ + sendByte(pCB, pCB->currentServer->sock, &_0); + } + + if (returnValue == kDrpServiceOk) { + returnValue = send_flush(pCB, pCB->currentServer->sock, 0); + } + + return returnValue; +} + + +/** + * handleWriteData + * Satisfy a Write-Data DRP server request in progress. This routine + * receives the data packet (length and data) to be written to the agent + * from the DRP server, and attempts to write that data to the agent. + * return: 0 == success; !0 == failure + */ +static DrpServiceStatus handleWriteData(drpContextBlock * pCB) +{ + int returnValue = kDrpServiceOk; + size_t length; + drpByte success = 1; + size_t bytesPiped = 0; + size_t bytesToPipe = 0; + + if (pCB->serviceStatus < kServicingRequest) + pCB->serviceStatus = kServicingRequest; + returnValue = + recvLong(pCB, pCB->currentServer->sock, (drpInt *) & length); + if ((length > 0) && (returnValue == kDrpServiceOk)) { + if (pCB->statusSetByServer && (!pCB->statusSentToAgent)) { + returnValue = doSendHeader(pCB); + /* + * We must complete the request even if sending the headers fails + * In particular, we have to read the data from the client or else + * the protocol will get screwed up. + */ + if (returnValue != kDrpServiceOk) { + success = 0; + returnValue = kDrpServiceOk; + } + } + while ((bytesPiped < length) && (returnValue == kDrpServiceOk)) { + bytesToPipe = MIN(length - bytesPiped, pCB->ioBuffer.avail); + returnValue = recvBuffer(pCB, pCB->currentServer->sock, + &pCB->ioBuffer, bytesToPipe); + if (returnValue == kDrpServiceOk) { + /* NB: don't propagate a non-zero return from writeToAgent as an + error return from handleWriteData (which will be interpreted as + a DRP-server related error) */ + int result; + + result = pCB->writeToAgent(pCB->shellData, &pCB->ioBuffer, + bytesToPipe); + if (result != 0) { + success = 0; + /* + * Return an error so that this gets reported to dynamo + * after the request. + */ + returnValue = kDrpServiceError; + + /* + * Close the socket right here. This will give the immediate + * feedback to the DRP thread regardless of whether or not + * we are doing "dropConnectionAfterRequest". It also spares + * us from having to finish reading all of the data for this + * request (which has been aborted by the user). It does have + * the overhead that we'll need to create a new socket for + * the next request but that is not a big hit + */ + closesocket(pCB->currentServer->sock); + pCB->currentServer->sock = kInvalidSocket; + break; /* out of while loop */ + } + } else { + /* recv (from server) not successful */ + success = 0; + break; /* out of while loop */ + } + bytesPiped += bytesToPipe; + } + } else { + success = 0; + } + + return returnValue; +} + + +/** + * handleFlush + * Satisfy a Flush-Data-Stream DRP server request in progress. + * return: 0 == success; !0 == failure + */ +static DrpServiceStatus handleFlush(drpContextBlock * pCB) +{ + int returnValue = kDrpServiceOk; + drpByte success = 1; + int result; + + /* NB: don't propagate a non-zero return from flushData as an + error return from handleFlush (which will be interpreted as a + DRP-server related error) */ + + result = pCB->flushData(pCB->shellData); + if (result != 0) + success = 0; + + return returnValue; +} + + +/** + * handleClose + * Satisfy a Close-Data-Stream DRP server request in progress. + * return: 0 == success; !0 == failure + */ +static DrpServiceStatus handleClose(drpContextBlock * pCB) +{ + int returnValue = kDrpServiceOk; + drpByte success = 1; + int result; + + /* NB: don't propagate a non-zero return from closeData as an + error return from handleClose (which will be interpreted as a + DRP-server related error) */ + + result = pCB->closeData(pCB->shellData); + if (result != 0) + success = 0; + + return returnValue; +} + + +/** + * handleHeader + * Satisfy a Send-Header DRP server request in progress. This routine + * (with subroutines) receives status code and message and response + * headers, and distributes headers and status info to agent. + * return: 0 == success; !0 == failure + */ +static DrpServiceStatus handleHeader(drpContextBlock * pCB) +{ + int returnValue = kDrpServiceOk; + drpByte shouldSend = 0; + drpByte success = 1; + + returnValue = + recvLong(pCB, pCB->currentServer->sock, &pCB->statusCode); + if (returnValue == kDrpServiceOk) { + returnValue = recvTLiteral(pCB, pCB->currentServer->sock, + &pCB->statusMesg, &pCB->statusBuffer); + } + if (returnValue == kDrpServiceOk) + returnValue = recvByte(pCB, pCB->currentServer->sock, &shouldSend); + + if (pCB->shellExpectsHeaderPairs) { + returnValue = dispatchHeaders(pCB); + } else { + returnValue = batchHeaders(pCB); + } + + pCB->statusSetByServer = 1; + + if (shouldSend && (returnValue == kDrpServiceOk)) { + returnValue = doSendHeader(pCB); + } + + if (returnValue != kDrpServiceOk) + success = 0; + + return returnValue; +} + + +/** + * dispatchHeaders + * Retrieve header pairs from DRP server and dispatch them to shell (for + * those shells that expect headers to come one pair at a time) + * return: 0 == success; !0 == failure + */ +static DrpServiceStatus dispatchHeaders(drpContextBlock * pCB) +{ + int returnValue = kDrpServiceOk; + drpByte pairDelim; + + returnValue = recvByte(pCB, pCB->currentServer->sock, &pairDelim); + while ((pairDelim == 1) && (returnValue == 0)) { + drpIdentifier headerName; + drpTLiteral headerVal; + + pCB->ioBuffer.used = 0; /* "clear" ioBuffer */ + returnValue = + recvIdentifier(pCB, pCB->currentServer->sock, &headerName, + &pCB->ioBuffer); + if (returnValue == kDrpServiceOk) { + pCB->ioBuffer2.used = 0; /* "clear" ioBuffer2 */ + returnValue = + recvTLiteral(pCB, pCB->currentServer->sock, &headerVal, + &pCB->ioBuffer2); + if (returnValue == kDrpServiceOk) { + pCB->headers.used = 0; /* "clear" headers buffer */ + identToAscii(pCB->definedStringLength, + pCB->definedStringToAscii, pCB->shellData, + &headerName, &pCB->headers); + pCB->headers2.used = 0; /* "clear" headers2 buffer */ + tliteralToAscii(pCB->definedStringLength, + pCB->definedStringToAscii, pCB->shellData, + &headerVal, &pCB->headers2); + returnValue = + pCB->setResponseHeader(pCB->shellData, &pCB->headers, + &pCB->headers2); + } + } + if (returnValue == kDrpServiceOk) + returnValue = + recvByte(pCB, pCB->currentServer->sock, &pairDelim); + } + + return returnValue; +} + + +/** + * batchHeaders + * Dump headers from the DRP server into an ascii buffer (for those shells + * that expect headers to come in one big lump) + * return: 0 == success; !0 == failure + */ +static DrpServiceStatus batchHeaders(drpContextBlock * pCB) +{ + int returnValue = kDrpServiceOk; + drpByte pairDelim; + + returnValue = recvByte(pCB, pCB->currentServer->sock, &pairDelim); + while ((pairDelim == 1) && (returnValue == kDrpServiceOk)) { + drpIdentifier headerName; + drpTLiteral headerVal; + + pCB->ioBuffer.used = 0; /* "clear" ioBuffer */ + returnValue = + recvIdentifier(pCB, pCB->currentServer->sock, &headerName, + &pCB->ioBuffer); + if (returnValue == kDrpServiceOk) { + identToAscii(pCB->definedStringLength, + pCB->definedStringToAscii, pCB->shellData, + &headerName, &pCB->headers); + concatenate(&pCB->headers, kString_HeaderNVDelim); + pCB->ioBuffer.used = 0; /* "clear" ioBuffer */ + returnValue = + recvTLiteral(pCB, pCB->currentServer->sock, &headerVal, + &pCB->ioBuffer); + if (returnValue == kDrpServiceOk) { + tliteralToAscii(pCB->definedStringLength, + pCB->definedStringToAscii, pCB->shellData, + &headerVal, &pCB->headers); + concatenate(&pCB->headers, kString_Newline); + } + } + returnValue = recvByte(pCB, pCB->currentServer->sock, &pairDelim); + } + concatenate(&pCB->headers, kString_Newline); + + return returnValue; +} + + +/** + * identToAscii + * Copy an ascii representation of a DRP Identifier object onto the end + * of the supplied buffer. (Grows buffer as necessary.) + */ +void +identToAscii(DefinedLength_fn iDefinedLength, + DefinedAscii_fn iDefinedAscii, void *pShellData, + const drpIdentifier * iIdent, growBuffer * oBuffer) +{ + /* NB: ignoring index */ + tliteralToAscii(iDefinedLength, iDefinedAscii, pShellData, + &iIdent->name, oBuffer); +} + + +/** + * tliteralToAscii + * Copy an ascii representation of a DRP Typed Literal object onto the end + * of the supplied buffer. (Grows buffer as necessary.) + */ +void +tliteralToAscii(DefinedLength_fn iDefinedLength, + DefinedAscii_fn iDefinedAscii, void *pShellData, + const drpTLiteral * iTLiteral, growBuffer * oBuffer) +{ + size_t result; + size_t c; + + switch (iTLiteral->type) { + case kInteger: + ensureGrowBufferSize_m(oBuffer, (oBuffer->used + 16)); + result = sprintf(oBuffer->buffer + oBuffer->used, "%ld", + iTLiteral->value.integer); + oBuffer->used += result; + break; + case kDefined: + result = iDefinedLength(pShellData, iTLiteral->value.defined); + if (result > 0) { + ensureGrowBufferSize_m(oBuffer, (oBuffer->used + result)); + } + result = sprintf(oBuffer->buffer + oBuffer->used, "%s", + iDefinedAscii(pShellData, + iTLiteral->value.defined)); + oBuffer->used += result; + break; + case kAscii: + ensureGrowBufferSize_m(oBuffer, + (oBuffer->used + iTLiteral->numChars)); + memmove(oBuffer->buffer + oBuffer->used, iTLiteral->value.ascii, + iTLiteral->numChars); + oBuffer->used += iTLiteral->numChars; + oBuffer->buffer[oBuffer->used] = kChar_Null; + break; + case kUnicode: + ensureGrowBufferSize_m(oBuffer, + (oBuffer->used + iTLiteral->numChars)); + for (c = 0; c < iTLiteral->numChars; c++) { + oBuffer->buffer[oBuffer->used++] = + ((char *) iTLiteral->value.unicode)[2 * c + 1]; + } + oBuffer->buffer[oBuffer->used] = kChar_Null; + break; + case kNull: + /* intentional fall-through */ + default: + break; + } +} + + +/** + * doSendHeader + * Send HTTP header information to user agent + * return: 0 == success; !0 == failure + */ +static DrpServiceStatus doSendHeader(drpContextBlock * pCB) +{ + int returnValue = kDrpServiceOk; + + pCB->statusSentToAgent = 1; + + if (pCB->statusMesg.type > kNull) { + pCB->ioBuffer.used = 0; + tliteralToAscii(pCB->definedStringLength, + pCB->definedStringToAscii, pCB->shellData, + &pCB->statusMesg, &pCB->ioBuffer); + } else { + pCB->ioBuffer.buffer[0] = kChar_Null; + pCB->ioBuffer.used = 0; + } + + if (pCB->shellExpectsHeaderPairs) { + returnValue = + pCB->sendHeaderNoBatch(pCB->shellData, pCB->statusCode, + pCB->ioBuffer.buffer, + pCB->ioBuffer.used); + } else { + returnValue = pCB->sendHeaderBatch(pCB->shellData, pCB->statusCode, + pCB->ioBuffer.buffer, + pCB->ioBuffer.used, + pCB->headers.buffer, + pCB->headers.used); + } + + return returnValue; +} + + +/** + * bitcpy32 + * NB: macro, modifies d (destination) in place + * d: destination (4 bytes) + * db: destination offset, in bits + * s: source (4 bytes) + * sb: source offset, in bits + * "copies" up to 32 bits from s (offset sb) to d (offset db) + */ +#define bitcpy32(d,db,s,sb) \ + ((d) |= \ + ((db) > (sb) ? \ + (((long) (s)) << ((db) - (sb))) : \ + (((long) (s)) >> ((sb) - (db))))) + +/** + * bitcpy16 + * NB: macro, modifies d (destination) in place + * d: destination (2 bytes) + * db: destination offset, in bits + * s: source (2 bytes) + * sb: source offset, in bits + * "copies" up to 16 bits from s (offset sb) to d (offset db) + */ +#define bitcpy16(d,db,s,sb) \ + ((d) |= \ + ((db) > (sb) ? \ + (((short) (s)) << ((db) - (sb))) : \ + (((short) (s)) >> ((sb) - (db))))) + + +/** + * getDrpServerInfoFromSid + * From the session-ID stored in pCB, extract the the address and port + * of the DRP server that issued the SID. + * oAddr: will be filled in with address of DRP server (if return is 0) + * oPort: will be filled in with port of DRP server (if return is 0) + * return: 0 == success; !0 == failure + */ +static int +getDrpServerInfoFromSid(drpContextBlock * pCB, unsigned long *oAddr, + unsigned short *oPort) +{ + /* + adapted from Nate-o-rama's documentation of the d3 session id format + (atg.servlet.sessiontracking.SessionManager): + + The generated id's are based on a byte array with + the following format: + bytes 0-3: hash based on counter and start time + bytes 4-7: counter + bytes 8-11: host IP addr + The byte array is then converted to a String. The byte array is + broken down into groups of 5 bits, and each group's value (0-31) is + used to form a character from the character set 'A'-'Z', '0'-'5'. + */ + + int returnValue = kDrpServiceOk; + char addrInts[8]; + char portInts[4]; + int c; + char *id = pCB->sessionID; + + /* DRP server IP address: + convert relevant characters from session ID into array of byte integers */ + for (c = 0; c < 8; c++) { + if ((id[c + 12] >= 'A') && (id[c + 12] <= 'Z')) + addrInts[c] = id[c + 12] - 'A'; + else if ((id[c + 12] >= '0') && (id[c + 12] <= '5')) + addrInts[c] = id[c + 12] - '0' + 26; + else { + char badChar[2]; + char buf[128]; + badChar[0] = id[c + 12]; + badChar[1] = kChar_Null; + sprintf(buf, "(case 1) session id='%s', char='%s'(0x%x)", + pCB->sessionID, badChar, (int) id[c + 12]); + + pCB->logMessage(pCB->shellData, kLog_Warn, + kLogMessage_BadSIDCharacter, buf, NULL); + + if (pCB->debugEnabled) { + drpIdentifier cookieHeaderName; + int result; + cookieHeaderName.hasIndex = 0; + cookieHeaderName.name.type = kAscii; + cookieHeaderName.name.numChars = + strlen(kCookieHeaderName) + 1; + cookieHeaderName.name.value.ascii = kCookieHeaderName; + + result = + pCB->getParameter(pCB->shellData, &cookieHeaderName, + &pCB->ioBuffer); + if (result == 0) { + pCB->ioBuffer.buffer[pCB->ioBuffer.used] = kChar_Null; + sprintf(buf, "cookie header is='%s'", + pCB->ioBuffer.buffer); + pCB->logMessage(pCB->shellData, kLog_Info, + kLogMessage_OneString, buf, NULL); + } else { + pCB->logMessage(pCB->shellData, kLog_Info, + kLogMessage_OneString, + "no cookie header present", NULL); + } + } + returnValue = -1; + } + } + + /* DRP server port: + convert relevant characters from session ID into array of byte integers */ + if (returnValue == 0) + for (c = 0; c < 4; c++) { + if ((id[c + 19] >= 'A') && (id[c + 19] <= 'Z')) + portInts[c] = id[c + 19] - 'A'; + else if ((id[c + 19] >= '0') && (id[c + 19] <= '5')) + portInts[c] = id[c + 19] - '0' + 26; + else { + char badChar[2]; + char buf[128]; + + badChar[0] = id[c + 19]; + badChar[1] = kChar_Null; + sprintf(buf, "(case 2) session id='%s', char='%s'(0x%x)", + pCB->sessionID, badChar, (int) id[c + 12]); + + pCB->logMessage(pCB->shellData, kLog_Warn, + kLogMessage_BadSIDCharacter, badChar, + NULL); + if (pCB->debugEnabled) { + drpIdentifier cookieHeaderName; + int result; + cookieHeaderName.hasIndex = 0; + cookieHeaderName.name.type = kAscii; + cookieHeaderName.name.numChars = + strlen(kCookieHeaderName) + 1; + cookieHeaderName.name.value.ascii = kCookieHeaderName; + + result = + pCB->getParameter(pCB->shellData, + &cookieHeaderName, + &pCB->ioBuffer); + if (result == 0) { + pCB->ioBuffer.buffer[pCB->ioBuffer.used] = + kChar_Null; + sprintf(buf, "cookie header is='%s'", + pCB->ioBuffer.buffer); + pCB->logMessage(pCB->shellData, kLog_Info, + kLogMessage_OneString, buf, NULL); + } else { + pCB->logMessage(pCB->shellData, kLog_Info, + kLogMessage_OneString, + "no cookie header present", NULL); + } + } + returnValue = kDrpServiceBadSID; + } + } + + if (returnValue == kDrpServiceOk) { + /* DRP server IP address: + pack bits from drp server int array into *oAddr */ + *oAddr = 0; + bitcpy32(*oAddr, 31, addrInts[0], 0); + for (c = 0; c < 6; c++) + bitcpy32(*oAddr, 30 - c * 5, addrInts[c + 1], 4); + bitcpy32(*oAddr, 0, addrInts[7], 4); + /* NB: *oAddr is in host byte-order, because we reconstructed it by + value rather than receiving it in a specific order; but, it has + to be in network byte-order for the network calls. so munge it. */ + *oAddr = htonl(*oAddr); + + /* DRP server port: + pack bits from drp server int array into *oPort */ + *oPort = 0; + bitcpy16(*oPort, 15, portInts[0], 3); + bitcpy16(*oPort, 11, portInts[1], 4); + bitcpy16(*oPort, 6, portInts[2], 4); + bitcpy16(*oPort, 1, portInts[3], 4); + /* NB: *oPort is in host byte-order, because we recontsructed it by + value rather than receiving it in a specific byte order. + so leave it. */ + } + + return returnValue; +} + +/* Sets the value of a grow buffer. + * Return: 0 == success; !0 == failure + */ +int setGrowBuffer(growBuffer * b, const char *s) +{ + clearGrowBuffer_m(b); + return concatenate(b, s); +} + + +/** + * concatenate + * Concatenate a character string onto the end of pBuffer, growing + * pBuffer if necessary. + * return: 0 == success; !0 == failure + */ +int concatenate(growBuffer * pBuffer, const char *iString) +{ + int returnValue = kDrpServiceOk; + int stringLength = strlen(iString); + + ensureGrowBufferSize_m(pBuffer, (pBuffer->used + stringLength + 1)); + pBuffer->buffer[pBuffer->used] = kChar_Null; + strcat(pBuffer->buffer, iString); + pBuffer->used += stringLength; + + return returnValue; +} + + +/** + * createGrowBuffer + * creates a new growable buffer structure with at least iInitialSize bytes + * bytes allocated to the buffer field. + * returns: new growBuffer object + */ +growBuffer *createGrowBuffer(growBuffer * pBuffer, size_t iInitialSize) +{ + if (pBuffer != NULL) + pBuffer->allocated = 0; + else { + pBuffer = (growBuffer *) malloc(sizeof(growBuffer)); + if (pBuffer == NULL) + return NULL; + pBuffer->allocated = 1; + } + pBuffer->used = 0; + pBuffer->avail = iInitialSize + 1; + pBuffer->buffer = (char *) malloc(sizeof(char) * pBuffer->avail); + if (pBuffer->buffer == NULL) { + if (pBuffer->allocated) + free(pBuffer); + return NULL; + } + + return pBuffer; +} + + +/** + * growGrowBuffer + * increases the allocation of the buffer field of the indicated + * growable buffer object by at least iGrowSize bytes. + * return: 0 == success; !0 == failure (i.e. allocation failure) + */ +int growGrowBuffer(growBuffer * pBuffer, size_t iGrowSize) +{ + int returnValue = kDrpServiceOk; + + pBuffer->avail += iGrowSize; + pBuffer->buffer = realloc(pBuffer->buffer, pBuffer->avail); + if (!pBuffer->buffer) + returnValue = kDrpServiceNoMemory; + + return returnValue; +} + +/** + * destroyGrowBuffer + * frees up a growBuffer's resources. + */ +void destroyGrowBuffer(growBuffer * pBuffer) +{ + free(pBuffer->buffer); + if (pBuffer->allocated) + free(pBuffer); +} + +/** + * hostToInetAddr + * Given a host address string (either IP address or host name), return + * a corresponding internet address value. + * iHost: host address string (IP or host name). + * return: internet address value; INADDR_NONE (see DRPTypes.h) on failure. + */ +unsigned long hostToInetAddr(const char *iHost) +{ + unsigned long addr; + + /* first, try inet_addr to see if the host is in dotted-decimal form */ + addr = inet_addr(iHost); + if (addr == INADDR_NONE) { + /* second, try gethostbyname */ + struct hostent *he = gethostbyname(iHost); + struct sockaddr_in sa_in; + + if (he != NULL) { + memcpy(&sa_in.sin_addr, he->h_addr, he->h_length); + addr = (unsigned long) sa_in.sin_addr.s_addr; + } + } + + return addr; +} + +#if 0 +/* the following routines were obsoleted with the change from "DRP 2.0" + to "DRP 2.01" (my fake version numbers) */ + +/** + * handleGetAllParameters + * Satisfy the DRP server's request for all Parameters + * return: 0 == success; !0 == failure + */ +static DrpServiceStatus handleGetAllParameters(drpContextBlock * pCB) +{ + int returnValue = kDrpServiceOk; + drpIdentifier paramName; + int namePtr = 0; + int valPtr = 0; + int nextPtr = 0; + int queryLength = 0; + drpByte _1 = 1; + + paramName.name.type = kDefined; + paramName.name.value.defined = kQueryString; + paramName.hasIndex = 0; + + returnValue = + pCB->getParameter(pCB->shellData, ¶mName, &pCB->ioBuffer2); + + if ((pCB->ioBuffer2.used > 0) && (returnValue == kDrpServiceOk)) { + queryLength = strlen(pCB->ioBuffer2.buffer); + while ((nextPtr < queryLength) && (returnValue == kDrpServiceOk)) { + namePtr = nextPtr; + if (pCB->ioBuffer2.buffer[namePtr] == kChar_Null) + break; /* out of while loop */ + getNextQueryArg(pCB->ioBuffer2.buffer, namePtr, &valPtr, + &nextPtr); + /* send byte: NV-Pair follows */ + returnValue = sendByte(pCB, pCB->currentServer->sock, &_1); + if (returnValue == 0) + returnValue = + sendNameIndexedPair(pCB, pCB->currentServer->sock, + kParameter, + pCB->ioBuffer2.buffer + namePtr, + pCB->ioBuffer2.buffer + valPtr); + } + } + + /* do _not_ send 0x00 (NV-Pair terminating byte); caller will handle */ + + return returnValue; +} + + +/** + * getNextQueryArg + * obtain the next query argument from the query argument list + */ +static void +getNextQueryArg(char *pBuffer, int namePtr, int *oValPtr, int *oNextPtr) +{ + char *valCharPtr; + char *nextCharPtr; + + /* name known to start at namePtr */ + + /* first: find where this query argument ends and null-terminate it */ + nextCharPtr = strchr(pBuffer + namePtr, kChar_Ampersand); + if (!nextCharPtr) + nextCharPtr = strchr(pBuffer + namePtr, kChar_Null); + *nextCharPtr = kChar_Null; + + /* second: find next occurrence of '=' */ + valCharPtr = strchr(pBuffer + namePtr, kChar_Equals); + if (!valCharPtr) + valCharPtr = nextCharPtr; + else { + /* null-terminate the name, and move the val ptr ahead to 1st char of + value */ + *valCharPtr = kChar_Null; + valCharPtr++; + } + + /* now: namePtr indicates 1st char of name, which is null-terminated. + valCharPtr is either 1st char of value, or null if no value. + nextCharPtr is terminating char of value (or name, if no value). */ + + nextCharPtr++; /* move next ptr ahead to 1st char of next arg */ + + *oValPtr = valCharPtr - pBuffer; + *oNextPtr = nextCharPtr - pBuffer; +} +#endif diff --git a/mk4/moddynamo/DRPClient.h b/mk4/moddynamo/DRPClient.h new file mode 100644 index 0000000..19cd9df --- /dev/null +++ b/mk4/moddynamo/DRPClient.h @@ -0,0 +1,440 @@ +/* + * Copyright (C) 1997 Art Technology Group, Inc. + * All Rights Reserved. No use, copying or distribution of this + * work may be made except in accordance with a valid license + * agreement from Art Technology Group. This notice must be + * included on all copies, modifications and derivatives of this + * work. + * + * Art Technology Group (ATG) MAKES NO REPRESENTATIONS OR WARRANTIES + * ABOUT THE SUITABILITY OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. ATG SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, + * MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. + * + * "Dynamo" is a trademark of Art Technology Group, Inc. + */ + +/* + DRPClient.h - public API for DRP client routines + */ + +#ifndef _DRP_CLIENT_H_ +#define _DRP_CLIENT_H_ + +#include "DRPTypes.h" + +#ifdef _CPOOL +#include "connectionPool.h" +#endif + +/* constants */ + +/* orig. size of main (per-context) buffers */ +#define kMainBufferSize 4096 + +/* orig. size of minor storage buffers */ +#define kMinorBufferSize 1024 + +/* max # of DRP servers for which the CM will keep information */ +#define kMaxDRPRecords 100 + +/* length of session ID */ +#define kMaxSessionIDLength 256 + +/* size of IO buffers used for buffered send/recv */ +#define kSockBufSize 4200 + +/* default total time to go around a loop calling connect() and + * getting a timeout + */ +#define kDRP_DefaultMaxConnectTimeout 30 /* seconds */ + +/* checkpoints in the service of a request */ +enum { + kIdle = 0, + + kConnectingToServer, + kExaminingRequest, + kNotificationInProgress, + kServicingRequest, + + kServiceComplete, + kNotificationComplete, + + kServiceError, + + kServiceStatusPlaceholder +}; + +/* status values returned from drpService */ +typedef enum DrpServiceStatus { + kDrpServiceOk = 0, /* service request succeeded */ + kDrpServiceError = -1, /* service request failed nonrecoverably */ + kDrpServiceNoServer = -2, /* service request failed because no server + * could satisfy it. */ + kDrpServiceFailover = -3, /* load-managed service request failed; failover + * should be attempted */ + kDrpServiceNoMemory = -4, /* service request failed due to lack of server + * memory */ + kDrpServiceProtocolError = -5, /* service request failed due to a protocol + * error */ + kDrpServiceBadSID = -6, /* service request failed due to bad SID */ +} DrpServiceStatus; + +/* HTTP response information for kDrpServiceFailover handling */ +#define kFailoverStatusCode 302 /* Moved Temporarily */ +#define kFailoverStatusMessage "Application failure, use alternate server" + +void drpSetFailoverServer(const char* newServer); + +void drpSetSessionCookieName(const char* cookieName); + +/* type definitions */ + +typedef struct _sockBuf sockBuf; + +/* SockBuf: IO buffer used for buffered send/recv */ +struct _sockBuf { + char * data; + size_t capacity; /* # bytes allocated to data field */ + size_t used; /* # bytes of data in data field */ + size_t curPtr; /* indicates next byte in buffer to "recv" */ +}; + + +typedef struct _drpContextBlock drpContextBlock; +typedef struct _drpServerRecord drpServerRecord; + + +/* DRPServerRecord: maintains information about a single DRP2 server */ +struct _drpServerRecord { + socket_t sock; /* socket connection to the DRP2 server */ + unsigned long inetaddr; /* IP address of DRP2 server */ + unsigned short port; /* port of DRP2 server */ + unsigned short probability; /* weight used to determine selection of + DRP2 server from list; see + DRPClient.c:drpService_load() */ + unsigned short flags; /* per-server flags, e.g. "active" */ +#ifdef _CPOOL + connectionPool *pool; /* per-server connection pool */ +#endif +}; + + +/** SHELL CALLBACK FUNCTION TYPE DEFINITIONS **/ +/* these prototypes indicate the callback interface used by the DRP2 client + to access functionality in the CM "shell" specific to each server API */ + +/** + * GetParameter_fn + * Retrieve the value (in ascii) for a request parameter (e.g. URI, + * server port, etc). + * pShellData: shell-specific (request-specific) data object + * iName: incdicates parameter to retrieve + * oVal: (growable) buffer in which to store parameter value (in ascii) + * (if no value found, return successfully with empty oVal buffer) + * return: 0 == success; !0 == failure (other than val not found) + */ +typedef int (* GetParameter_fn) + (void * pShellData , const drpIdentifier * iName, growBuffer * oVal); + +/** + * GetNthHeader_fn + * Retrieve the name and value (in ascii) of the nth request header. + * pShellData: shell-specific (request-specific) data object + * iHeaderNum: 0-based index of header to retrieve + * oName, oVal: (growable) buffers in which to store header name and value + * (in ascii) (if no header for iHeaderNum, return successfully + * with empty name and val buffers) + * return: 0 == success; !0 == failure (other than no such header) + */ +typedef int (* GetNthHeader_fn) + (void * pShellData, int iHeaderNum, growBuffer * oName, + growBuffer * oVal); + +/** + * ReadFromAgent_fn + * Read at most iMaxLength bytes from the user agent (browser). + * pShellData: shell-specific (request-specific) data object + * oBuffer: buffer in which to store data read from browser; this callback + * should not increase the size available in oBuffer + * iMaxLength: maximum number of bytes to read from agent; actual number of + * bytes read is indicated via oBuffer->used. guaranteed to be + * <= bytes available in oBuffer. + * return: 0 == success (including EOF); !0 == failure (other than EOF) + * note: if the data stream to the agent has been closed (physically or + * logically), return failure. + */ +typedef int (* ReadFromAgent_fn) + (void * pShellData, growBuffer * oBuffer, size_t iMaxLength); + +/** + * WriteToAgent_fn + * Write iLength bytes to the user agent (browser). + * pShellData: shell-specific (request-specific) data object + * iBuffer: contains data to write to agent + * iLength: number of bytes to write to agent. + * return: 0 == success (all bytes were written); !0 == failure + * note: if the data stream to the agent has been closed (physically or + * logically), return failure. + */ +typedef int (* WriteToAgent_fn) + (void * pShellData, const growBuffer * iBuffer, size_t iLength); + +/** + * FlushData_fn + * Flush the data stream to the user agent (browser), if possible. + * pShellData: shell-specific (request-specific) data object + * note: if the data stream to the agent has been closed (physically or + * logically), return failure. + */ +typedef int (* FlushData_fn) + (void * pShellData); + +/** + * CloseData_fn + * Close the data stream to the user agent (browser), if possible. + * pShellData: shell-specific (request-specific) data object + * note: if it is not possible or advisable for the CM shell to close the + * data stream, it is permissible to mark it as closed for the + * purpose of responding to future callbacks as if the stream were + * closed. + */ +typedef int (* CloseData_fn) + (void * pShellData); + +/** + * SendHeaderBatch_fn + * Send HTTP response status and header(s) to user agent (browser); + * headers are provided in a preformatted block. + * pShellData: shell-specific (request-specific) data object + * iStatusCode: HTTP status code (e.g. 200) + * iStatusMesg: optional status message for HTTP status line + * iMesgLength: number of relevant bytes in iStatusMesg; test iMesgLength + * rather than iStatusMesg for presence of message + * iHeaders: preformatted block of header name-value pairs, including + * newlines (should need no parsing by shell) + * iHeadersLength: number of relevant bytes in iHeaders + * return: 0 == success; !0 == failure + * note: a CM shell implementation need implement only one of + * SendHeaderBatch or SendHeaderNoBatch; the shell's expectation is + * noted in the DRP Context Block passed to drpService. a shell + * that registers itself as expecting batched headers need not + * implement a SetResponseHeader callback. + */ +typedef int (* SendHeaderBatch_fn) + (void * pShellData, drpInt iStatusCode, const char * iStatusMesg, + size_t iMesgLength, const char * iHeaders, size_t iHeadersLength); + +/** + * SetResponseHeader_fn + * Set a single HTTP response header name-value pair, to be sent to the agent + * when SendHeaderNoBatch is invoked. + * pShellData: shell-specific (request-specific) data object + * iHeaderName: name of response header (ascii, null-terminated) + * iHeaderValue: value of response header (ascii, null-terminated) + * return: 0 == success; !0 == failure + * note: a shell that registers itself as expecting batched headers need not + * implement a SetResponseHeader callback. + */ +typedef int (* SetResponseHeader_fn) + (void * pShellData, const growBuffer * iHeaderName, + const growBuffer * iHeaderValue); + +/** + * SendHeaderNoBatch_fn + * Send HTTP response status and header(s) to user agent (browser); + * headers will have been provided already via SetResponseHeader callback, + * and must be sent with this callback. + * pShellData: shell-specific (request-specific) data object + * iStatusCode: HTTP status code (e.g. 200) + * iStatusMesg: optional status message for HTTP status line + * iMesgLength: number of relevant bytes in iStatusMesg; test iMesgLength + * rather than iStatusMesg for presence of message + * return: 0 == success; !0 == failure + * note: a CM shell implementation need implement only one of + * SendHeaderBatch or SendHeaderNoBatch; the shell's expectation is + * noted in the DRP Context Block passed to drpService. a shell + * that registers itself as expecting batched headers need not + * implement a SetResponseHeader callback. + */ +typedef int (* SendHeaderNoBatch_fn) + (void * pShellData, drpInt iStatusCode, const char * iStatusMesg, + size_t iMesgLength); + +/** + * DefinedLength_fn + * Return the length of the shell-specific ascii representation of the + * indicated DRP defined string. + * pShellData: shell-specific (request-specific) data object + * iDefined: DRP defined string String-ID. + * return: length of shell's representation of iDefined; 0 if the shell has + * no representation for iDefined + */ +typedef int (* DefinedLength_fn) + (void * pShellData, drpByte iDefined); + +/** + * DefinedAscii_fn + * Return the (null-terminated) shell-specific ascii representation of the + * indicated DRP defined string. + * pShellData: shell-specific (request-specific) data object + * iDefined: DRP defined string String-ID. + * return: shell's representation of iDefined; NULL if the shell has no + * representation for iDefined. + */ +typedef const char * (* DefinedAscii_fn) + (void * pShellData, drpByte iDefined); + +/** + * LogMessage_fn + * Log the message associated with iMessageNumber (with up to two optional + * arguments) to the HTTP-server's log (or WIN32 event log for ISAPI). + * pShellData: shell-specific (request-specific) data object + * iMessageType: indicates whether message is "Info", "Warning", or "Error" + * iMessageNumber: index of message to log + * iParam1, iParam2: optional parameters to include in the log message (can be + * NULL) + */ +typedef void (* LogMessage_fn) + (void * pShellData, int iMessageType, int iMessageNumber, + const char * iParam1, const char * iParam2); + +/* log message types */ +enum { + kLog_Info, + kLog_Warn, + kLog_Error +}; + + +/* structure definitions */ + +/* DRPContextBlock: maintains the information each service "context" + (service thread for multithreaded servers or service process for + multiprocess servers) needs to service requests; in the multithreaded + case, an instance of this structure is associated with each service + thread via the Thread-Local-Storage mechanism (see threadabstr.h) */ +struct _drpContextBlock { + /** INPUTS **/ + + /* call back functions (for accessing shell functionality) */ + GetParameter_fn getParameter; + GetNthHeader_fn getNthHeader; + ReadFromAgent_fn readFromAgent; + WriteToAgent_fn writeToAgent; + FlushData_fn flushData; + CloseData_fn closeData; + SendHeaderBatch_fn sendHeaderBatch; + SendHeaderNoBatch_fn sendHeaderNoBatch; + SetResponseHeader_fn setResponseHeader; + DefinedLength_fn definedStringLength; + DefinedAscii_fn definedStringToAscii; + LogMessage_fn logMessage; + + /* 0: CM shell expects response headers to be sent in one big block; + !0: CM shell expects response headers in name-value pairs. + see DRPClient.c:handleHeader*/ + short shellExpectsHeaderPairs; + + /* shellData: http-server-API-specific chunk of data the CM shell passes in; + to be sent back to shell in shell callbacks */ + void * shellData; + + + /** INTERNALS **/ + + int serviceStatus; + + /* socket IO buffers */ + sockBuf recvBuf; + sockBuf sendBuf; + + growBuffer ioBuffer; + growBuffer ioBuffer2; + + drpServerRecord * currentServer; + drpServerRecord drpServers[kMaxDRPRecords]; + drpServerRecord * drpServerPtrs[kMaxDRPRecords]; + int numDrpServers; + unsigned int drpServerInfoVersion; /* local DRP information version; + compared to + CMLDRP.h:gCMLDRP_InfoVersion */ + + short statusSetByServer; /* 0: DRP server has not yet set HTTP status */ + short statusSentToAgent; + drpInt statusCode; /* HTTP response code */ + drpTLiteral statusMesg; /* HTTP response message (or kNull) */ + growBuffer headers; + growBuffer headers2; + growBuffer statusBuffer; + + char sessionID[kMaxSessionIDLength]; /* SID (if any) for current requests */ + + unsigned int totalProb; /* total of "probabilities" (weights) for all + known DRP2 servers */ + + char isLoggedRequest; /* 0 for regular service request, 1 for logged request*/ + + char debugEnabled; /* 1 if debugging is turned on */ + char isTargetedRequest; /* 1 if dyn_server arg was specified */ + + int maxConnectTimeout; /* total time (seconds) to go around a loop + calling connect() and getting a timeout */ + + /* + * The address and port of the DRP server if isTargetedRequest is + * true + */ + unsigned long targetedServerAddr; + unsigned short targetedServerPort; +}; + + + +/* clearGrowBuffer: (_m : reminds me this is a macro :) + reset growbuffer to 0 bytes used; set first byte to null character + (in case buffer about to be used as C string) */ +#define clearGrowBuffer_m(/* (growBuffer *) */b) \ + { (b)->used = 0; \ + (b)->buffer[0] = kChar_Null; } + +/* ensureGrowBufferSize: (_m : reminds me this is a macro :) + if bytes allocated to growbuffer less than bytes requested, buffer is + grown (by realloc()) to requested size */ +#define ensureGrowBufferSize_m(/* (growBuffer *) */ b, /* size_t */ s) \ + { if ((b)->avail < (s)) \ + growGrowBuffer((b), (s) - (b)->avail + 1); } + +/* sets the value of a grow buffer + */ +int setGrowBuffer(growBuffer* b, const char* s); + +/* DRP-type to ASCII string converters */ +void identToAscii(DefinedLength_fn iDefinedLength, + DefinedAscii_fn iDefinedAscii, void * pShellData, + const drpIdentifier * iIdent, growBuffer * oBuffer); +void tliteralToAscii(DefinedLength_fn iDefinedLength, + DefinedAscii_fn iDefinedAscii, void * pShellData, + const drpTLiteral * iTLiteral, growBuffer * oBuffer); + +/* growbuffer manipulation */ +growBuffer * createGrowBuffer(growBuffer * pBuffer, size_t iInitialSize); +int concatenate(growBuffer * pBuffer, const char * iString); +int growGrowBuffer(growBuffer * pBuffer, size_t iGrowSize); +void destroyGrowBuffer(growBuffer * growBuffer); + + +/* DRP2 client service entry points */ +void drpInitialize(void); +void drpReset(drpContextBlock * pCB); +int drpService(drpContextBlock * pCB); + + +/* convert host identifier (IP address or host name) to struct in_addr */ +unsigned long hostToInetAddr(const char * iHost); + + +#endif /* _DRP_CLIENT_H_ */ diff --git a/mk4/moddynamo/DRPServerIO.c b/mk4/moddynamo/DRPServerIO.c new file mode 100644 index 0000000..25ac464 --- /dev/null +++ b/mk4/moddynamo/DRPServerIO.c @@ -0,0 +1,820 @@ +/* + * Copyright (C) 1997 Art Technology Group, Inc. + * All Rights Reserved. No use, copying or distribution of this + * work may be made except in accordance with a valid license + * agreement from Art Technology Group. This notice must be + * included on all copies, modifications and derivatives of this + * work. + * + * Art Technology Group (ATG) MAKES NO REPRESENTATIONS OR WARRANTIES + * ABOUT THE SUITABILITY OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. ATG SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, + * MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. + * + * "Dynamo" is a trademark of Art Technology Group, Inc. + */ + +/* + DRPServerIO.c - routines for sending/receiving DRP objects, etc + */ + + +#include + +#ifndef WIN32 +/* UNIXen */ +#include +#include +#include +#include +#include +#include +#else +#define EINTR WSAEINTR +#endif + + +#include "DRPClient.h" +#include "DRPServerIO.h" + + +#include +#include + +/** + * do_recv + * locally-buffered interface to recv(). if requested amount of data + * is not already in the "receive" socket io buffer in the context block + * (pCB), then the io buffer is filled from socket iSock. + * (NB: assumed that iSock, flags always the same for given context) + * return: number of bytes received; 0 == sock closed; SOCKET_ERROR == failure + */ +static size_t +do_recv(drpContextBlock * pCB, socket_t iSock, char *oBuffer, + size_t iLength, int iFlags) +{ + size_t returnValue = 0; + sockBuf *recvBuf = &pCB->recvBuf; + size_t bytesAvail; + + if (recvBuf->used - recvBuf->curPtr < iLength) { + /* fewer bytes in recvBuf than requested */ + int result; + + if (recvBuf->curPtr > 0) { + /* move as-yet-unretrieved data in recvBuf to beginning of recvBuf */ + memmove(recvBuf->data, recvBuf->data + recvBuf->curPtr, + recvBuf->used - recvBuf->curPtr); + recvBuf->used -= recvBuf->curPtr; + recvBuf->curPtr = 0; + } + /* fill recvBuf with delicious data */ + tryagain: + result = recv(iSock, recvBuf->data + recvBuf->used, + recvBuf->capacity - recvBuf->used, iFlags); + if (result < 0) { + int errorNum = net_error(); + char buf[128]; + + if (errorNum == EINTR) { + if (pCB->debugEnabled) { + sprintf(buf, + "read failed from socket %d with errno %d retrying...", + iSock, errorNum); + + pCB->logMessage(pCB->shellData, kLog_Info, + kLogMessage_OneString, buf, NULL); + } + goto tryagain; + } + + if (pCB->debugEnabled) { + sprintf(buf, "read failed from socket %d with errno %d", + iSock, errorNum); + + pCB->logMessage(pCB->shellData, kLog_Info, + kLogMessage_OneString, buf, NULL); + } + returnValue = result; + goto DO_RECV_EXIT; + } else { + if (result == 0 && pCB->debugEnabled) { + pCB->logMessage(pCB->shellData, kLog_Info, + kLogMessage_OneString, "recv returned 0", + NULL); + } + recvBuf->used += result; + } + } + bytesAvail = recvBuf->used - recvBuf->curPtr; /* avail in recvBuf */ + returnValue = MIN(bytesAvail, iLength); /* bytes to copy into return buf */ + memcpy(oBuffer, recvBuf->data + recvBuf->curPtr, returnValue); + recvBuf->curPtr += returnValue; + + DO_RECV_EXIT: + + return returnValue; +} + + +/** + * do_send + * uses send() to send all data currently in the "send" socket io buffer + * in the context block (pCB) via socket iSock. + * return: number of bytes send; SOCKET_ERROR == failure + */ +static size_t do_send(drpContextBlock * pCB, socket_t iSock, int iFlags) +{ + size_t returnValue = 0; + sockBuf *sendBuf = &pCB->sendBuf; + size_t result = 1; + size_t bytesSentSoFar = 0; + + while ((bytesSentSoFar < sendBuf->used) && (result > 0)) { + result = send(iSock, sendBuf->data + bytesSentSoFar, + sendBuf->used - bytesSentSoFar, iFlags); + + if (result < 0) { + char buf[128]; + int errorNum = net_error(); + + if (errorNum == EINTR) + continue; + + if (pCB->debugEnabled) { + sprintf(buf, "write failed to socket %d with errno %d", + iSock, errorNum); + + pCB->logMessage(pCB->shellData, kLog_Info, + kLogMessage_OneString, buf, NULL); + } + } + bytesSentSoFar += result; + } + if (result == SOCKET_ERROR) { + returnValue = result; + goto DO_SEND_EXIT; + } else { + returnValue += result; + sendBuf->used = 0; + } + + DO_SEND_EXIT: + + return returnValue; +} + + +/** + * send_queue + * locally-buffered interface to send(). if there is not enough space + * in the "send" socket io buffer for the data, the buffer is flushed + * out to socket iSock. otherwise, data is copied into send buffer + * to be sent later. + * (NB: assumed that iSock, flags always the same for given context) + * return: number of bytes (queued to be) sent; SOCKET_ERROR == failure + */ +static size_t +send_queue(drpContextBlock * pCB, socket_t iSock, const char *iBuffer, + size_t iLength, int iFlags) +{ + size_t returnValue = 0; + sockBuf *sendBuf = &pCB->sendBuf; + size_t bytesAvail; + + if (sendBuf->capacity - sendBuf->used < iLength) { + size_t result; + + /* fewer bytes avail in sendBuf than needed to store data */ + result = do_send(pCB, iSock, iFlags); + if (result == SOCKET_ERROR) { + returnValue = result; + goto DO_SEND_EXIT; + } + } + bytesAvail = sendBuf->capacity - sendBuf->used; /* avail in sendBuf */ + returnValue = MIN(bytesAvail, iLength); /* bytes to copy into sendBuf */ + memcpy(sendBuf->data + sendBuf->used, iBuffer, returnValue); + sendBuf->used += returnValue; + + DO_SEND_EXIT: + + return returnValue; +} + + +/** + * send_flush + * forces send of data currently in "send" socket io buffer in the context + * block (pCB) via socket iSock. + * return: 0 == success; SOCKET_ERROR == failure + */ +int send_flush(drpContextBlock * pCB, socket_t iSock, int iFlags) +{ + size_t result; + + result = do_send(pCB, iSock, iFlags); + + return (result == SOCKET_ERROR ? result : 0); +} + + +/** + * recvByte + * Receive a single byte from the DRP server + * oByte: will be filled in with byte value received + * return: 0 == success; !0 == failure + */ +int recvByte(drpContextBlock * pCB, socket_t iSock, drpByte * oByte) +{ + int returnValue = 0; + size_t bytesRead; + + bytesRead = do_recv(pCB, iSock, oByte, sizeof(drpByte), 0); + if (bytesRead != sizeof(drpByte)) { + if (pCB->debugEnabled) { + char buf[128]; +#if defined(SOLARIS2) && !defined(_LP64) && !defined(_I32LPx) || defined(WIN32) || defined(LINUX) + sprintf(buf, "failed to read byte (size=%u) from socket %d", +#else + sprintf(buf, "failed to read byte (size=%lu) from socket %d", +#endif + bytesRead, iSock); + pCB->logMessage(pCB->shellData, kLog_Info, + kLogMessage_OneString, buf, NULL); + } + returnValue = -1; + } + + return returnValue; +} + + +/** + * sendByte + * Send a single byte to the DRP server + * iByte: byte to send + * return: 0 == success; !0 == failure + */ +int sendByte(drpContextBlock * pCB, socket_t iSock, const drpByte * iByte) +{ + int returnValue = 0; + int bytesSent; + + bytesSent = send_queue(pCB, iSock, iByte, sizeof(drpByte), 0); + if (bytesSent != sizeof(drpByte)) + returnValue = -1; + + return returnValue; +} + + +/** + * recvLong + * Receive a 4-byte integer from the DRP server + * oLong: will be filled in with the "long" value received + * return: 0 == success; !0 == failure + */ +int recvLong(drpContextBlock * pCB, socket_t iSock, drpInt * oLong) +{ + int returnValue = 0; + size_t bytesRead; + + bytesRead = do_recv(pCB, iSock, (char *) oLong, sizeof(drpInt), 0); + if (bytesRead != sizeof(drpInt)) { + if (pCB->debugEnabled) { + char buf[128]; +#if defined(SOLARIS2) && !defined(_LP64) && !defined(_I32LPx) || defined(WIN32) || defined(LINUX) + sprintf(buf, "failed to read long (size=%u) from socket %d", +#else + sprintf(buf, "failed to read long (size=%lu) from socket %d", +#endif + bytesRead, iSock); + pCB->logMessage(pCB->shellData, kLog_Info, + kLogMessage_OneString, buf, NULL); + } + returnValue = -1; + } else + *oLong = ntohl(*oLong); + + return returnValue; +} + + +/** + * sendLong + * Send a 4-byte integer to the DRP server + * iLong: the "long" value to send + * return: 0 == success; !0 == failure + */ +int sendLong(drpContextBlock * pCB, socket_t iSock, const drpInt * iLong) +{ + int returnValue = 0; + size_t bytesSent; + drpInt value; + + value = htonl(*iLong); + bytesSent = send_queue(pCB, iSock, (char *) &value, sizeof(drpInt), 0); + if (bytesSent != sizeof(drpInt)) + returnValue = -1; + + return returnValue; +} + + +/** + * recvBuffer + * Receive a byte stream from the DRP server + * oBuffer: buffer object to fill with data received + * iLength: number of bytes to receive + * return: 0 == success; !0 == failure + */ +int +recvBuffer(drpContextBlock * pCB, socket_t iSock, growBuffer * oBuffer, + size_t iLength) +{ + int returnValue = 0; + size_t bytesRead = 1; + + /* NB: not necessary to grow buffer */ + + oBuffer->used = 0; + + while ((oBuffer->used < iLength) && (bytesRead > 0)) { + bytesRead = do_recv(pCB, iSock, oBuffer->buffer + oBuffer->used, + iLength - oBuffer->used, 0); + + if (bytesRead > 0) + oBuffer->used += bytesRead; + } + + if (oBuffer->used < iLength) { + if (pCB->debugEnabled) { + char buf[128]; + sprintf(buf, "failed to read buffer stream " +#if defined(SOLARIS2) && !defined(_LP64) && !defined(_I32LPx) || defined(WIN32) || defined(LINUX) + "(size=%u != %u) read=%u from socket %d", +#else + "(size=%lu != %lu) read=%lu from socket %d", +#endif + oBuffer->used, iLength, bytesRead, iSock); + pCB->logMessage(pCB->shellData, kLog_Info, + kLogMessage_OneString, buf, NULL); + } + returnValue = -1; + } + + return returnValue; +} + + +/** + * sendBuffer + * Send a byte stream to the DRP server + * iBuffer: buffer object containing data to send + * (iBuffer->used is number of bytes to send) + * return: 0 == success; !0 == failure + */ +int +sendBuffer(drpContextBlock * pCB, socket_t iSock, + const growBuffer * iBuffer) +{ + int returnValue = 0; + + returnValue = + sendByteStream(pCB, iSock, iBuffer->buffer, iBuffer->used); + + return returnValue; +} + + +/** + * sendBytes + * Send a byte stream to the DRP server + * iBytes: bytes to send + * iLength: number of bytes to send + * return: 0 == success; !0 == failure + */ +int +sendByteStream(drpContextBlock * pCB, socket_t iSock, const char *iBytes, + size_t iLength) +{ + int returnValue = 0; + size_t bytesSent = 1; + size_t bytesSentSoFar = 0; + + while ((bytesSentSoFar < iLength) && (bytesSent > 0)) { + bytesSent = send_queue(pCB, iSock, iBytes + bytesSentSoFar, + iLength - bytesSentSoFar, 0); + bytesSentSoFar += bytesSent; + } + + if (bytesSentSoFar < iLength) + returnValue = -1; + + return returnValue; +} + + +/** + * recvIdentifier + * Receive a DRP Identifier object from the DRP server. + * oIdent: will be filled in with received Identifier data. + * oBuffer: if received Identifier includes string data, that data will + * be placed in oBuffer (and the appropriate Identifier field will be + * pointed to oBuffer) + * return: 0 == success; !0 == failure + */ +int +recvIdentifier(drpContextBlock * pCB, socket_t iSock, + drpIdentifier * oIdent, growBuffer * oBuffer) +{ + int returnValue = 0; + + /* recv has-index byte */ + returnValue = recvByte(pCB, iSock, &oIdent->hasIndex); + if (returnValue == 0) + /* recv ident name (TLiteral) */ + returnValue = recvTLiteral(pCB, iSock, &oIdent->name, oBuffer); + if (oIdent->hasIndex && (returnValue == 0)) + /* recv ident index (TLiteral) */ + returnValue = recvTLiteral(pCB, iSock, &oIdent->index, oBuffer); + else + memset(&oIdent->index, 0, sizeof(drpTLiteral)); + + return returnValue; +} + + +/** + * recvTLiteral + * Receive a DRP Typed Literal object from the DRP server. + * oTLiteral: will be filled in with received TLiteral data. + * oBuffer: if received TLiteral includes string data, that data will + * be placed in oBuffer (and the appropriate TLiteral field will be + * pointed to oBuffer); will be grown if necessary + * return: 0 == success; !0 == failure + */ +int +recvTLiteral(drpContextBlock * pCB, socket_t iSock, + drpTLiteral * oTLiteral, growBuffer * oBuffer) +{ + int returnValue = 0; + + oTLiteral->numChars = 0; + + /* recv TLiteral type byte */ + returnValue = recvByte(pCB, iSock, &oTLiteral->type); + if (returnValue == 0) { + switch (oTLiteral->type) { + case kNull: + /* do nothing */ + break; + case kInteger: + returnValue = recvLong(pCB, iSock, &oTLiteral->value.integer); + break; + case kAscii: + /* recv ascii data length */ + returnValue = + recvLong(pCB, iSock, (drpInt *) & oTLiteral->numChars); + if (returnValue == 0) { + /* recv ascii data */ + ensureGrowBufferSize_m(oBuffer, + (oBuffer->used + + oTLiteral->numChars)); + returnValue = + recvByteStream(pCB, iSock, + oBuffer->buffer + oBuffer->used, + oTLiteral->numChars); + if (returnValue == 0) { + oBuffer->used += oTLiteral->numChars; + oTLiteral->value.ascii = oBuffer->buffer; + } else + oTLiteral->numChars = 0; + } else + oTLiteral->numChars = 0; + break; + case kUnicode: + /* recv unicode data length */ + returnValue = + recvLong(pCB, iSock, (drpInt *) & oTLiteral->numChars); + if (returnValue == 0) { + /* recv unicode data */ + ensureGrowBufferSize_m(oBuffer, + (oBuffer->used + + oTLiteral->numChars * + sizeof(drpChar))); + returnValue = + recvByteStream(pCB, iSock, + oBuffer->buffer + oBuffer->used, + sizeof(drpChar) * oTLiteral->numChars); + if (returnValue == 0) { + oBuffer->used += oTLiteral->numChars * sizeof(drpChar); + /* DO NOT re-order unicode */ + oTLiteral->value.unicode = (drpChar *) oBuffer->buffer; + } else + oTLiteral->numChars = 0; + } else + oTLiteral->numChars = 0; + break; + case kDefined: + returnValue = recvByte(pCB, iSock, &oTLiteral->value.defined); + break; + default: + returnValue = -1; + break; + } + } + + return returnValue; +} + + +/** + * recvByteStream + * Receive a byte stream from the DRP server + * oBuffer: buffer in which to store received data + * iLength: number of bytes to receive + * return: 0 == success; !0 == failure + */ +int +recvByteStream(drpContextBlock * pCB, socket_t iSock, char *oBuffer, + size_t iLength) +{ + int returnValue = 0; + size_t bytesRead = 1; + size_t bytesReadSoFar = 0; + + while ((bytesReadSoFar < iLength) && (bytesRead > 0)) { + bytesRead = do_recv(pCB, iSock, oBuffer + bytesReadSoFar, + iLength - bytesReadSoFar, 0); + if (bytesRead > 0) + bytesReadSoFar += bytesRead; + } + + if (bytesReadSoFar < iLength) { + if (pCB->debugEnabled) { + char buf[128]; + sprintf(buf, "failed to read byte stream " +#if defined(SOLARIS2) && !defined(_LP64) && !defined(_I32LPx) || defined(WIN32) || defined(LINUX) + "(size=%u != %u) read=%u from socket %d", +#else + "(size=%lu != %lu) read=%lu from socket %d", +#endif + bytesReadSoFar, iLength, bytesRead, iSock); + pCB->logMessage(pCB->shellData, kLog_Info, + kLogMessage_OneString, buf, NULL); + } + returnValue = -1; + } + + return returnValue; +} + + +/** + * sendIdentifier + * Send a DRP Identifier object to the DRP server. + * iIdent: the Identifier to send. + * return: 0 == success; !0 == failure + */ +int +sendIdentifier(drpContextBlock * pCB, socket_t iSock, + const drpIdentifier * iIdent) +{ + int returnValue = 0; + + /* send has-index byte */ + returnValue = sendByte(pCB, iSock, &iIdent->hasIndex); + if (returnValue == 0) + /* send ident name (TLiteral) */ + returnValue = sendTLiteral(pCB, iSock, &iIdent->name); + if (iIdent->hasIndex && (returnValue == 0)) + /* send ident index (TLiteral) */ + returnValue = sendTLiteral(pCB, iSock, &iIdent->index); + + return returnValue; +} + + +/** + * sendTLiteral + * Send a DRP Typed Literal object to the DRP server. + */ +int +sendTLiteral(drpContextBlock * pCB, socket_t iSock, + const drpTLiteral * iTLiteral) +{ + int returnValue = 0; + + /* send TLiteral type byte */ + returnValue = sendByte(pCB, iSock, &iTLiteral->type); + if (returnValue == 0) { + switch (iTLiteral->type) { + case kNull: + /* do nothing */ + break; + case kInteger: + returnValue = sendLong(pCB, iSock, &iTLiteral->value.integer); + break; + case kDefined: + returnValue = sendByte(pCB, iSock, &iTLiteral->value.defined); + break; + case kAscii: + /* send ascii data length */ + returnValue = + sendLong(pCB, iSock, (drpInt *) & iTLiteral->numChars); + if (returnValue == 0) + /* send ascii data */ + returnValue = + sendByteStream(pCB, iSock, iTLiteral->value.ascii, + iTLiteral->numChars); + break; + case kUnicode: + /* send unicode data length */ + returnValue = + sendLong(pCB, iSock, (drpInt *) & iTLiteral->numChars); + if (returnValue == 0) { + /* send unicode data */ + /* DO NOT reorder unicode */ + returnValue = sendByteStream(pCB, iSock, + (char *) iTLiteral->value. + unicode, + iTLiteral->numChars * + sizeof(drpChar)); + } + break; + default: + returnValue = -1; + break; + } + } + + return returnValue; +} + + +/** + * sendAsciiTLiteral + * Send a DRP Typed Literal object with ASCII string data to the DRP server. + * iAsciiBuffer: the ASCII string data to send. + * return: 0 == success; !0 == failure + */ +int +sendAsciiTLiteral(drpContextBlock * pCB, socket_t iSock, + const growBuffer * iAsciiBuffer) +{ + int returnValue = 0; + drpByte _ascii = kAscii; + + /* send ascii typed-literal type byte */ + returnValue = sendByte(pCB, iSock, &_ascii); + if (returnValue == 0) + /* send length of ascii data */ + returnValue = + sendLong(pCB, iSock, (drpInt *) & iAsciiBuffer->used); + if (returnValue == 0) + /* send ascii data */ + returnValue = sendByteStream(pCB, iSock, iAsciiBuffer->buffer, + iAsciiBuffer->used); + + return returnValue; +} + + +/** + * sendIntTLiteral + * Send a DRP Typed Literal object with DRP-Integer data to the DRP server. + * iInt: the 4-byte integer to send. + * return: 0 == success; !0 == failure. + */ +int sendIntTLiteral(drpContextBlock * pCB, socket_t iSock, drpInt iInt) +{ + int returnValue = 0; + drpByte _int = kInteger; + + /* send integer typed-literal type byte */ + returnValue = sendByte(pCB, iSock, &_int); + if (returnValue == 0) + /* send integer value */ + returnValue = sendLong(pCB, iSock, &iInt); + + return returnValue; +} + + + +/** + * sendNameIndexedPair + * Send a Name-Value pair, indexed by (ascii string) iIndex. + * iDefinedName: defined-string index indicating "name" of pair + * iIndex: (null-terminated) ascii string indicating "index" of pair + * iAscii: (null-terminated) ascii string "value" of pair. + * return: 0 == success; !0 == failure + */ +int +sendNameIndexedPair(drpContextBlock * pCB, socket_t iSock, + drpByte iDefinedName, const drpByte * iIndex, + const drpByte * iAscii) +{ + int returnValue = 0; + drpByte _1 = 1; + drpByte _ascii = kAscii; + drpByte _defined = kDefined; + drpInt length = strlen(iIndex); + + /* send Identifier (pair name) */ + /* send byte: identifier has index */ + returnValue = sendByte(pCB, iSock, &_1); + + /* send TLiteral (identifier name): iDefinedName */ + if (returnValue == 0) + /* TLiteral type: defined string type */ + returnValue = sendByte(pCB, iSock, &_defined); + if (returnValue == 0) + /* TLiteral value: defined string ID */ + returnValue = sendByte(pCB, iSock, &iDefinedName); + + /* send TLiteral (identifier index): iIndex */ + if (returnValue == 0) + /* TLiteral type: ascii string type */ + returnValue = sendByte(pCB, iSock, &_ascii); + if (returnValue == 0) + /* ascii string length */ + returnValue = sendLong(pCB, iSock, &length); + if (returnValue == 0) + /* ascii string data */ + returnValue = sendByteStream(pCB, iSock, iIndex, length); + + length = strlen(iAscii); + + /* send TLiteral (pair value): iAscii */ + if (returnValue == 0) + /* TLiteral type: ascii string type */ + returnValue = sendByte(pCB, iSock, &_ascii); + if (returnValue == 0) + /* ascii string length */ + returnValue = sendLong(pCB, iSock, &length); + if (returnValue == 0) + /* ascii string data */ + returnValue = sendByteStream(pCB, iSock, iAscii, length); + + return returnValue; +} + + +/** + * sendIntIndexedPair + * Send a Name-Value pair, indexed by (integer) iIndex. + * iDefinedName: defined-string index indicating "name" of pair. + * iIndex: integer "index" of pair. + * iAscii: (null-terminated) ascii string "value" of pair. + * return: 0 == success; !0 == failure + */ +int +sendIntIndexedPair(drpContextBlock * pCB, socket_t iSock, + drpByte iDefinedName, int iIndex, + const drpByte * iAscii) +{ + int returnValue = 0; + drpByte _1 = 1; + drpByte _defined = kDefined; + drpByte _integer = kInteger; + drpByte _ascii = kAscii; + drpInt length = strlen(iAscii); + + /* send Identifier (pair name) */ + /* send byte: identifier has index */ + returnValue = sendByte(pCB, iSock, &_1); + + /* send TLiteral (identifier name): iDefinedName */ + if (returnValue == 0) + /* TLiteral type: defined string type */ + returnValue = sendByte(pCB, iSock, &_defined); + if (returnValue == 0) + /* TLiteral value: defined string ID */ + returnValue = sendByte(pCB, iSock, &iDefinedName); + + /* send TLiteral (identifier index): iIndex */ + if (returnValue == 0) + /* TLiteral type: integer type */ + returnValue = sendByte(pCB, iSock, &_integer); + if (returnValue == 0) + /* TLiteral value: iIndex */ + returnValue = sendLong(pCB, iSock, (drpInt *) & iIndex); + + /* send TLiteral (pair value): iAscii */ + if (returnValue == 0) + /* TLiteral type: ascii string type */ + returnValue = sendByte(pCB, iSock, &_ascii); + if (returnValue == 0) + /* ascii string length */ + returnValue = sendLong(pCB, iSock, &length); + if (returnValue == 0) + /* ascii string data */ + returnValue = sendByteStream(pCB, iSock, iAscii, length); + + return returnValue; +} diff --git a/mk4/moddynamo/DRPServerIO.h b/mk4/moddynamo/DRPServerIO.h new file mode 100644 index 0000000..4bcf7d9 --- /dev/null +++ b/mk4/moddynamo/DRPServerIO.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 1997 Art Technology Group, Inc. + * All Rights Reserved. No use, copying or distribution of this + * work may be made except in accordance with a valid license + * agreement from Art Technology Group. This notice must be + * included on all copies, modifications and derivatives of this + * work. + * + * Art Technology Group (ATG) MAKES NO REPRESENTATIONS OR WARRANTIES + * ABOUT THE SUITABILITY OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. ATG SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, + * MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. + * + * "Dynamo" is a trademark of Art Technology Group, Inc. + */ + +/* + DRPServerIO.h - API for sending/receiving DRP objects, etc + */ + +#ifndef _DRP_SERVER_IO_ +#define _DRP_SERVER_IO_ + +#include "DRPTypes.h" +#include "DRPClient.h" + + +int recvByte(drpContextBlock * pCB, socket_t iSock, drpByte * oByte); +int sendByte(drpContextBlock * pCB, socket_t iSock, const drpByte * iByte); +int recvLong(drpContextBlock * pCB, socket_t iSock, drpInt * oLong); +int sendLong(drpContextBlock * pCB, socket_t iSock, const drpInt * iLong); +int recvBuffer(drpContextBlock * pCB, socket_t iSock, growBuffer * oBuffer, + size_t iLength); +int sendBuffer(drpContextBlock * pCB, socket_t iSock, + const growBuffer * iBuffer); +int recvByteStream(drpContextBlock * pCB, socket_t iSock, char * oBuffer, + size_t iLength); +int sendByteStream(drpContextBlock * pCB, socket_t iSock, + const char * iBytes, size_t iLength); +int recvIdentifier(drpContextBlock * pCB, socket_t iSock, + drpIdentifier * oIdent, growBuffer * oBuffer); +int recvTLiteral(drpContextBlock * pCB, socket_t iSock, + drpTLiteral * oTLiteral, growBuffer * oBuffer); +int sendIdentifier(drpContextBlock * pCB, socket_t iSock, + const drpIdentifier * iIdent); +int sendTLiteral(drpContextBlock * pCB, socket_t iSock, + const drpTLiteral * iTLiteral); +int sendAsciiTLiteral(drpContextBlock * pCB, socket_t iSock, + const growBuffer * iAsciiBuffer); +int sendIntTLiteral(drpContextBlock * pCB, socket_t iSock, + drpInt iInt); +int sendNameIndexedPair(drpContextBlock * pCB, socket_t iSock, + drpByte iDefinedName, const drpByte * iIndex, + const drpByte * iValue); +int sendIntIndexedPair(drpContextBlock * pCB, socket_t iSock, + drpByte iDefinedName, int iIndex, + const drpByte * iAscii); +int send_flush(drpContextBlock * pCB, socket_t iSock, int iFlags); + + + +#endif diff --git a/mk4/moddynamo/DRPTypes.h b/mk4/moddynamo/DRPTypes.h new file mode 100644 index 0000000..2f6e1fb --- /dev/null +++ b/mk4/moddynamo/DRPTypes.h @@ -0,0 +1,241 @@ +/* + * Copyright (C) 1997 Art Technology Group, Inc. + * All Rights Reserved. No use, copying or distribution of this + * work may be made except in accordance with a valid license + * agreement from Art Technology Group. This notice must be + * included on all copies, modifications and derivatives of this + * work. + * + * Art Technology Group (ATG) MAKES NO REPRESENTATIONS OR WARRANTIES + * ABOUT THE SUITABILITY OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. ATG SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, + * MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. + * + * "Dynamo" is a trademark of Art Technology Group, Inc. + */ + + +/* + DRPTypes.h - typedefs and constant #defines + */ + + +#ifndef _DRP_TYPES_H_ +#define _DRP_TYPES_H_ + + +#ifdef WIN32 +/* NT */ +#include +#include +#else +/* UNIXen */ +#include +#include +#endif + + +/* DRP Packet identifiers: identify the type of DRP packet + being sent by the CM or DRP server */ +enum { + kUnknownType = 0, /* placeholder - not used */ + kBeginRequest, /* 1 */ /* CM sends to start response cycle */ + kReply, /* 2 */ /* server sends to supply response headers, + response data, etc */ + kGetParameters, /* 3 */ /* server sends to get add'l req params */ + kReadDataStream, /* 4 */ /* server sends to read agent data (post) */ + kBeginLogRequest, /* 5 */ /* server sends a log request */ + + kPacketTypePlaceholder /* placeholder - not used */ +}; + + +/* Typed-Literal data types: identify the type of object contained in a + DRP2 TypedLiteral */ +enum { + kNull = 0, /* null object (not placeholder) */ + kInteger, /* 1 */ /* 4-byte integer */ + kAscii, /* 2 */ + kUnicode, /* 3 */ + kDefined, /* 4 */ /* pre-defined string placeholder (integral) */ + + kTLiteralTypePlaceholder /* placeholder - not used */ +}; + + +/* defined string identifiers: pre-defined string placeholders */ +enum { + kContentLength = 1, + kContentType, /* 2 */ + kParameter, /* 3 */ + kParameters, /* 4 */ + kProtocol, /* 5 */ + kRemoteAddr, /* 6 */ + kRemoteHost, /* 7 */ + kServerName, /* 8 */ + kServerPort, /* 9 */ + kAuthType, /* 10 */ + kHeaderName, /* 11 */ + kHeaderVal, /* 12 */ + kHeaders, /* 13 */ + kMethod, /* 14 */ + kPathInfo, /* 15 */ + kPathTranslated, /* 16 */ + kQueryString, /* 17 */ + kRemoteUser, /* 18 */ + kRequestURI, /* 19 */ + kServletPath, /* 20 */ + kScheme, /* 21 */ + kUserAgent, /* 22 */ + + kDefinedPlaceholder +}; + + +/* socket_t: abstracted socket type for WIN32 & UNIXen */ +#ifdef WIN32 +typedef SOCKET socket_t; +#define kInvalidSocket INVALID_SOCKET +#else +typedef int socket_t; +#define kInvalidSocket -1 +#ifndef INADDR_NONE +#define INADDR_NONE -1 +#endif +#endif + +#define ATG_INVALID_DYNSOCKET NULL + +#ifdef WIN32 +# define ATG_INVALID_SOCKET INVALID_SOCKET +# define ATG_SOCKET_ERROR SOCKET_ERROR +# define ATG_INADDR_NONE INADDR_NONE +# define net_error() WSAGetLastError() +#else +# define ATG_INVALID_SOCKET -1 +# define ATG_SOCKET_ERROR -1 +# define ATG_INADDR_NONE -1 +# define net_error() errno +#endif + + + +/* DRP2 protocol's atomic types */ +typedef char drpByte; +typedef long drpInt; +typedef short drpChar; + +/* DRP2 protocol's complex types */ +typedef struct _drpTLiteral drpTLiteral; +typedef struct _drpIdentifier drpIdentifier; +typedef struct _growBuffer growBuffer; + + +/* TypedLiteral object type: represents a single value (e.g. a header name) */ +struct _drpTLiteral { + drpByte type; + size_t numChars; /* number of *characters*, not necessarily *bytes*; + relevant to kAscii and kUnicode TLiteral types */ + union { + drpInt integer; + drpByte defined; + drpByte * ascii; + drpChar * unicode; + } value; +}; + + +/* Identifier object type: associates a TypedLiteral object with an optional + (TypedLiteral) index value */ +struct _drpIdentifier { + drpByte hasIndex; + drpTLiteral name; + drpTLiteral index; +}; + + +/* GrowBuffer: growable (e.g. via realloc()) buffer object */ +struct _growBuffer { + int allocated; /* true if growBuffer structure was allocated by + * createGrowBuffer(). */ + char * buffer; + size_t avail; /* # bytes total allocated for buffer field */ + size_t used; /* # bytes of actual data in buffer */ +}; + + +/* character constants */ +#define kChar_Null '\0' +#define kChar_Ampersand '&' +#define kChar_Equals '=' +#define kChar_Colon ':' +#define kChar_Semicolon ';' +#define kChar_Comma ',' +#define kChar_Slash '/' +#define kChar_QMark '?' +#define kChar_Hash '#' +#define kChar_Backslash '\\' +#define kChar_Newline '\n' +#define kChar_Dot '.' +#define kChar_Space ' ' + +/* string constants */ +#define kString_HeaderNVDelim ": " +#define kString_Newline "\n" +#define kString_QMark "?" +#define kString_Space " " +#define kString_Star "*" +#define kString_Slash "/" +#define kString_Backslash "\\" +#define kString_Colon ":" +#define kString_HTTP_ "HTTP_" +#define kString_http "http" +#define kString_https "https" + +#define kEmptyString "" + + +#ifndef MIN +#define MIN(a,b) ((a)<(b)?(a):(b)) +#endif +#ifndef MAX +#define MAX(a,b) ((a)>(b)?(a):(b)) +#endif + + +/* Server-API-independent log messages */ +enum { + kLogMessage_DRPServerUnavailable = 1, + kLogMessage_NoDRPServerAvailable, + kLogMessage_CannotCreateSocket, + kLogMessage_CannotConnect, + kLogMessage_InternalProtoError, + kLogMessage_BadSIDCharacter, + kLogMessage_CannotCreateRWLock, + kLogMessage_CannotStartCMLDRPThread, + kLogMessage_BadCMLDRPResponseType, + kLogMessage_NoCMLDRPResponsePeriod, + kLogMessage_NoCMLDRPResponseFirst, + kLogMessage_OneString, + kLogMessage_CantResolveCMLDRPHost, + kLogMessage_NoGoodCMLDRPServers, + + kLogMessage_Placeholder /* placeholder used as starting point for + API-dependent log messages */ +}; + + +#ifdef WIN32 +#define net_error() WSAGetLastError() +#else +#define net_error() errno +#endif + +#ifndef SOCKET_ERROR +#define SOCKET_ERROR -1 +#endif + + +#endif diff --git a/mk4/moddynamo/DynSock.c b/mk4/moddynamo/DynSock.c new file mode 100644 index 0000000..a309f56 --- /dev/null +++ b/mk4/moddynamo/DynSock.c @@ -0,0 +1,302 @@ +/* + * Copyright (C) 2000 Art Technology Group, Inc. + * All Rights Reserved. No use, copying or distribution of this + * work may be made except in accordance with a valid license + * agreement from Art Technology Group. This notice must be + * included on all copies, modifications and derivatives of this + * work. + * + * Art Technology Group (ATG) MAKES NO REPRESENTATIONS OR WARRANTIES + * ABOUT THE SUITABILITY OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. ATG SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, + * MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. + * + * "Dynamo" is a trademark of Art Technology Group, Inc. + */ + +#include "DynSock.h" +#include "DRPTypes.h" +#include +#include +#include + +#ifdef WIN32 +#include +#include +#else +#include +#include +#include +#include +#include +#endif + +#define DYNSOCKET_VERSION "dynSocket1.0" + +/************************** + * Communication Routines * + **************************/ + +/** + * dynSock_int(pInitData) + * + * Initialize any dynSocket global structures + * Returns 0 on sucess + */ +int dynSocket_init(void *pInitData) +{ + return 0; +} + +/** + * dynSocket *dynSocket_new(pInfo) + * + * Creates a new dynSocket using information contained in pInfo. + * Returns a pointer to the new dynSocket if successful, + * ATG_INVALID_DYNSOCKET otherwise. + * + * NOTE: NEVER call any of the other dynSocket_xxx calls with a + * pointer to an invalid dynSocket, i.e. the pointer has a value of + * ATG_INVALID_DYNSOCKET. + */ +#ifdef _ISAPI +dynSocket *dynSocket_new(HANDLE gHeap, dynSocketInfo * pInfo) +{ +#else +dynSocket *dynSocket_new(dynSocketInfo * pInfo) +{ +#endif + dynSocket *dynSock = NULL; + socket_t s = ATG_INVALID_SOCKET; + + /* Create a DynSocket */ +#ifdef _ISAPI + dynSock = (dynSocket *) HeapAlloc(gHeap, 0, sizeof(dynSocket)); +#else + dynSock = (dynSocket *) malloc(sizeof(dynSocket)); +#endif + if (dynSock == NULL) + return ATG_INVALID_DYNSOCKET; + + /* Zero out memory */ + memset(dynSock, 0, sizeof(dynSocket)); + + /*Set Version */ + strcpy(dynSock->version, DYNSOCKET_VERSION); + + /*Set Socket Info */ + dynSock->info = pInfo; + + /* Create the socket */ + s = socket(AF_INET, SOCK_STREAM, 0); + if (s == ATG_INVALID_SOCKET) { +#ifdef _ISAPI + (void) HeapFree(gHeap, 0, dynSock); +#else + free(dynSock); +#endif + return ATG_INVALID_DYNSOCKET; + } + dynSock->socket_data = (void *) s; + dynSock->connected = 0; + + /* Manipulate operating characteristics of + * socket with ioctl here + */ + + return dynSock; +} + +/** + * int dynSocket_connect(pDynSocket,pRemoteAddr,pLen) + * + * Connects pDynSocket to pRemoteAddr. Use dySocket_close(pDynSocket) + * to close this dynSocket. + * On success zero is returned. Otherwise ATG_SOCKET_ERROR is returned. + */ + +int dynSocket_connect(dynSocket * pDynSocket, + struct sockaddr *pRemoteAddr, int pLen) +{ + int ret = 0; + + /* Get the socket */ + socket_t s = (socket_t) pDynSocket->socket_data; + + /* Connect to the remote host */ + ret = connect(s, pRemoteAddr, pLen); + if (ret == ATG_SOCKET_ERROR) { + return ret; + } + memcpy(&(pDynSocket->remote_addr), pRemoteAddr, + sizeof(struct sockaddr)); + pDynSocket->remote_addr_len = pLen; + pDynSocket->connected = 1; + + return ret; +} + +/** + * int dynSocket_close(pDynSocket) + * + * Close a pDynSocket and does clean up. + * On success returns zero, or ATG_SOCKET_ERROR if an error occurred. + */ +#ifdef _ISAPI +int dynSocket_close(HANDLE gHeap, dynSocket * pDynSocket) +{ +#else +int dynSocket_close(dynSocket * pDynSocket) +{ +#endif + socket_t s = (socket_t) (pDynSocket->socket_data); + + pDynSocket->connected = 0; +#ifdef _ISAPI + (void) HeapFree(gHeap, 0, pDynSocket); +#else + free(pDynSocket); +#endif + +#ifdef WIN32 + return closesocket(s); +#else + return close(s); +#endif +} + +#ifndef WIN32 +/** + * int dynSocket_read(pDynSocket,pBuf,pCount) + * + * Only for UNIX. + * Read data from dynSocket. Attempt to read up to count bytes from + * pDynSocket into pBuf. + * On Success, the number of bytes read is returned. Zero indicates + * the end of file. On error -1 is returned. + */ +int dynSocket_read(dynSocket * pDynSocket, void *pBuf, size_t pCount) +{ + return read((socket_t) (pDynSocket->socket_data), pBuf, pCount); +} + +/** + * int dynSocket_write(pDynSocket,pBuf,pCount) + * + * Only for UNIX. + * Write data to dynSocket. Attempt to write up to pCount bytes to + * the pDynSocket from pBuf. + * On success, the number of byte written are returned. Zero indicates + * nothing was written. On error -1 is returned. + */ +int dynSocket_write(dynSocket * pDynSocket, const void *pBuf, + size_t pCount) +{ + return write((socket_t) (pDynSocket->socket_data), pBuf, pCount); +} +#endif + +/** + * dynSocket_recv(pDynSocket,pBuf,pLen,pFlags) + * + * Receive data from a dynSocket. Attepm to read up to pLen bytes from + * pDynSocket into pBuf + * On Success, the number of bytes reveived is returned. Zero indicates + * the end of file. On error ATG_SOCKET_ERROR is returned. + */ +int dynSocket_recv(dynSocket * pDynSocket, void *pBuf, int pLen, + int pFlags) +{ + return recv((socket_t) (pDynSocket->socket_data), pBuf, pLen, pFlags); +} + +/** + * dynSocket_send(pDynSocket,pMsg,pLen,pFlags) + * + * Send data on dynSocket. Attempt to send up to pCount bytes to + * the pDynSocket from pBuf. + * On success, the number of byte sent are returned. Zero indicates + * nothing was sent. On error ATG_SOCKET_ERROR is returned. + */ +int dynSocket_send(dynSocket * pDynSocket, const void *pMsg, int pLen, + int pFlags) +{ + return send((socket_t) (pDynSocket->socket_data), pMsg, pLen, pFlags); +} + +/********************** + * DynSock Properties * + **********************/ + +/** + * char *dynSocket_version(pDynSocket) + * + * Return version of pDynSocket + */ +char *dynSocket_version(dynSocket * pDynSocket) +{ + return pDynSocket->version; +} + +/** + * dynSocketInfo *dynSocket_info(pDynSocket) + * + * Return the info struct for pDynSocket + */ +dynSocketInfo *dynSocket_info(dynSocket * pDynSocket) +{ + return pDynSocket->info; +} + +/** + * void *dynSocket_socket_data(pDynSocket) + * + * Return the socket data for pDynSocket + */ +void *dynSocket_socket_data(dynSocket * pDynSocket) +{ + return pDynSocket->socket_data; +} + +/** + * int dynSocket_connected(pDynSocket) { + * + * Return the connected field for pDynSocket + */ +int dynSocket_connected(dynSocket * pDynSocket) +{ + return pDynSocket->connected; +} + + +/** + * struct sockaddr *dynSocket_remote_addr(pDynSocket) + * + * Return the remote address for pDynSocket + */ +struct sockaddr *dynSocket_remote_addr(dynSocket * pDynSocket) +{ + return &(pDynSocket->remote_addr); +} + +/** + * int dynSocket_remote_addr_len(*pDynSocket) + * + * Return remote address length for pDynSocket + */ +int dynSocket_remote_addr_len(dynSocket * pDynSocket) +{ + return pDynSocket->remote_addr_len; +} + +/** + * socket_t dynSocket_socket(pDynSocket) + * + * Return the raw socket for pDynSocket + */ +socket_t dynSocket_socket(dynSocket * pDynSocket) +{ + return (socket_t) (pDynSocket->socket_data); +} diff --git a/mk4/moddynamo/DynSock.h b/mk4/moddynamo/DynSock.h new file mode 100644 index 0000000..cfc504d --- /dev/null +++ b/mk4/moddynamo/DynSock.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2000 Art Technology Group, Inc. + * All Rights Reserved. No use, copying or distribution of this + * work may be made except in accordance with a valid license + * agreement from Art Technology Group. This notice must be + * included on all copies, modifications and derivatives of this + * work. + * + * Art Technology Group (ATG) MAKES NO REPRESENTATIONS OR WARRANTIES + * ABOUT THE SUITABILITY OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. ATG SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, + * MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. + * + * "Dynamo" is a trademark of Art Technology Group, Inc. + */ + +/* + DynSock.h - public API for Socket adaption +*/ + +#ifndef _DYN_SOCK_H_ +#define _DYN_SOCK_H_ + +#ifdef WIN32 +/* NT */ +#include +#include +#else +/* UN?X */ +#include +#include + +#include +#endif + +/* socket_t: abstracted socket type for WIN32 & UNIXen */ +#ifdef WIN32 +typedef SOCKET socket_t; +#else +typedef int socket_t; +#endif + +/* struct used in creation of socket */ +typedef struct _dynSocketInfo { + void *info; /* Info used in creation of socket */ +} dynSocketInfo; + +/* struct used to represent a socket */ +typedef struct _dynSocket { + char version[24]; /* version identification */ + dynSocketInfo *info; /* pointer to socket info */ + void *socket_data; /* pointer to raw socket data */ + int connected; /* is this socket connected */ + struct sockaddr remote_addr; /* remote host address */ + int remote_addr_len; /* remote host address len */ +}dynSocket; + +/* Initialization Routines */ +int dynSocket_init(void *pInitData); + +/* Socket Communication Routines */ +#ifdef _ISAPI +dynSocket *dynSocket_new(HANDLE gHeap, dynSocketInfo *pInfo); +int dynSocket_close(HANDLE gHeap, dynSocket *pDynSocket); +#else +dynSocket *dynSocket_new(dynSocketInfo *pInfo); +int dynSocket_close(dynSocket *pDynSocket); +#endif +int dynSocket_connect(dynSocket *pDynSocket,struct sockaddr *pRemoteAddr,int pLen); +int dynSocket_read(dynSocket *pDynSocket,void *pBuf,size_t pCount); +int dynSocket_write(dynSocket *pDynSocket,const void *pBuf,size_t pCount); +int dynSocket_recv(dynSocket *pDynSocket, void *pBuf,int pLen,int pFlags); +int dynSocket_send(dynSocket *pDynSocket,const void *pMsg,int len,int pFlags); + +/* DynSock Properties */ +char *dynSocket_version(dynSocket *pDynSocket); +dynSocketInfo *dynSocket_info(dynSocket *pDynSocket); +void *dynSocket_socket_data(dynSocket *pDynSocket); +int dynSocket_connected(dynSocket *pDynSocket); +struct sockaddr *dynSocket_remote_addr(dynSocket *pDynSocket); +int dynSocket_remote_addr_len(dynSocket *pDynSocket); +socket_t dynSocket_socket(dynSocket *pDynSocket); + + +#endif /* _DYN_SOCK_H_ */ diff --git a/mk4/moddynamo/Makefile b/mk4/moddynamo/Makefile new file mode 100644 index 0000000..973fe3a --- /dev/null +++ b/mk4/moddynamo/Makefile @@ -0,0 +1,22 @@ +# $Header: /san01/cvs/ashpool/csrc/moddynamo/Attic/Makefile,v 1.4 2004/06/22 14:36:14 aleigh Exp $ + +SRCS=CMLDRP.c DRPClient.c DRPServerIO.c DynSock.c pageroute.c io.c hook.c threadabstr.c sockerrs.c +OBJS=CMLDRP.o DRPClient.o DRPServerIO.o DynSock.o pageroute.o io.o hook.o threadabstr.o sockerrs.o + +include ../continuity/lib/env.mk + +CFLAGS=-D_DRP_MTHREAD -I../continuity/include $(CONT_FLAGS) + +world: install + +dynamo.so: $(OBJS) + $(LD_SHARECMD) -o dynamo.so $(OBJS) + +install: dynamo.so + cp dynamo.so ../continuity/lib + +clean: + rm -rf $(OBJS) *~ dynamo.so + +depend: + $(MAKEDEPEND) $(DEPFLAGS) -I ../continuity/include $(SRCS) diff --git a/mk4/moddynamo/cmVersion.h b/mk4/moddynamo/cmVersion.h new file mode 100644 index 0000000..38bcd41 --- /dev/null +++ b/mk4/moddynamo/cmVersion.h @@ -0,0 +1,228 @@ +/* + * Copyright (C) 1997 Art Technology Group, Inc. + * All Rights Reserved. No use, copying or distribution of this + * work may be made except in accordance with a valid license + * agreement from Art Technology Group. This notice must be + * included on all copies, modifications and derivatives of this + * work. + * + * Art Technology Group (ATG) MAKES NO REPRESENTATIONS OR WARRANTIES + * ABOUT THE SUITABILITY OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. ATG SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, + * MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. + * + * "Dynamo" is a trademark of Art Technology Group, Inc. + */ + +/* + cmVersion.h - header file to determine CM version information at + compile time + */ + + + +#ifndef _CM_VERSION_H_ +#define _CM_VERSION_H_ + + +#define kCM_VersionNumber "0.500" + +#define kString_Version "version " + +#define kCM_Name "Dynamo 3 Connection Module for continuity aleigh@tessier.com\n" + +#ifdef NOTDEF + + +#ifdef WIN32 + +#ifdef _NSAPI1 + +#define kCM_Name \ + "Dynamo 3 Connection Module for Netscape Commerce and Communications 1.x\n" \ + "servers (Windows NT)" + +#elif defined(_NSAPI2) + +#define kCM_Name \ + "Dynamo 3 Connection Module for Netscape Enterprise and FastTrack 2.x\n" \ + "servers (Windows NT)" + +#elif defined(_NSAPI3) + +#define kCM_Name \ + "Dynamo 3 Connection Module for Netscape Enterprise and FastTrack 3.x\n" \ + "servers (Windows NT)" + +#elif defined(_NSAPI4) + +#define kCM_Name \ + "Dynamo 3 Connection Module for Netscape Enterprise 4.x\n" \ + "servers (Windows NT)" + +#elif defined(_ISAPI) + +#define kCM_Name \ + "Dynamo 3 Connection Module for Microsoft Internet Information Server\n" \ + "(Windows NT)" + +#else +#error "Unknown CM API" + +#endif /* def? _NSAPI1 */ + +#elif defined(SOLARIS2) + +#ifdef _NSAPI1 + +#define kCM_Name \ + "Dynamo 3 Connection Module for Netscape Commerce and Communications 1.x\n" \ + "servers (Solaris)" + +#elif defined(_NSAPI2) + +#define kCM_Name \ + "Dynamo 3 Connection Module for Netscape Enterprise and FastTrack 2.x\n" \ + "servers (Solaris)" + +#elif defined(_NSAPI3) + +#define kCM_Name \ + "Dynamo 3 Connection Module for Netscape Enterprise and FastTrack 3.x\n" \ + "servers (Solaris)" + +#elif defined(_NSAPI4) + +#define kCM_Name \ + "Dynamo 3 Connection Module for Netscape Enterprise 4.x\n" \ + "servers (Solaris)" + +#elif defined(_APACHE) + +#define kCM_Name \ + "Dynamo 3 Connection Module for Apache server (Solaris)\n" + +#else +#error "Unknown CM API" + +#endif /* def? _NSAPI1 */ + +#elif defined(_IRIX) + +#ifdef _NSAPI1 + +#define kCM_Name \ + "Dynamo 3 Connection Module for Netscape Commerce and Communications 1.x\n" \ + "servers (IRIX)" + +#elif defined(_NSAPI2) + +#define kCM_Name \ + "Dynamo 3 Connection Module for Netscape Enterprise and FastTrack 2.x\n" \ + "servers (IRIX)" + +#elif defined(_NSAPI3) + +#define kCM_Name \ + "Dynamo 3 Connection Module for Netscape Enterprise and FastTrack 3.x\n" \ + "servers (IRIX)" + +#elif defined(_NSAPI4) + +#define kCM_Name \ + "Dynamo 3 Connection Module for Netscape Enterprise 4.x\n" \ + "servers (IRIX)" + +#elif defined(_APACHE) + +#define kCM_Name \ + "Dynamo 3 Connection Module for Apache server (IRIX)\n" + +#else +#error "Unknown CM API" + +#endif /* def? _NSAPI1 */ + +#elif defined(_AIX) + +#ifdef _NSAPI1 + +#define kCM_Name \ + "Dynamo 3 Connection Module for Netscape Commerce and Communications 1.x\n" \ + "servers (AIX)" + +#elif defined(_NSAPI2) + +#define kCM_Name \ + "Dynamo 3 Connection Module for Netscape Enterprise and FastTrack 2.x\n" \ + "servers (AIX)" + +#elif defined(_NSAPI3) + +#define kCM_Name \ + "Dynamo 3 Connection Module for Netscape Enterprise and FastTrack 3.x\n" \ + "servers (AIX)" + +#elif defined(_NSAPI4) + +#define kCM_Name \ + "Dynamo 3 Connection Module for Netscape Enterprise 4.x\n" \ + "servers (AIX)" + +#elif defined(_APACHE) + +#define kCM_Name \ + "Dynamo 3 Connection Module for Apache server (AIX)\n" + +#else +#error "Unknown CM API" + +#endif /* def? _NSAPI1 */ + +#elif defined(_HPUX) + +#ifdef _NSAPI1 + +#define kCM_Name \ + "Dynamo 3 Connection Module for Netscape Commerce and Communications 1.x\n" \ + "servers (HPUX)" + +#elif defined(_NSAPI2) + +#define kCM_Name \ + "Dynamo 3 Connection Module for Netscape Enterprise and FastTrack 2.x\n" \ + "servers (HPUX)" + +#elif defined(_NSAPI3) + +#define kCM_Name \ + "Dynamo 3 Connection Module for Netscape Enterprise and FastTrack 3.x\n" \ + "servers (HPUX)" + +#elif defined(_NSAPI4) + +#define kCM_Name \ + "Dynamo 3 Connection Module for Netscape Enterprise 4.x\n" \ + "servers (HPUX)" + +#elif defined(_APACHE) + +#define kCM_Name \ + "Dynamo 3 Connection Module for Apache server (HPUX)\n" + +#else +#error "Unknown CM API" + +#endif /* def? _NSAPI1 */ + +#else +#error "Unknown Platform" + +#endif /* def? _WIN32 */ + +#endif /* ndef? _CM_VERSION_H_ */ + +#endif + diff --git a/mk4/moddynamo/hook.c b/mk4/moddynamo/hook.c new file mode 100644 index 0000000..ad74481 --- /dev/null +++ b/mk4/moddynamo/hook.c @@ -0,0 +1,570 @@ +#pragma ident "$Header: /san01/cvs/ashpool/csrc/moddynamo/Attic/hook.c,v 1.12 2004/03/18 15:04:15 aleigh Exp $" + +/* + * Copyright (c) 2003 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Disclosure, copying, distribution, or transmission of of this code without + * express permission is prohibited. + */ + +#include "DRPClient.h" +#include "CMLDRP.h" +#include "cmVersion.h" + +#include +#include +#include "../continuity/mecha/lst.h" + +#undef DEBUG + +/** SHELL CALLBACK FUNCTION TYPE DEFINITIONS **/ +/* + * these prototypes indicate the callback interface used by the DRP2 client + * to access functionality in the CM "shell" specific to each server API + */ + +/* + * pBlock->logFunction(pBlock->logShellData, kLog_Error, + * kLogMessage_CantResolveCMLDRPHost, iServers[s].host, NULL); } + */ + +static const char *sLogMessages[] = { + NULL, + + /* server-api-independent messages */ + "mod/dynamo: Failure while attempting to use DRP server at %s:%s to service a request.", + "mod/dynamo: Could not find a functioning DRP server to service a request.", + "mod/dynamo: Cannot create socket for connection to DRP server; error number is: %s.", + "mod/dynamo: Cannot connect to DRP server; error number is: %s.", + "mod/dynamo: Internal protocol error: unexpected DRP packet type: %s.", + "mod/dynamo: Bad character found in Dynamo3 session identifier: %s.", + "mod/dynamo: CMLDRP subsystem cannot start: cannot create read-write lock.", + "mod/dynamo: CMLDRP subsystem cannot start: cannot start updater thread.", + "mod/dynamo: Bad CMLDRP packet response type received from CMLDRP server at %s:%s.", + "mod/dynamo: No response received from CMLDRP server at %s:%s for 150 seconds.", + "mod/dynamo: No response received from CMLDRP server at %s:%s.", + "mod/dynamo: %s", + "mod/dynamo: Cannot resolve the CMLDRP server host: %s.", + "mod/dynamo: Cannot continue; no acceptable CMLDRP servers specified.", + NULL +}; + +void logHook(void *shell, int log_level, int log_message, char *arg1, + char *arg2) +{ + int status; + + switch (log_level) { + case kLog_Info: + status = 0; + break; + case kLog_Warn: + status = 1; + break; + case kLog_Error: + status = 2; + break; + default: + status = 3; + } + + logFmsg(status, sLogMessages[log_message], arg1, arg2); +} + +/** + * GetParameter_fn + * Retrieve the value (in ascii) for a request parameter (e.g. URI, + * server port, etc). + * pShellData: shell-specific (request-specific) data object + * iName: incdicates parameter to retrieve + * oVal: (growable) buffer in which to store parameter value (in ascii) + * (if no value found, return successfully with empty oVal buffer) + * return: 0 == success; !0 == failure (other than val not found) + */ + +int GetParameter(void *pShellData, const drpIdentifier * iName, + growBuffer * oVal) +{ + httpTtrans *t = (httpTtrans *) pShellData; + char *value = NULL; + int returnValue = 0; + + oVal->used = 0; + oVal->buffer[0] = kChar_Null; + + if (iName->name.type == kDefined) { + drpByte defined = iName->name.value.defined; + + switch (defined) { + case kProtocol: + value = lstFset_get(t->vars, "protocol"); + break; + + case kServerName: /* HOSTNAME */ + value = "10.10.10.22"; + break; + + case kMethod: + value = lstFset_get(t->vars, "method"); + break; + + case kContentType: + value = lstFset_get(t->req_hdrs, "content-type"); + break; + + case kUserAgent: + value = lstFset_get(t->req_hdrs, "user-agent"); + break; + + case kContentLength: + value = lstFset_get(t->req_hdrs, "content-length"); + break; + + case kRequestURI: + /* request URI: parsed URI, no dynamo args or query args. */ + value = lstFset_get(t->vars, "uri"); + break; + + case kQueryString: + value = lstFset_get(t->vars, "query"); + break; + + case kPathInfo: + /* path-iinfo: path_info + dynamo-args */ + value = lstFset_get(t->vars, "req_uri"); + break; + + case kRemoteAddr: + value = lstFset_get(t->vars, "remote_addr"); + if (value == NULL) { + char remote_addr[16]; + utlFip_to_str(t->cli_ipv4_addr, remote_addr, 16); + lstFset_add(t->vars, "remote_addr", remote_addr); + value = lstFset_get(t->vars, "remote_addr"); + } + break; + + case kRemoteHost: + value = lstFset_get(t->vars, "remote_addr"); + if (value == NULL) { + char remote_addr[16]; + utlFip_to_str(t->cli_ipv4_addr, remote_addr, 16); + lstFset_add(t->vars, "remote_addr", remote_addr); + value = lstFset_get(t->vars, "remote_addr"); + } + break; + + case kAuthType: + break; + + case kRemoteUser: + + break; + + case kPathTranslated: + /* + * This should be the full path to the jhtml file on the dyanmo app + * server. If this is NULL, the dynamo server will try to work out + * the path from the request uri and it's idea of the document root, + * if it's configured to do so. + */ + value = lstFset_get(t->vars, "path"); + break; + + case kServerPort: + value = "8990"; + break; + + case kServletPath: + + break; + + case kScheme: + /* This is used by dynamo for building redirects. */ + value = "http"; + break; + + default: + break; + + } + } else { +#ifdef DEBUG + logFmsg(3, "mod/dynamo: getParameter: Called for undefined."); +#endif + } + + if (value) { + concatenate(oVal, value); + return returnValue; + } else { + return 0; + } +} + +/** + * GetNthHeader_fn + * Retrieve the name and value (in ascii) of the nth request header. + * pShellData: shell-specific (request-specific) data object + * iHeaderNum: 0-based index of header to retrieve + * oName, oVal: (growable) buffers in which to store header name and value + * (in ascii) (if no header for iHeaderNum, return successfully + * with empty name and val buffers) + * return: 0 == success; !0 == failure (other than no such header) + */ +int GetNthHeader(void *pShellData, int iHeaderNum, growBuffer * oName, + growBuffer * oVal) +{ + httpTtrans *t = (httpTtrans *) pShellData; + int index; + + index = lstFnth_find(t->req_hdrs, iHeaderNum); + + oName->used = 0; + oName->buffer[0] = kChar_Null; + oVal->used = 0; + oVal->buffer[0] = kChar_Null; + + if (index == -1) { + return 0; + } + concatenate(oName, t->req_hdrs->fields[index].name); + concatenate(oVal, t->req_hdrs->fields[index].value); + + return 0; +} + + +/** + * ReadFromAgent_fn + * Read at most iMaxLength bytes from the user agent (browser). + * pShellData: shell-specific (request-specific) data object + * oBuffer: buffer in which to store data read from browser; this callback + * should not increase the size available in oBuffer + * iMaxLength: maximum number of bytes to read from agent; actual number of + * bytes read is indicated via oBuffer->used. guaranteed to be + * <= bytes available in oBuffer. + * return: 0 == success (including EOF); !0 == failure (other than EOF) + * note: if the data stream to the agent has been closed (physically or + * logically), return failure. + */ +int ReadFromAgent(void *pShellData, growBuffer * oBuffer, + size_t iMaxLength) +{ + httpTtrans *t = (httpTtrans *) pShellData; + char *clen; + int read; + + if (t->client_read == 0) { + clen = lstFset_get(t->req_hdrs, "content-length"); + if (clen == NULL) + return 0; + t->client_read = atoi(clen); + } + if (t->client_read == -1) + return 0; + + if (iMaxLength < t->client_read) + read = httpFread(t, oBuffer->buffer, iMaxLength); + else + read = httpFread(t, oBuffer->buffer, t->client_read); + + + if (read < 1) + return -1; + + oBuffer->used = read; + + t->client_read -= read; + if (t->client_read == 0) + t->client_read = -1; + + return 0; +} + +/** + * WriteToAgent_fn + * Write iLength bytes to the user agent (browser). + * pShellData: shell-specific (request-specific) data object + * iBuffer: contains data to write to agent + * iLength: number of bytes to write to agent. + * return: 0 == success (all bytes were written); !0 == failure + * note: if the data stream to the agent has been closed (physically or + * logically), return failure. + */ +int WriteToAgent + (void *pShellData, const growBuffer * iBuffer, size_t iLength) { + httpTtrans *t = (httpTtrans *) pShellData; + + if (httpFwrite(t, iBuffer->buffer, iLength) != iLength) + return -1; + + return 0; +} + +/** + * FlushData_fn + * Flush the data stream to the user agent (browser), if possible. + * pShellData: shell-specific (request-specific) data object + * note: if the data stream to the agent has been closed (physically or + * logically), return failure. + */ +int FlushData(void *pShellData) { + httpTtrans *t = (httpTtrans *) pShellData; + + /* + * Flushing is not required for continuity, since writes aren't buffered + */ + + return 0; + +} + +/** + * CloseData_fn + * Close the data stream to the user agent (browser), if possible. + * pShellData: shell-specific (request-specific) data object + * note: if it is not possible or advisable for the CM shell to close the + * data stream, it is permissible to mark it as closed for the + * purpose of responding to future callbacks as if the stream were + * closed. + */ +int CloseData(void *pShellData) { + httpTtrans *t = (httpTtrans *) pShellData; + + /* Shouldn't do this under Continuity.. Just pretend. */ + /* close(t->sd); */ + + return 0; +} + +/** + * SendHeaderBatch_fn + * Send HTTP response status and header(s) to user agent (browser); + * headers are provided in a preformatted block. + * pShellData: shell-specific (request-specific) data object + * iStatusCode: HTTP status code (e.g. 200) + * iStatusMesg: optional status message for HTTP status line + * iMesgLength: number of relevant bytes in iStatusMesg; test iMesgLength + * rather than iStatusMesg for presence of message + * iHeaders: preformatted block of header name-value pairs, including + * newlines (should need no parsing by shell) + * iHeadersLength: number of relevant bytes in iHeaders + * return: 0 == success; !0 == failure + * note: a CM shell implementation need implement only one of + * SendHeaderBatch or SendHeaderNoBatch; the shell's expectation is + * noted in the DRP Context Block passed to drpService. a shell + * that registers itself as expecting batched headers need not + * implement a SetResponseHeader callback. + */ + +/* UNIMPLEMENTED */ + +/** + * SendHeaderNoBatch_fn + * Send HTTP response status and header(s) to user agent (browser); + * headers will have been provided already via SetResponseHeader callback, + * and must be sent with this callback. + * pShellData: shell-specific (request-specific) data object + * iStatusCode: HTTP status code (e.g. 200) + * iStatusMesg: optional status message for HTTP status line + * iMesgLength: number of relevant bytes in iStatusMesg; test iMesgLength + * rather than iStatusMesg for presence of message + * return: 0 == success; !0 == failure + * note: a CM shell implementation need implement only one of + * SendHeaderBatch or SendHeaderNoBatch; the shell's expectation is + * noted in the DRP Context Block passed to drpService. a shell + * that registers itself as expecting batched headers need not + * implement a SetResponseHeader callback. + */ + +int SendHeaderNoBatch + (void *pShellData, drpInt iStatusCode, const char *iStatusMesg, + size_t iMesgLength) { + httpTtrans *t = (httpTtrans *) pShellData; + + httpFset_status(t, iStatusCode, NULL); + httpFstart_response(t); + httpFsend_response(t); + + return 0; +} + +/** + * SetResponseHeader_fn + * Set a single HTTP response header name-value pair, to be sent to the agent + * when SendHeaderNoBatch is invoked. + * pShellData: shell-specific (request-specific) data object + * iHeaderName: name of response header (ascii, null-terminated) + * iHeaderValue: value of response header (ascii, null-terminated) + * return: 0 == success; !0 == failure + * note: a shell that registers itself as expecting batched headers need not + * implement a SetResponseHeader callback. + */ + +int SetResponseHeader + (void *pShellData, const growBuffer * iHeaderName, + const growBuffer * iHeaderValue) { + httpTtrans *t = (httpTtrans *) pShellData; + + /* strFtolower(iHeaderName->buffer); */ + + /* remove in case we already have it */ + lstFset_delete_key(t->res_hdrs, iHeaderName->buffer); + lstFset_add(t->res_hdrs, iHeaderName->buffer, iHeaderValue->buffer); + + return 0; +} + +/** + * cmldrpInitialize + * Initializes the CMLDRP subsystem and initiates the first attempt to + * obtain DRP server information from a CMLDRP server (in the multiprocess + * case) or starts the CMLDRP thread (in the multithreaded case). + * iNumServers: number of CMLDRP server info blocks in iServers + * iServers: array of CMLDRP_ServerInfo objects + * iBindAddress: address to which CMLDRP subsystem should bind its socket + * (NULL: bind to any appropriate local address) + * iHTTPPort: main service port of the host HTTP server (for purposes of + * identifying this CMLDRP client to the CMLDRP server). + * iLogFunction: http-server-API-specific logging routine + * iLogShellData: opaque shellData object to be passed to iLogFunction + * return: 0 == success; !0 == failure + */ + +/* + * cmldrpInitialize(int iNumServers, CMLDRP_ServerInfo * iServers, const char * + * iBindAddress, unsigned short iHTTPPort, LogMessage_fn iLogFunction, void * + * iLogShellData) { + */ + +int dynamoFinit(void *p, lstTset * o) +{ + CMLDRP_ServerInfo server; + char *host = lstFset_get(o, "cmldrp_host"); + char *port = lstFset_get(o, "cmldrp_port"); + + logFmsg(0, "mod/dynamo: Dynamo Connection Manager v.%s (module)", + kCM_VersionNumber); + logFmsg(0, "mod/dynamo: Copyright (c) 2003, Alex Leigh"); + logFmsg(0, "mod/dynamo: Copyright (c) 1997, Art Technology Group"); + + if (host == NULL || port == NULL) { + logFmsg(2, + "mod/dynamo: cmldrp_host and cmldrp_port not configured! Exiting.."); + exit(5); + } + server.host = malloc(strlen(host) + 1); + strcpy(server.host, host); + server.port = atoi(port); + + logFmsg(0, "mod/dynamo: Using CMLDDRP server %s:%s", host, port); + + return cmldrpInitialize(1, &server, NULL, 8990, &logHook, NULL); +} + +/** + * DefinedLength_fn + * Return the length of the shell-specific ascii representation of the + * indicated DRP defined string. + * iDefined: DRP defined string String-ID. + * return: length of shell's representation of iDefined; 0 if the shell has + * no representation for iDefined + */ +/* + * typedef int (* DefinedLength_fn) (drpByte iDefined); + */ + +int definedLength(void *shellData, drpByte iDefined) +{ + return 0; +} + +/** + * DefinedAscii_fn + * Return the (null-terminated) shell-specific ascii representation of the + * indicated DRP defined string. + * iDefined: DRP defined string String-ID. + * return: shell's representation of iDefined; NULL if the shell has no + * representation for iDefined. + */ +/* + * typedef const char * (* DefinedAscii_fn) (drpByte iDefined); + */ + +int definedAscii(void *shellData, drpByte iDefined) +{ + return NULL; +} + + +int dynamoFsession(httpTtrans * t, lstTset * arg) +{ + char *path = lstFset_get(t->vars, "uri"); + char *session; + + session = strstr(path, ";$sessionid"); + + if (session != NULL) { + *session = '\0'; /* truncate the session */ + session++; + lstFset_add(t->vars, "drp-session", session); + } + return STATUS_PROCEED; +} + +int dynamoFservice(httpTtrans * trans, lstTset * arg) +{ + drpContextBlock *gClientData = NULL; + int ret; + +#ifdef DEBUG + logFmsg(3, "mod/dynamo: dynamoFservice called."); +#endif + + tasFstat_counter_add("http_svc", 0, "dynamoFservice", 1); + + gClientData = (drpContextBlock *) malloc(sizeof(drpContextBlock)); + memset(gClientData, 0, sizeof(drpContextBlock)); + + drpReset(gClientData); + + gClientData->getParameter = &GetParameter; + gClientData->getNthHeader = &GetNthHeader; + gClientData->readFromAgent = &ReadFromAgent; + gClientData->writeToAgent = &WriteToAgent; + gClientData->flushData = &FlushData; + gClientData->closeData = &CloseData; + gClientData->sendHeaderBatch = NULL; + gClientData->sendHeaderNoBatch = &SendHeaderNoBatch; + gClientData->setResponseHeader = &SetResponseHeader; + gClientData->definedStringLength = &definedLength; + gClientData->definedStringToAscii = &definedAscii; + gClientData->logMessage = &logHook; + + gClientData->shellExpectsHeaderPairs = 1; /* not batched */ + gClientData->shellData = (void *) trans; + + /* set request logging */ + /* gClientData->isLoggedRequest = 1; */ + + /* set debugging */ + gClientData->debugEnabled = 1; + + /* Max DRP connect timeout */ + gClientData->maxConnectTimeout = 30; + + ret = drpService(gClientData); + + if (ret != 0) { + httpFset_status(trans, 500, "drpService() failed."); + httpFstart_response(trans); + httpFsend_response(trans); + httpFerror_page(trans, "drpService() failed."); + } + return STATUS_EXIT; +} diff --git a/mk4/moddynamo/io.c b/mk4/moddynamo/io.c new file mode 100644 index 0000000..6f85275 --- /dev/null +++ b/mk4/moddynamo/io.c @@ -0,0 +1,1672 @@ +/* io.c: + * + * Implementation of buffered streams. + * + * Copyright (C) 1997 Art Technology Group, Inc. + * All Rights Reserved. No use, copying or distribution of this + * work may be made except in accordance with a valid license + * agreement from Art Technology Group. This notice must be + * included on all copies, modifications and derivatives of this + * work. + */ + +#include "DRPTypes.h" +#include "io.h" +#include "DynSock.h" + + +#define DEFAULT_BUFFER_SIZE 4098 + + +/*--------------------------------------------------------------- + * External Globals + */ + +#ifdef _ISAPI +/* + * Our own heap for handling frequent memory allocations. + */ +extern HANDLE gHeap; +#endif + + +static const char *IOStatusMessages[IOStatusCount] = { + "Succeeded", + "Generic failure", + "Feature has not been implemented", + "No more data", + "Read error", + "Write error", + "Bad URL", + "Unknown host", + "No more sockets", + "Connection refused", + "Network error", + "Memory exhausted", + "No more files can be opened", + "No such file", + "Permission denied", + "Buffer overflow", + "Protocol error", + "Protocol version mismatch", + "Operation failed due to excessive time", + "Socket system initialization failed", +}; + +#ifdef WIN32 +/*----------------------------------------------------------------------------- + * Used to manage WinSock subsystem initialization + */ +static BOOL WinsockInitialized = FALSE; + +static IOStatus initializeWinsock() +{ + WSADATA info; + if (WSAStartup(MAKEWORD(1, 1), &info) != 0) + return IOStatusInitializationFailed; + return IOStatusOk; +} +#endif /* WIN32 */ + +/*----------------------------------------------------------------------------- + * Returns a human-readable string describing the indicated IOStatus value. + */ +const char *getIOStatusString(IOStatus status) +{ + if ((status >= 0) && (status < IOStatusCount)) + return IOStatusMessages[(int) status]; + else + return "Unknown status value"; +} + +/*----------------------------------------------------------------------------- + * Creates a buffered input stream. + * Returns NULL if unable to create a stream because out of memory. + */ +InputStream *createInputStream(void *handle, + InputStreamReader reader, + InputStreamCloser closer, int bufferSize) +{ +#ifdef _ISAPI + InputStream *retStream = HeapAlloc(gHeap, 0, sizeof(InputStream)); +#else + InputStream *retStream = malloc(sizeof(InputStream)); +#endif + if (retStream == NULL) + return NULL; + + memset(retStream, 0, sizeof(InputStream)); + + if (bufferSize <= 0) + bufferSize = DEFAULT_BUFFER_SIZE; + if (retStream != NULL) { + retStream->handle = handle; + retStream->reader = reader; + retStream->closer = closer; + retStream->bufferSize = bufferSize; + retStream->timeout = 0; + retStream->status = IOStatusOk; +#ifdef _ISAPI + retStream->buffer = HeapAlloc(gHeap, 0, bufferSize); + if (retStream->buffer == NULL) { + (void) HeapFree(gHeap, 0, retStream); + retStream = NULL; + } +#else + retStream->buffer = malloc(bufferSize); + if (retStream->buffer == NULL) { + free(retStream); + retStream = NULL; + } +#endif + } + return retStream; +} + +/*----------------------------------------------------------------------------- + * Fills the buffer of an input stream as much as immediately possible. Waits + * for more input if none is immediately available. This is intended for + * internal use. + */ +IOStatus fillInputStream(InputStream * stream) +{ + int spaceAvail; + int bytesRead; + + if (stream->readp == stream->avail) /* reset read pointers */ + stream->readp = stream->avail = 0; + spaceAvail = stream->bufferSize - stream->avail; + if (spaceAvail > 0) { + stream->status = + stream->reader(stream->handle, &stream->buffer[stream->readp], + spaceAvail, stream->timeout, &bytesRead); + if (stream->status == IOStatusOk) + stream->avail += bytesRead; + } + return stream->status; +} + +/*----------------------------------------------------------------------------- + * Reads some data from an input stream. + */ +IOStatus readSomeFromInputStream(InputStream * stream, void *retBuffer, + int size, int *retBytesRead) +{ + /* if the buffer is empty, fill it. + */ + if (stream->readp == stream->avail) + fillInputStream(stream); + + /* return as much data from the read buffer as we can. + */ + if (size > stream->avail - stream->readp) + size = stream->avail - stream->readp; + memcpy(retBuffer, &stream->buffer[stream->readp], size); + stream->readp += size; + *retBytesRead = size; + return stream->status; +} + +/*----------------------------------------------------------------------------- + * Reads as much data as is requested from an input stream, if possible. + */ +IOStatus readFromInputStream(InputStream * stream, void *retBuffer, + int size, unsigned int *read) +{ + char *bp = retBuffer; + while ((stream->status == IOStatusOk) && (size > 0)) { + int bytesToCopy; + + if (stream->avail == stream->readp) + fillInputStream(stream); + bytesToCopy = stream->avail - stream->readp; + if (bytesToCopy > size) + bytesToCopy = size; + memcpy(bp, &stream->buffer[stream->readp], bytesToCopy); + stream->readp += bytesToCopy; + bp += bytesToCopy; + size -= bytesToCopy; + } + *read = size; + return stream->status; +} + +/*----------------------------------------------------------------------------- + * Destroys an input stream, closing its source if a closer function was specified. + */ +IOStatus destroyInputStream(InputStream * stream) +{ + IOStatus status = IOStatusOk; + if (stream->closer != NULL) + status = stream->closer(stream->handle); +#ifdef _ISAPI + (void) HeapFree(gHeap, 0, stream->buffer); + (void) HeapFree(gHeap, 0, stream); +#else + free(stream->buffer); + free(stream); +#endif + return status; +} + +/*----------------------------------------------------------------------------- + * Creates a buffered output stream. + * Returns NULL if unable to create a stream because out of memory. + */ +OutputStream *createOutputStream(void *handle, + OutputStreamWriter writer, + OutputStreamCloser closer, int bufferSize) +{ +#ifdef _ISAPI + OutputStream *retStream = HeapAlloc(gHeap, 0, sizeof(OutputStream)); +#else + OutputStream *retStream = malloc(sizeof(OutputStream)); +#endif + if (retStream == NULL) + return NULL; + + memset(retStream, 0, sizeof(OutputStream)); + + if (bufferSize <= 0) + bufferSize = DEFAULT_BUFFER_SIZE; + if (retStream != NULL) { + retStream->handle = handle; + retStream->writer = writer; + retStream->closer = closer; + retStream->bufferSize = bufferSize; + retStream->status = IOStatusOk; +#ifdef _ISAPI + retStream->buffer = HeapAlloc(gHeap, 0, bufferSize); + if (retStream->buffer == NULL) { + (void) HeapFree(gHeap, 0, retStream); + retStream = NULL; + } +#else + retStream->buffer = malloc(bufferSize); + if (retStream->buffer == NULL) { + free(retStream); + retStream = NULL; + } +#endif + } + return retStream; +} + +/*----------------------------------------------------------------------------- + * Writes data to a buffered output stream. + */ +IOStatus writeToOutputStream(OutputStream * stream, const void *buf, + int size) +{ + const char *bp = (const char *) buf; + while ((stream->status == IOStatusOk) && (size > 0)) { + /* if the buffer is empty and the data to write is larger than + * the buffer, send it straight through the writer to avoid the copy. + */ + if ((stream->writep == 0) && (size > stream->bufferSize)) { + stream->status = stream->writer(stream->handle, bp, size); + break; + } else { + int bytesToCopy = stream->bufferSize - stream->writep; + if (bytesToCopy > size) + bytesToCopy = size; + memcpy(&stream->buffer[stream->writep], bp, bytesToCopy); + bp += bytesToCopy; + stream->writep += bytesToCopy; + size -= bytesToCopy; + + /* if the buffer is full, flush it. */ + if (stream->writep == stream->bufferSize) { + stream->status = + stream->writer(stream->handle, stream->buffer, + stream->bufferSize); + stream->writep = 0; + } + } + } + return stream->status; +} + +/*----------------------------------------------------------------------------- + * Flushes buffered data to the output stream. + */ +IOStatus flushOutputStream(OutputStream * stream) +{ + if (stream->writep > 0) { + stream->status = + stream->writer(stream->handle, stream->buffer, stream->writep); + stream->writep = 0; + } + return stream->status; +} + +/*----------------------------------------------------------------------------- + * Copies an InputStream to an OutputStream. + */ +IOStatus copyToOutputStream(OutputStream * outStream, + InputStream * inStream) +{ + IOStatus status; + + /* copy any buffered input directly to the output + */ + if (inStream->readp < inStream->avail) { + status = writeToOutputStream(outStream, + &inStream->buffer[inStream->readp], + inStream->avail - inStream->readp); + inStream->avail = inStream->readp = 0; + if (status != IOStatusOk) + return status; + } + + /* flush the output buffer + */ + status = flushOutputStream(outStream); + + /* at this point both the input and output buffers are completely + * empty, allowing us to read directly into the output buffer and + * avoid a copy. + */ + while (status == IOStatusOk) { + int br; + + /* read a chunk of data */ + status = + inStream->reader(inStream->handle, outStream->buffer, + outStream->bufferSize, inStream->timeout, + &br); + if (status != IOStatusOk) { + if (status == IOStatusNoMoreData) + return IOStatusOk; + else + break; + } + + /* write the chunk of data */ + status = + outStream->writer(outStream->handle, outStream->buffer, br); + } + return status; +} + +/*----------------------------------------------------------------------------- + * Destroys an output stream, flushing its buffered data and closing its + * destination if a closer function was specified. + */ +IOStatus destroyOutputStream(OutputStream * stream) +{ + IOStatus status = IOStatusOk; + flushOutputStream(stream); + if (stream->closer != NULL) + status = stream->closer(stream->handle); +#ifdef _ISAPI + (void) HeapFree(gHeap, 0, stream->buffer); + (void) HeapFree(gHeap, 0, stream); +#else + free(stream->buffer); + free(stream); +#endif + return status; +} + +/*----------------------------------------------------------------------------- + * Flushes deferred output buffers to the raw output stream. + */ +static IOStatus flushDeferredOutputStreamBuffers(DeferredOutputStreamHandle + * doh) +{ + IOStatus status = IOStatusOk; + DeferredOutputStreamBuffer *dob = doh->deferredBuffers; + while (dob != NULL) { + DeferredOutputStreamBuffer *oldDob = dob; + dob = dob->next; + if (status == IOStatusOk) + status = + writeToOutputStream(doh->rawOutputStream, oldDob->buffer, + oldDob->bufferSize); +#ifdef _ISAPI + (void) HeapFree(gHeap, 0, oldDob->buffer); + (void) HeapFree(gHeap, 0, oldDob); +#else + free(oldDob->buffer); + free(oldDob); +#endif + } + doh->deferredBuffers = doh->lastDeferredBuffer = NULL; + if (status == IOStatusOk) + status = flushOutputStream(doh->rawOutputStream); + return status; +} + +/*----------------------------------------------------------------------------- + * Destroys both an input and output streams and handles the case when + * the two streams share the same handle. + * + * When you destroy a stream, you close its dynamo handle. In this + * case we are closing two streams. If these streams have the same + * handle then closing the same handle twice may be bad. For example + * closing the same dynamo socket more than once is bad because you + * will free the same memory more than once. + * + * To prevent this from happening in the case where both streams have + * the same handle we explicitly close the handle once and then set + * the closer functions of each stream to NULL so that they will not + * close their handles when they are destroyed. + */ +IOStatus destroyIOStreams(InputStream * pInStream, + OutputStream * pOutStream) +{ + IOStatus status = IOStatusOk, tempStatus; + if (pInStream && pOutStream) { + if (pInStream->handle && pInStream->handle == pOutStream->handle) { + tempStatus = pInStream->closer(pInStream->handle); + pInStream->closer = NULL; + pOutStream->closer = NULL; + } + status = destroyInputStream(pInStream); + status = destroyOutputStream(pOutStream); + } else if (pInStream) + status = destroyInputStream(pInStream); + else if (pOutStream) + status = destroyOutputStream(pOutStream); + + return status; +} + +/*----------------------------------------------------------------------------- + + * Handles deferred output buffering. + */ +static IOStatus deferredOutputWriter(void *handle, const void *buf, + int size) +{ + DeferredOutputStreamHandle *doh = + (DeferredOutputStreamHandle *) handle; + OutputStream *myOutStream = doh->myOutputStream; + + if (size == 0) + return IOStatusOk; + if (doh->mode == OutputDeferred) { +#ifdef _ISAPI + DeferredOutputStreamBuffer *dob = (DeferredOutputStreamBuffer *) + HeapAlloc(gHeap, HEAP_ZERO_MEMORY, + sizeof(DeferredOutputStreamBuffer)); +#else + DeferredOutputStreamBuffer *dob = (DeferredOutputStreamBuffer *) + calloc(1, sizeof(DeferredOutputStreamBuffer)); +#endif + if (dob == NULL) + return IOStatusMemoryExhausted; /* Doh! */ + + /* if we're writing the entire output stream buffer, just move the + * buffer into the buffer list and allocate a new one. this avoids + * a buffer copy in some common cases. + */ + if ((buf == myOutStream->buffer) + && (size == myOutStream->bufferSize)) { + dob->buffer = myOutStream->buffer; + dob->bufferSize = size; + + /* create a new output stream buffer + */ +#ifdef _ISAPI + myOutStream->buffer = + HeapAlloc(gHeap, 0, myOutStream->bufferSize); + if (myOutStream->buffer == NULL) { + (void) HeapFree(gHeap, 0, dob->buffer); + (void) HeapFree(gHeap, 0, dob); + return IOStatusMemoryExhausted; + } +#else + myOutStream->buffer = malloc(myOutStream->bufferSize); + if (myOutStream->buffer == NULL) { + free(dob->buffer); + free(dob); + return IOStatusMemoryExhausted; + } +#endif + } + + /* move written data into a buffer in the buffer list. + */ + else { +#ifdef _ISAPI + dob->buffer = HeapAlloc(gHeap, 0, size); + if (dob->buffer == NULL) { + (void) HeapFree(gHeap, 0, dob); + return IOStatusMemoryExhausted; + } +#else + dob->buffer = malloc(size); + if (dob->buffer == NULL) { + free(dob); + return IOStatusMemoryExhausted; + } +#endif + dob->bufferSize = size; + memcpy(dob->buffer, buf, size); + } + + /* append the new buffer to the deferred buffer list. + */ + if (doh->lastDeferredBuffer == NULL) + doh->deferredBuffers = dob; + else + doh->lastDeferredBuffer->next = dob; + doh->lastDeferredBuffer = dob; + + return IOStatusOk; + } else /* pass-through mode */ + return writeToOutputStream(doh->rawOutputStream, buf, size); +} + +/*----------------------------------------------------------------------------- + * Flushes deferred output and cleans up the handle. + */ +static IOStatus deferredOutputFinalizer(void *handle) +{ + DeferredOutputStreamHandle *doh = + (DeferredOutputStreamHandle *) handle; + IOStatus status = flushDeferredOutputStreamBuffers(doh); + destroyOutputStream(doh->rawOutputStream); + free(doh); + return status; +} + +/*----------------------------------------------------------------------------- + * Creates a deferred (buffered) output stream. + */ +IOStatus createDeferredOutputStream(OutputStream * rawOutputStream, + OutputStream ** retStream) +{ + OutputStream *outStream; +#ifdef _ISAPI + DeferredOutputStreamHandle *handle = + HeapAlloc(gHeap, HEAP_ZERO_MEMORY, + sizeof(DeferredOutputStreamHandle)); +#else + DeferredOutputStreamHandle *handle = + calloc(1, sizeof(DeferredOutputStreamHandle)); +#endif + if (handle == NULL) + return IOStatusMemoryExhausted; + outStream = + createOutputStream(handle, deferredOutputWriter, + deferredOutputFinalizer, -1); + if (outStream == NULL) { +#ifdef _ISAPI + (void) HeapFree(gHeap, 0, handle); +#else + free(handle); +#endif + return IOStatusMemoryExhausted; + } + handle->myOutputStream = outStream; + handle->rawOutputStream = rawOutputStream; + handle->mode = OutputDeferred; + *retStream = outStream; + return IOStatusOk; +} + +/*----------------------------------------------------------------------------- + * Changes the deferred output stream mode between buffered and passed-through. + */ +IOStatus setDeferredOutputMode(OutputStream * outStream, + DeferredOutputStreamMode mode) +{ + IOStatus status; + DeferredOutputStreamHandle *doh = + (DeferredOutputStreamHandle *) outStream->handle; + switch (mode) { + case OutputDeferred: + status = IOStatusOk; + doh->mode = mode; + break; + case OutputPassedThrough: + status = flushOutputStream(outStream); + if (status == IOStatusOk) + status = flushDeferredOutputStreamBuffers(doh); + doh->mode = mode; + break; + default: + status = IOStatusFailed; /* silly user, tricks are for kids */ + break; + } + return status; +} + +/*----------------------------------------------------------------------------- + * Writes all deferred output to the raw output stream. + */ +IOStatus writeDeferredOutput(OutputStream * outStream) +{ + return flushDeferredOutputStreamBuffers((DeferredOutputStreamHandle *) + outStream->handle); +} + +/*----------------------------------------------------------------------------- + * Given a host name and port number, this returns an internet address. + */ +IOStatus getSocketAddress(const char *hostname, int port, + struct sockaddr_in * retAddress) +{ + struct sockaddr_in address; + struct hostent *hp; + +#ifdef WIN32 + if (!WinsockInitialized) { + IOStatus status = initializeWinsock(); + if (status != IOStatusOk) + return status; + } +#endif /* WIN32 */ + + /* create an internet address from the host name and port number. + */ + hp = gethostbyname(hostname); + if (hp == NULL) + return IOStatusUnknownHost; + memset(&address, 0, sizeof(struct sockaddr_in)); + memcpy((char *) &address.sin_addr, hp->h_addr, hp->h_length); + address.sin_family = hp->h_addrtype; + address.sin_port = htons((unsigned short) port); + *retAddress = address; + return IOStatusOk; +} + +#ifdef WIN32 +/*----------------------------------------------------------------------------- + * Connects a socket to a server and returns input and output streams for it, + * or fails if a connection cannot be established in a given number of + * milliseconds. + * + * FIXME: Because createSocketIOStreamsFromAddressWithTimeout() is + * only supported on WIN32, this function can only be supported on + * WIN32. + */ +IOStatus createSocketIOStreamsWithTimeout(const char *hostname, int port, + int timeout, + InputStream ** retInStream, + OutputStream ** retOutStream) +{ + struct sockaddr_in address; + IOStatus status = getSocketAddress(hostname, port, &address); + if (status != IOStatusOk) + return status; + return createSocketIOStreamsFromAddressWithTimeout(address, timeout, + retInStream, + retOutStream); +} +#endif + +#ifdef WIN32 +/**************************************************** + * Win32-specific I/O stream implementations follow * + ****************************************************/ + +/*----------------------------------------------------------------------------- + * Converts a WIN32 "last error" value to an IOStatus value. + */ +static IOStatus lastErrorToIOStatus() +{ + switch (GetLastError()) { + case ERROR_FILE_NOT_FOUND: + case ERROR_PATH_NOT_FOUND: + case ERROR_INVALID_DRIVE: + case ERROR_BAD_UNIT: + case ERROR_BAD_NETPATH: + case ERROR_NETNAME_DELETED: + case ERROR_BAD_NET_NAME: + return IOStatusNoSuchFile; + case ERROR_ACCESS_DENIED: + case ERROR_WRITE_PROTECT: + case ERROR_SHARING_VIOLATION: + case ERROR_LOCK_VIOLATION: + case ERROR_SHARING_BUFFER_EXCEEDED: + case ERROR_NETWORK_ACCESS_DENIED: + return IOStatusPermissionDenied; + break; + case ERROR_NO_MORE_FILES: + case ERROR_TOO_MANY_SESS: + case ERROR_REQ_NOT_ACCEP: + return IOStatusNoMoreFiles; + case ERROR_OUTOFMEMORY: + case ERROR_NOT_ENOUGH_MEMORY: + case ERROR_OUT_OF_STRUCTURES: + return IOStatusMemoryExhausted; + case ERROR_CRC: + case ERROR_SEEK: + case ERROR_SECTOR_NOT_FOUND: + case ERROR_READ_FAULT: + return IOStatusReadError; + case ERROR_WRITE_FAULT: + case ERROR_HANDLE_DISK_FULL: + case ERROR_NET_WRITE_FAULT: + case ERROR_DISK_FULL: + return IOStatusWriteError; + case ERROR_HANDLE_EOF: + return IOStatusNoMoreData; + case ERROR_REM_NOT_LIST: + case ERROR_NETWORK_BUSY: + case ERROR_DEV_NOT_EXIST: + case ERROR_ADAP_HDW_ERR: + case ERROR_BAD_NET_RESP: + case ERROR_UNEXP_NET_ERR: + case ERROR_BAD_REM_ADAP: + return IOStatusNetworkError; + default: + return IOStatusFailed; + } +} + +/*----------------------------------------------------------------------------- + */ +static IOStatus handleReader(void *handle, void *retBuf, int size, + int timeout, int *retBytesRead) +{ + if (!ReadFile + ((HANDLE) handle, retBuf, size, (LPDWORD) retBytesRead, NULL)) + return IOStatusFailed; + else if (*retBytesRead == 0) + return IOStatusNoMoreData; + else + return IOStatusOk; +} + +/*----------------------------------------------------------------------------- + */ +static IOStatus handleWriter(void *handle, const void *buf, int size) +{ + const char *bp = (const char *) buf; + while (size > 0) { + DWORD bytesWritten; + if (!WriteFile((HANDLE) handle, bp, size, &bytesWritten, NULL)) + return IOStatusFailed; + bp += bytesWritten; + size -= bytesWritten; + } + return IOStatusOk; +} + +/*----------------------------------------------------------------------------- + */ +static IOStatus handleCloser(void *handle) +{ + CloseHandle((HANDLE) handle); + return IOStatusOk; +} + +/*----------------------------------------------------------------------------- + */ +static IOStatus socketReader(void *handle, void *retBuf, int size, + int timeout, int *retBytes) +{ + SOCKET sock = (SOCKET) handle; + + for (;;) { + int br; + + if (timeout > 0) { + fd_set readfds; + struct timeval timeout_val; + + FD_ZERO(&readfds); + FD_SET(sock, &readfds); + timeout_val.tv_sec = timeout / 1000; + timeout_val.tv_usec = timeout % 1000; + if (select(1, &readfds, NULL, NULL, &timeout_val) == + SOCKET_ERROR) + return IOStatusFailed; + if (!FD_ISSET(sock, &readfds)) + return IOStatusTimeout; + } + + br = recv(sock, retBuf, size, 0); + if (br == 0) { + *retBytes = 0; + return IOStatusNoMoreData; + } + if (br == SOCKET_ERROR) { + *retBytes = 0; + switch (WSAGetLastError()) { + case WSAEINTR: + continue; + case WSAECONNRESET: + return IOStatusNoMoreData; /* same thing */ + case WSAENETDOWN: + case WSAENETUNREACH: + case WSAENETRESET: + case WSAECONNABORTED: + case WSAEHOSTUNREACH: + case WSAEDISCON: + return IOStatusNetworkError; + default: + return IOStatusFailed; + } + } + *retBytes = br; + return IOStatusOk; + } +} + +/*----------------------------------------------------------------------------- + */ +static IOStatus socketWriter(void *handle, const void *buf, int size) +{ + SOCKET sock = (SOCKET) handle; + const char *bp = (const char *) buf; + + while (size > 0) { + int bw; + + bw = send(sock, bp, size, 0); + if (bw == SOCKET_ERROR) { + switch (WSAGetLastError()) { + case WSAEINTR: + continue; + case WSAENETDOWN: + case WSAENETUNREACH: + case WSAENETRESET: + case WSAECONNABORTED: + case WSAECONNRESET: + case WSAEHOSTUNREACH: + case WSAEDISCON: + return IOStatusNetworkError; + default: + return IOStatusFailed; + } + } + bp += bw; + size -= bw; + } + return IOStatusOk; +} + +/*----------------------------------------------------------------------------- + */ +static IOStatus socketCloser(void *handle) +{ + closesocket((SOCKET) handle); + return IOStatusOk; +} + +/*----------------------------------------------------------------------------- + * Creates (opens) a new file input stream. + */ +IOStatus createFileInputStream(const char *filename, + InputStream ** retStream) +{ + IOStatus status; + HANDLE handle = CreateFile(filename, + GENERIC_READ, +#if 1 + (FILE_SHARE_READ | FILE_SHARE_WRITE), +#else + FILE_SHARE_READ, +#endif + NULL, /* security */ + OPEN_EXISTING, + (FILE_ATTRIBUTE_NORMAL | + FILE_FLAG_SEQUENTIAL_SCAN), + INVALID_HANDLE_VALUE); + if (handle == INVALID_HANDLE_VALUE) { + status = lastErrorToIOStatus(); + } else { + status = createHandleInputStream(handle, TRUE, retStream); + if (status != IOStatusOk) + CloseHandle(handle); + } + return status; +} + +/*----------------------------------------------------------------------------- + * Creates (opens) a new file output stream. + */ +IOStatus createFileOutputStream(const char *filename, + OutputStream ** retStream) +{ + IOStatus status; + HANDLE handle = CreateFile(filename, + GENERIC_WRITE, +#if 1 + (FILE_SHARE_READ | FILE_SHARE_WRITE), +#else + 0, /* exclusive write */ +#endif + NULL, /* security */ + (CREATE_ALWAYS /*|TRUNCATE_EXISTING */ ), + FILE_ATTRIBUTE_NORMAL, + INVALID_HANDLE_VALUE); + if (handle == INVALID_HANDLE_VALUE) { + switch (GetLastError()) { + default: + status = IOStatusFailed; + } + } else { + status = createHandleOutputStream(handle, TRUE, retStream); + if (status != IOStatusOk) + CloseHandle(handle); + } + return status; +} + +/*----------------------------------------------------------------------------- + * Wraps a generic I/O handle with an input stream. + */ +IOStatus createHandleInputStream(HANDLE handle, int doClose, + InputStream ** retStream) +{ + *retStream = createInputStream((void *) handle, handleReader, + (doClose ? handleCloser : NULL), + DEFAULT_BUFFER_SIZE); + if (*retStream == NULL) + return IOStatusMemoryExhausted; + else + return IOStatusOk; +} + +/*----------------------------------------------------------------------------- + * Wraps a generic I/O handle with an output stream. + */ +IOStatus createHandleOutputStream(HANDLE handle, int doClose, + OutputStream ** retStream) +{ + *retStream = createOutputStream((void *) handle, handleWriter, + (doClose ? handleCloser : NULL), + DEFAULT_BUFFER_SIZE); + if (*retStream == NULL) + return IOStatusMemoryExhausted; + else + return IOStatusOk; +} + +/*----------------------------------------------------------------------------- + * Wraps a SOCKET with an input stream. + */ +IOStatus createSocketInputStream(SOCKET sock, int doClose, + InputStream ** retStream) +{ + *retStream = createInputStream((void *) sock, socketReader, + (doClose ? socketCloser : NULL), + DEFAULT_BUFFER_SIZE); + if (*retStream == NULL) + return IOStatusMemoryExhausted; + else + return IOStatusOk; +} + +/*----------------------------------------------------------------------------- + * Wraps a SOCKET with an output stream. + */ +IOStatus createSocketOutputStream(SOCKET sock, int doClose, + OutputStream ** retStream) +{ + *retStream = createOutputStream((void *) sock, socketWriter, + (doClose ? socketCloser : NULL), + DEFAULT_BUFFER_SIZE); + if (*retStream == NULL) + return IOStatusMemoryExhausted; + else + return IOStatusOk; +} + +/*----------------------------------------------------------------------------- + * Given a socket address structure, this connects a socket to a server and + * returns input and output streams for it. + * FIXME: Needs to be upgraded to support DynSock. + */ +IOStatus createSocketIOStreamsFromAddressWithTimeout(struct sockaddr_in + address, int timeout, + InputStream ** + retInStream, + OutputStream ** + retOutStream) +{ + int address_size = sizeof(struct sockaddr_in); + SOCKET sock; + IOStatus status; + + *retInStream = NULL; + *retOutStream = NULL; + if (!WinsockInitialized) { + IOStatus status = initializeWinsock(); + if (status != IOStatusOk) + return status; + } + /* create socket and socket event structures */ + sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock == SOCKET_ERROR) { + status = IOStatusNoMoreSockets; + goto cleanupAndFail; + } + + if (timeout > 0) { + DWORD blocking = 1; + if (ioctlsocket(sock, FIONBIO, &blocking) == SOCKET_ERROR) { + status = IOStatusFailed; + goto cleanupAndFail; + } + } + + if (connect(sock, (struct sockaddr *) &address, address_size) == + SOCKET_ERROR) { + switch (WSAGetLastError()) { + case WSAEWOULDBLOCK: /* ok so far */ + break; + case WSAECONNREFUSED: + status = IOStatusConnectionRefused; + goto cleanupAndFail; + default: + status = IOStatusFailed; + goto cleanupAndFail; + } + + /* wait for socket to connect */ + { + fd_set writefds; + fd_set exceptfds; + struct timeval timeout_val; + int result; + + FD_ZERO(&writefds); + FD_SET(sock, &writefds); + FD_ZERO(&exceptfds); + FD_SET(sock, &exceptfds); + timeout_val.tv_sec = timeout / 1000; + timeout_val.tv_usec = timeout % 1000; + result = select(1, NULL, &writefds, &exceptfds, &timeout_val); + if (result == SOCKET_ERROR) { + status = IOStatusFailed; + goto cleanupAndFail; + } + + /* see if connection failed */ + if (FD_ISSET(sock, &exceptfds)) { + status = IOStatusConnectionRefused; + goto cleanupAndFail; + } + + /* see if connection timed out */ + if (!FD_ISSET(sock, &writefds)) { + status = IOStatusTimeout; + goto cleanupAndFail; + } + } + + /* put socket back into blocking mode */ + if (timeout > 0) { + DWORD blocking = 0; + if (ioctlsocket(sock, FIONBIO, &blocking) == SOCKET_ERROR) { + status = IOStatusFailed; + goto cleanupAndFail; + } + } + } + + /* wrap the socket with I/O streams */ + status = createSocketInputStream(sock, TRUE, retInStream); + if (status != IOStatusOk) + goto cleanupAndFail; + status = createSocketOutputStream(sock, TRUE, retOutStream); + if (status != IOStatusOk) + goto cleanupAndFail; + + /* thank you for using AT&T */ + return IOStatusOk; + + cleanupAndFail: + if (*retInStream != NULL) + destroyInputStream(*retInStream); + if (*retOutStream != NULL) + destroyOutputStream(*retOutStream); + if (sock != SOCKET_ERROR) + closesocket(sock); + return status; +} + +#else /* assume it is UNIX */ + +/*************************************************** + * Unix-specific I/O stream implementations follow * + ***************************************************/ + +#include +#include +#include + +/*----------------------------------------------------------------------------- + * Converts a UNIX errno value to an IOStatus value + */ +static IOStatus errnoToIOStatus(int value) +{ + switch (value) { + case 0: + return IOStatusOk; + case ECONNREFUSED: + return IOStatusConnectionRefused; + case ENETDOWN: + case ENETUNREACH: + case ENETRESET: + case ECONNABORTED: + case ECONNRESET: + case EHOSTUNREACH: + return IOStatusNetworkError; + case ENOENT: + return IOStatusNoSuchFile; + case EPERM: + return IOStatusPermissionDenied; + default: + return IOStatusFailed; + } +} + +/*----------------------------------------------------------------------------- + */ +static IOStatus fdReader(void *handle, void *buf, int size, + int timeout, int *retBytesRead) +{ + int br; + + for (;;) { + if (timeout > 0) { + for (;;) { + int nfds; + struct pollfd read_fds[1]; + read_fds[0].fd = (int) handle; + read_fds[0].events = POLLIN; + read_fds[0].revents = 0; + nfds = poll(read_fds, 1, timeout); + if (nfds < 0) { + switch (errno) { + case EINTR: + continue; + default: + return IOStatusFailed; + } + } else if (nfds == 0) + return IOStatusTimeout; + else /* have data */ + goto doRead; + } + } + + doRead: + br = read((int) handle, buf, size); + if (br <= 0) { + *retBytesRead = 0; + if (br == 0) + return IOStatusNoMoreData; + switch (errno) { + case EINTR: + continue; + case EIO: /* old macdonald had a farm */ + return IOStatusReadError; + default: + return errnoToIOStatus(errno); + } + } + *retBytesRead = br; + return IOStatusOk; + } +} + +/*----------------------------------------------------------------------------- + */ +static IOStatus fdWriter(void *handle, const void *buf, int size) +{ + const char *bp = (const char *) buf; + while (size > 0) { + int bw = write((int) handle, bp, size); + if (bw < 0) { + switch (errno) { + case EINTR: + continue; + case EIO: /* old macdonald had a farm */ + return IOStatusWriteError; + default: + return errnoToIOStatus(errno); + } + } + bp += bw; + size -= bw; + } + return IOStatusOk; +} + +static IOStatus fdCloser(void *handle) +{ + if (close((int) handle) < 0) + return IOStatusFailed; + else + return IOStatusOk; +} + + /**/ +/*----------------------------------------------------------------------------- + */ +static IOStatus dynSockReader(void *handle, void *buf, int size, + int timeout, int *retBytesRead) +{ + int br; + + for (;;) { + if (timeout > 0) { + for (;;) { + int nfds; + struct pollfd read_fds[1]; + read_fds[0].fd = dynSocket_socket((dynSocket *) handle); + read_fds[0].events = POLLIN; + read_fds[0].revents = 0; + nfds = poll(read_fds, 1, timeout); + if (nfds < 0) { + switch (errno) { + case EINTR: + continue; + default: + return IOStatusFailed; + } + } else if (nfds == 0) + return IOStatusTimeout; + else /* have data */ + goto doRead; + } + } + + doRead: + br = dynSocket_read((dynSocket *) handle, buf, size); + if (br <= 0) { + *retBytesRead = 0; + if (br == 0) + return IOStatusNoMoreData; + switch (errno) { + case EINTR: + continue; + case EIO: /* old macdonald had a farm */ + return IOStatusReadError; + default: + return errnoToIOStatus(errno); + } + } + *retBytesRead = br; + return IOStatusOk; + } +} + +/*----------------------------------------------------------------------------- + */ +static IOStatus dynSockWriter(void *handle, const void *buf, int size) +{ + const char *bp = (const char *) buf; + while (size > 0) { + int bw = dynSocket_write((dynSocket *) handle, bp, size); + if (bw < 0) { + switch (errno) { + case EINTR: + continue; + case EIO: /* old macdonald had a farm */ + return IOStatusWriteError; + default: + return errnoToIOStatus(errno); + } + } + bp += bw; + size -= bw; + } + return IOStatusOk; +} + +static IOStatus dynSockCloser(void *handle) +{ + if (dynSocket_close((dynSocket *) handle) == ATG_SOCKET_ERROR) + return IOStatusFailed; + else + return IOStatusOk; +} + +/*----------------------------------------------------------------------------- + * Creates (opens) a new file input stream. + */ +IOStatus createFileInputStream(const char *filename, + InputStream ** retStream) +{ + int fd = open(filename, O_RDONLY); + if (fd < 0) { + IOStatus status; + switch (errno) { + case EIO: + status = IOStatusWriteError; + break; + default: + status = errnoToIOStatus(errno); + break; + } + *retStream = NULL; + return status; + } + *retStream = createInputStream((void *) fd, fdReader, fdCloser, -1); + if (*retStream == NULL) + return IOStatusMemoryExhausted; + else + return IOStatusOk; +} + +/*----------------------------------------------------------------------------- + * Creates (opens) a new file output stream. + */ +IOStatus createFileOutputStream(const char *filename, + OutputStream ** retStream) +{ + int fd = open(filename, O_WRONLY); + if (fd < 0) { + IOStatus status; + switch (errno) { + case EIO: + status = IOStatusWriteError; + break; + default: + status = errnoToIOStatus(errno); + break; + } + *retStream = NULL; + return status; + } + *retStream = createOutputStream((void *) fd, fdWriter, fdCloser, -1); + if (*retStream == NULL) + return IOStatusMemoryExhausted; + else + return IOStatusOk; +} + +/*----------------------------------------------------------------------------- + * Wraps a file descriptor with an input stream + */ +IOStatus createFdInputStream(int fd, int doClose, InputStream ** retStream) +{ + *retStream = createInputStream((void *) fd, fdReader, + (doClose ? fdCloser : NULL), + DEFAULT_BUFFER_SIZE); + if (*retStream == NULL) + return IOStatusMemoryExhausted; + else + return IOStatusOk; +} + +/*----------------------------------------------------------------------------- + * Wraps a file descriptor with an output stream. + */ +IOStatus createFdOutputStream(int fd, int doClose, + OutputStream ** retStream) +{ + *retStream = createOutputStream((void *) fd, fdWriter, fdCloser, + DEFAULT_BUFFER_SIZE); + if (*retStream == NULL) + return IOStatusMemoryExhausted; + else + return IOStatusOk; +} + +/*----------------------------------------------------------------------------- + * Wraps a dynSocket with an input stream + */ +IOStatus createDynSocketInputStream(dynSocket * s, int doClose, + InputStream ** retStream) +{ + *retStream = createInputStream((void *) s, dynSockReader, + (doClose ? dynSockCloser : NULL), + DEFAULT_BUFFER_SIZE); + if (*retStream == NULL) + return IOStatusMemoryExhausted; + else + return IOStatusOk; +} + +/*----------------------------------------------------------------------------- + * Wraps a dynSocket with an output stream. + */ +IOStatus createDynSocketOutputStream(dynSocket * s, int doClose, + OutputStream ** retStream) +{ + *retStream = + createOutputStream((void *) s, dynSockWriter, dynSockCloser, + DEFAULT_BUFFER_SIZE); + if (*retStream == NULL) + return IOStatusMemoryExhausted; + else + return IOStatusOk; +} + +/*----------------------------------------------------------------------------- + * Sleeps for a given number of milliseconds. + */ +/* NOTE: Currently not used so not defined. - Frank Kim, 12/28/99 */ +#if 0 +static void millisecondWait(int ms) +{ + poll(NULL, 0, ms); +} +#endif + +/*----------------------------------------------------------------------------- + * Given a socket address structure, this connects a socket to a server and + * returns input and output streams for it. + * + * FIXME: This function never worked reliably on UNIX hence the reason + * Allan Scott wrote createSocketIOStreamsFromAddressWithBlocking(). + * For now this function is NOT DEFINED so that no one will use it. + * + * Here is what Jim Frost, the author of this function, says on + * 3/2/2001. + * + * I had a lot of trouble getting it to work on Solaris in my tests. + * I literally tried every single technique I could think of to do + * the timeout -- there were several OS bugs that I found in the + * process (usually the connection success would not be reported as + * it should have been). I had thought I'd worked it out, but IIRC + * one or another of you guys had to go back in there because it + * still wasn't working right. It may well have been an issue of + * Solaris version -- I did my tests on the old Solaris/Intel box, + * not on a SPARC box. + * + * I kind of blame this on the really crappy socket implementation + * on SysV/Solaris. + */ +#if 0 +IOStatus createSocketIOStreamsFromAddressWithTimeout(struct sockaddr_in + address, int timeout, + InputStream ** + retInStream, + OutputStream ** + retOutStream) +{ + int address_size = sizeof(struct sockaddr_in); + dynSocket *sock; + IOStatus status, tempStatus; + int sock_flags, temp; +#ifndef FIONBIO + int orig_sock_flags; +#endif /* !SOLARIS */ + + *retInStream = NULL; + *retOutStream = NULL; + sock = dynSocket_new((void *) IO_SOCKET); + if (sock == ATG_INVALID_DYNSOCKET) { + status = IOStatusNoMoreSockets; + return status; + } + + /* if a timeout was specified, set socket up as nonblocking so we can + * determine if it has been too long. + */ + if (timeout > 0) { +#ifdef FIONBIO + + /* if FIONBIO is defined, use it. this is necessary on Solaris where + * sockets do not honor O_NONBLOCK. + */ + sock_flags = 1; + if (ioctl(dynSocket_socket(sock), FIONBIO, &sock_flags) < 0) + return IOStatusFailed; + +#else /* !FIONBIO */ + + /* if FIONBIO is not defined, try to set nonblocking mode using either + * the POSIX O_NONBLOCK or the BSD O_NDELAY. + */ + orig_sock_flags = fcntl(dynSocket_socket(sock), F_GETFL); + if (orig_sock_flags == -1) + return IOStatusFailed; +#ifdef O_NONBLOCK /* POSIX-style nonblocking */ + sock_flags = orig_sock_flags | O_NONBLOCK; +#else /* !O_NONBLOCK */ +#ifdef O_NDELAY /* BSD-style nonblocking */ + sock_flags = orig_sock_flags | O_NDELAY; +#endif /* O_NDELAY */ +#endif /* !O_NONBLOCK */ + if (fcntl(dynSocket_socket(sock), F_SETFL, orig_sock_flags) < 0) + return IOStatusFailed; +#endif /* !FIONBIO */ + } + + /* start the connection request. */ + for (;;) { + if (dynSocket_connect + (sock, (struct sockaddr *) &address, address_size) + == ATG_SOCKET_ERROR) { + switch (errno) { + case EINTR: + continue; + case EALREADY: + case EINPROGRESS: + case EISCONN: + goto waitForConnection; + default: + status = errnoToIOStatus(errno); + temp = dynSocket_close(sock); + return status; + } + } + } + + waitForConnection: + /* if timeout was specified, wait for the connection to finish */ + if (timeout > 0) { + struct pollfd fds[1]; + int result; + + fds[0].fd = dynSocket_socket(sock); + fds[0].events = POLLOUT; + fds[0].revents = 0; + + result = poll(fds, 1, timeout); + if (result < 0) { + switch (errno) { + case EINTR: + goto waitForConnection; + default: + return errnoToIOStatus(errno); + } + } else if (result == 0) { + status = IOStatusTimeout; + temp = dynSocket_close(sock); + return status; + } + + /* check the status of the connect request */ + if (dynSocket_connect + (sock, (struct sockaddr *) &address, address_size) + == ATG_SOCKET_ERROR) { + switch (errno) { + case EISCONN: + break; + default: + return errnoToIOStatus(errno); + } + } + + /* restore socket to blocking mode */ +#ifdef FIONBIO + sock_flags = 0; + if (ioctl(dynSocket_socket(sock), FIONBIO, &sock_flags) < 0) + return IOStatusFailed; +#else /* !FIONBIO */ + fcntl(dynSocket_socket(sock), F_SETFL, orig_sock_flags); +#endif /* !FIONBIO */ + } + + /* wrap the socket with I/O streams */ + status = createDynSocketInputStream(sock, TRUE, retInStream); + if (status != IOStatusOk) { + tempStatus = destroyIOStreams(*retInStream, NULL); + return status; + } + status = createDynSocketOutputStream(sock, TRUE, retOutStream); + if (status != IOStatusOk) { + tempStatus = destroyIOStreams(*retInStream, *retOutStream); + return status; + } + + /* thank you for using AT&T */ + return IOStatusOk; +} +#endif /* #if 0 */ + +/*----------------------------------------------------------------------------- + * Given a socket address structure, this connects a socket to a server and + * returns input and output streams for it. This uses a blocking socket. + */ +IOStatus +createSocketIOStreamsFromAddressWithBlocking(struct sockaddr_in address, + InputStream ** retInStream, + OutputStream ** retOutStream) +{ + int address_size = sizeof(struct sockaddr_in); + dynSocket *sock = ATG_INVALID_DYNSOCKET; + IOStatus status, tempStatus; + *retInStream = NULL; + *retOutStream = NULL; + + /* start the connection request. */ + { + int tries = 0, temp; + + /* try to create a dynamo socket */ + sock = dynSocket_new(NULL); + if (sock == ATG_INVALID_DYNSOCKET) { + status = IOStatusNoMoreSockets; + return status; + } + + while (1) { + + /* try to connect to server specified by address */ + if (dynSocket_connect + (sock, (struct sockaddr *) &address, address_size) + != ATG_SOCKET_ERROR) { + /* successfully connected, break out of the loop */ + break; + } + + /* did not successfully connect to server */ + switch (errno) { + + case EINTR: + + /* The connection attempt was interrupted before any data + arrived by the delivery of a signal. Try to connect again. + Eventually after several tries if it does not connect you + will get an ETIMEDOUT */ + continue; + case ETIMEDOUT: + + /* Timed out while attempting connection. The server may be + too busy to accept new connections. Close this socket and + try to create another one. */ + + status = errnoToIOStatus(errno); + + temp = dynSocket_close(sock); + sock = dynSocket_new(NULL); + if (sock == ATG_INVALID_DYNSOCKET) { + status = IOStatusNoMoreSockets; + return status; + } + break; + default: + status = errnoToIOStatus(errno); + temp = dynSocket_close(sock); + if (status == IOStatusOk) + return IOStatusConnectionRefused; + return status; + } + + tries++; + if (tries == 3) { + temp = dynSocket_close(sock); + if (status == IOStatusOk) + return IOStatusConnectionRefused; + return status; + } + } + } + + /* At this point we have successfully connected to the server with + our socket. Wrap this socket with I/O streams */ + status = createDynSocketInputStream(sock, TRUE, retInStream); + if (status != IOStatusOk) { + tempStatus = destroyIOStreams(*retInStream, NULL); + *retInStream = NULL; + return status; + } + + status = createDynSocketOutputStream(sock, TRUE, retOutStream); + if (status != IOStatusOk) { + tempStatus = destroyIOStreams(*retInStream, *retOutStream); + *retInStream = NULL; + *retOutStream = NULL; + return status; + } + + return IOStatusOk; +} + +#endif /* WIN32 */ diff --git a/mk4/moddynamo/io.h b/mk4/moddynamo/io.h new file mode 100644 index 0000000..a549731 --- /dev/null +++ b/mk4/moddynamo/io.h @@ -0,0 +1,341 @@ +#ifndef _IO_H_ +#define _IO_H_ +/* io.h: + * + * Copyright (C) 1997 Art Technology Group, Inc. + * All Rights Reserved. No use, copying or distribution of this + * work may be made except in accordance with a valid license + * agreement from Art Technology Group. This notice must be + * included on all copies, modifications and derivatives of this + * work. + */ + +#include "system.h" + +/* IOStatus error values. + * + * WARNING: IF YOU CHANGE THIS, YOU MUST ALSO INSERT THE TEXT VERSION OF YOUR + * NEW ERROR(S) IN THE CORRESPONDING MESSAGE TABLE IN sockpool.c. + */ +typedef enum IOStatus +{ + IOStatusOk = 0, + IOStatusFailed, + IOStatusNotImplemented, + IOStatusNoMoreData, + IOStatusReadError, + IOStatusWriteError, + IOStatusBadUrl, + IOStatusUnknownHost, + IOStatusNoMoreSockets, + IOStatusConnectionRefused, + IOStatusNetworkError, + IOStatusMemoryExhausted, + IOStatusNoMoreFiles, + IOStatusNoSuchFile, + IOStatusPermissionDenied, + IOStatusBufferOverflow, + IOStatusProtocolError, + IOStatusProtocolVersionMismatch, + IOStatusTimeout, + IOStatusInitializationFailed, + IOStatusCount +} IOStatus; + +typedef enum IOStreamOption { + IOStreamOptionTimeout = 1 +} IOStreamOption; + +#define IO_SOCKET 1001 + +/* Returns a human-readable string describing the indicated IOStatus value. + */ +const char* getIOStatusString(IOStatus status); + +/* Signature of an input stream reader function. The reader must read as much + * data as is immediately available, but never return before reading something. + */ +typedef IOStatus (*InputStreamReader)(void* handle, void* buf, int size, + int timeout, int* written); + +/* Signature of an input stream closer function. If NULL is passed for one of + * these, it is not closed when the stream is destroyed. + */ +typedef IOStatus (*InputStreamCloser)(void* handle); + +/* Signature of an output stream writer function. The writer must not return + * until all information has been written. + */ +typedef IOStatus (*OutputStreamWriter)(void* handle, const void* buf, int size); + +/* Signature of an output stream closer function. If NULL is passed for one + * of these, it is not closed when the stream is destroyed. + */ +typedef IOStatus (*OutputStreamCloser)(void* handle); + +/* An input stream structure. + */ +typedef struct InputStream +{ + void* handle; + InputStreamReader reader; + InputStreamCloser closer; + char* buffer; + int bufferSize; + int avail; + int readp; + int timeout; /* length of time to wait for input, in ms */ + IOStatus status; /* status of last source read */ +} InputStream; + +/* An output stream structure. + */ +typedef struct OutputStream +{ + void* handle; + OutputStreamWriter writer; + OutputStreamCloser closer; + char* buffer; + int bufferSize; + int writep; + IOStatus status; +} OutputStream; + +/* Creates a buffered input stream. + */ +InputStream* createInputStream(void* handle, + InputStreamReader reader, + InputStreamCloser closer, + int bufferSize); + +/* Fills the buffer of an input stream as much as immediately possible. Waits + * for more input if none is immediately available. This is intended for + * internal use. + */ +IOStatus fillInputStream(InputStream* stream); + +/* Reads some data from an input stream. + */ +IOStatus readSomeFromInputStream(InputStream* stream, void* buf, int size, int* bytesRead); + +/* Reads as much data as is requested from an input stream, if possible. + */ +IOStatus readFromInputStream(InputStream* stream, void* retBuffer, int size, unsigned int *read); + +/* Fast way to read a single character from an input stream. + */ +#define readCharFromInputStream(STREAM, RETCHAR) \ + (((STREAM)->readp == (STREAM)->avail ? fillInputStream(STREAM) : \ + IOStatusOk),\ + ((STREAM)->readp < (STREAM)->avail ? \ + (*(RETCHAR) = (STREAM)->buffer[(STREAM)->readp++]), IOStatusOk : \ + (STREAM)->status)) + +/* Pushes the last char read back onto the input stream. This is + * only valid if the last InputStream operation was readCharFromInputSTream(). + */ +#define pushCharBackOnInputStream(STREAM) \ + ((STREAM)->readp > 0 ? ((STREAM)->readp--, IOStatusOk) : \ + IOStatusBufferOverflow) + +/* Fast way to write a single character to an output stream. + */ +#define writeCharToOutputStream(STREAM, CHAR) \ + ((STREAM)->buffer[(STREAM)->writep++] = (CHAR), \ + ((STREAM)->writep == (STREAM)->bufferSize ? flushOutputStream(STREAM) : \ + IOStatusOk)) + +/* Destroys an input stream, closing its source if a closer function was + * specified. + */ +IOStatus destroyInputStream(InputStream* stream); + +/* Sets the timeout value, in ms, for an input stream. + */ +#define setInputStreamTimeout(STREAM, TIMEOUT) \ + (STREAM)->timeout = (TIMEOUT) + +/* Creates a buffered output stream. + */ +OutputStream* createOutputStream(void* handle, + OutputStreamWriter writer, + OutputStreamCloser closer, + int bufferSize); + +/* Writes data to a buffered output stream. All data will be written before this returns + * if possible. + */ +IOStatus writeToOutputStream(OutputStream* stream, const void* buf, int size); + +/* Prints a C-style string to the output stream. + */ +#define printToOutputStream(STREAM, STRING) \ + writeToOutputStream((STREAM),(STRING),strlen(STRING)) + +/* Flushes buffered data to the output stream. + */ +IOStatus flushOutputStream(OutputStream* stream); + +/* Copies an InputStream to an OutputStream. + */ +IOStatus copyToOutputStream(OutputStream* outStream, InputStream* inStream); + +/* Destroys an output stream, flushing its buffered data and closing its + * destination if a closer function was specified. + */ +IOStatus destroyOutputStream(OutputStream* stream); + +/* Mode values for deferred output streams. + */ +typedef enum DeferredOutputStreamMode { + OutputDeferred, /* All output buffered */ + OutputPassedThrough /* Buffered output flushed, subsequent output passed through */ +} DeferredOutputStreamMode; + +/* Buffer chain structure for deferred output streams. + */ +typedef struct DeferredOutputStreamBuffer +{ + char* buffer; + int bufferSize; + struct DeferredOutputStreamBuffer* next; +} DeferredOutputStreamBuffer; + +/* Handle information for a deferred output stream + */ +typedef struct DeferredOutputStreamHandle +{ + /* Output stream object that holds this handle + */ + OutputStream* myOutputStream; + + /* Output mode for the stream, either deferred or passed-through. + */ + DeferredOutputStreamMode mode; + + /* Raw output stream. + */ + OutputStream* rawOutputStream; + + /* Chain of deferred output buffers + */ + DeferredOutputStreamBuffer* deferredBuffers; + + /* Last deferred buffer in chain. + */ + DeferredOutputStreamBuffer* lastDeferredBuffer; +} DeferredOutputStreamHandle; + +/* Creates a deferred (buffered) output stream. + */ +IOStatus createDeferredOutputStream(OutputStream* rawOutputStream, OutputStream** retStream); + +/* Returns the raw output stream for a deferred output stream. + */ +#define getRawOutputStreamForDeferred(OUTSTREAM) \ + ((DeferredOutputStreamHandle*)outStream->handle)->rawOutputStream + +/* Changes the deferred output stream mode between buffered and passed-through. + */ +IOStatus setDeferredOutputMode(OutputStream* outStream, DeferredOutputStreamMode mode); + +/* Writes all deferred output to the raw output stream. + */ +IOStatus writeDeferredOutput(OutputStream* outStream); + +/* Creates (opens) a new file input stream. + */ +IOStatus createFileInputStream(const char* filename, InputStream** retStream); + +/* Creates (opens) a new file output stream. + */ +IOStatus createFileOutputStream(const char* filename, OutputStream** retStream); + +/* Connects a socket to a server and returns input and output streams for it. + */ +#define createSocketIOStreams(HOSTNAME, PORT, RETINSTREAM, RETOUTSTREAM) \ + createSocketIOStreamsWithTimeout((HOSTNAME), (PORT), 0, (RETINSTREAM), (RETOUTSTREAM)) + + +#ifdef WIN32 +/* Connects a socket to a server and returns input and output streams for it, + * or fails if a connection cannot be established in a given number of + * milliseconds. + * + * FIXME: Because createSocketIOStreamsFromAddressWithTimeout() is + * only supported on WIN32, this function can only be supported on + * WIN32 + */ +IOStatus createSocketIOStreamsWithTimeout(const char* hostname, int port, + int timeout, + InputStream** retStream, + OutputStream** outStream); +#endif + +/* Creates a new pair of I/O streams around a socket that is connected + * at the indicated address. + */ +#define createSocketIOStreamsFromAddress(ADDR, RETINSTREAM, RETOUTSTREAM) \ + createSocketIOStreamsFromAddressWithTimeout((ADDR), 0, (RETINSTREAM), (RETOUTSTREAM)) + +#ifdef WIN32 +/* FIXME: This function never worked reliably on UNIX hence the reason + * it is only defined on WIN32. + */ +IOStatus +createSocketIOStreamsFromAddressWithTimeout(struct sockaddr_in address, + int timeout, + InputStream** retInStream, + OutputStream** retOutStream); +#endif + +#ifndef WIN32 /* assume it's UNIX */ +IOStatus createSocketIOStreamsFromAddressWithBlocking(struct sockaddr_in address, + InputStream** retInStream, + OutputStream** retOutStream); +#endif + +/* Given a host name and port number, this returns an internet address. + */ +IOStatus getSocketAddress(const char* hostname, int port, struct sockaddr_in* retAddress); + +#ifdef WIN32 +/* Wraps a generic I/O handle with an input stream. + */ +IOStatus createHandleInputStream(HANDLE handle, int doClose, InputStream** retStream); + +/* Wraps a generic I/O handle with an output stream. + */ +IOStatus createHandleOutputStream(HANDLE handle, int doClose, OutputStream** retStream); + +/* Wraps a SOCKET with an input stream. + */ +IOStatus createSocketInputStream(SOCKET sock, int doClose, InputStream** retStream); + +/* Wraps a SOCKET with an output stream. + */ +IOStatus createSocketOutputStream(SOCKET sock, int doClose, OutputStream** retStream); +#endif /* WIN32 */ + +#ifdef UNIX +/* Wraps a file descriptor with an input stream + */ +IOStatus createFdInputStream(int fd, int doClose, InputStream** retStream); + +/* Wraps a file descriptor with an output stream. + */ +IOStatus createFdOutputStream(int fd, int doClose, OutputStream** retStream); +#endif /* UNIX */ + +/* Destroy Input/Output stream pair + */ +IOStatus destroyIOStreams(InputStream* pInStream,OutputStream* pOutStream); + +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +#endif /* !_IO_H_ */ diff --git a/mk4/moddynamo/pageroute.c b/mk4/moddynamo/pageroute.c new file mode 100644 index 0000000..5af3b5f --- /dev/null +++ b/mk4/moddynamo/pageroute.c @@ -0,0 +1,320 @@ +/* pageroute.c + * + * manages routing of pages where a consistent dynamo target is required. + * + * jim frost 11.10.97 + * + * Copyright (C) 1997 Art Technology Group, Inc. + * All Rights Reserved. No use, copying or distribution of this + * work may be made except in accordance with a valid license + * agreement from Art Technology Group. This notice must be + * included on all copies, modifications and derivatives of this + * work. + */ + +#include +#include +#include +#include "pageroute.h" + +#ifdef SOLARIS2 +char *strdup(const char *); /* morons forgot to include it in string.h */ +#endif /* SOLARIS2 */ + +/* An entry in the statically routed page table. + */ +typedef struct RoutedPage { + /* the URL or prefix portion of the URL of a routed page. + */ + char *url; + + /* the length of the URL string to compare if this is a prefix URL. + */ + int prefixLen; + + /* next page in table + */ + struct RoutedPage *next; +} RoutedPage; + +/* The statically routed page table. + */ +static RoutedPage *PageTable; + +#if 1 /* debug code */ +#include +void debugOut(const char *message) +{ + FILE *fp; + + fp = fopen("d:\\debug.log", "a"); + if (fp == NULL) + return; + fwrite(message, 1, strlen(message), fp); + fclose(fp); +} + +void debugOutInt(int value) +{ + char buf[32]; + sprintf(buf, "%d", value); + debugOut(buf); +} +#endif /* debug code */ + +/*---------------------------------------------------------------------------- + * Appends a page or list of pages to the page list. + */ +static void appendPage(RoutedPage * newPage) +{ + if (PageTable == NULL) + PageTable = newPage; + else { + RoutedPage *rp; + + for (rp = PageTable; rp->next != NULL; rp = rp->next) + /* EMPTY */ ; + rp->next = newPage; + } +} + +/*---------------------------------------------------------------------------- + * Looks for a trailing asterisk and sets the prefix length if it finds one. + */ +static void setPrefixValue(RoutedPage * rp) +{ + int len = strlen(rp->url); + if ((len > 0) && (rp->url[len - 1] == '*')) + rp->prefixLen = len - 1; +} + +/*---------------------------------------------------------------------------- + * Adds another statically routed page to the table. + */ +int addStaticallyRoutedPage(const char *pageUrl) +{ + RoutedPage *rp = (RoutedPage *) calloc(1, sizeof(RoutedPage)); + if (rp == NULL) + return 0; + rp->url = strdup(pageUrl); + if (rp->url == NULL) { + free(rp); + return 0; + } + setPrefixValue(rp); + appendPage(rp); + return 1; +} + +/*---------------------------------------------------------------------------- + * Adds a list of URLs (comma-delimited) to the statically routed page table. + */ +int addStaticallyRoutedPageList(const char *pageList) +{ + RoutedPage *newPages = NULL; + RoutedPage *lastPage = NULL; + const char *start = pageList; + const char *end; + + while ((start != NULL) && (*start != '\0')) { + char *url; + RoutedPage *rp; + + /* skip leading comma delimiters + */ + while (*start == ',') + start++; + + /* look for trailing comma delimiter + */ + end = strchr(start, ','); + if (end == NULL) { + url = strdup(start); + if (url == NULL) + goto cleanupAndFail; + } else { + int len = end - start; + url = (char *) malloc(len + 1); + if (url == NULL) + goto cleanupAndFail; + strncpy(url, start, len); + url[len] = '\0'; + } + + rp = (RoutedPage *) calloc(1, sizeof(RoutedPage)); + if (rp == NULL) { + free(url); + goto cleanupAndFail; + } + rp->url = url; + setPrefixValue(rp); + + /* append to the new page list + */ + if (lastPage == NULL) + newPages = lastPage = rp; + else { + lastPage->next = rp; + lastPage = rp; + } + start = end; + } + + /* concatenate the new page and routed page lists. + */ + if (newPages != NULL) + appendPage(newPages); + + return 1; + + cleanupAndFail: + /* clean up anything in the new page list + */ + while (newPages != NULL) { + RoutedPage *oldrp = newPages; + newPages = newPages->next; + if (oldrp->url != NULL) + free(oldrp->url); + free(oldrp); + } + return 0; +} + +/*---------------------------------------------------------------------------- + * Clears the statically routed page table. + */ +void clearStaticallyPageTable(void) +{ + while (PageTable != NULL) { + RoutedPage *oldrp = PageTable; + PageTable = PageTable->next; + if (oldrp->url != NULL) + free(oldrp->url); + free(oldrp); + } +} + +/*---------------------------------------------------------------------------- + * Computes a hash value for a string using a 32-bit CRC. + */ +int getStringHashValue(const char *string) +{ + unsigned int crc32_table[256] = { /* lookup table */ + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, + 0x706AF48F, + 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, + 0x97D2D988, + 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, + 0x6AB020F2, + 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, + 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, + 0x63066CD9, + 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, + 0xA2677172, + 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, + 0x42B2986C, + 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, + 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, + 0x56B3C423, + 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, + 0xB10BE924, + 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, + 0x01DB7106, + 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, + 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, + 0x086D3D2D, + 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, + 0xF262004E, + 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, + 0x12B7E950, + 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, + 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, + 0x3DD895D7, + 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, + 0xDA60B8D0, + 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, + 0x270241AA, + 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, + 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, + 0x2EB40D81, + 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, + 0x74B1D29A, + 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, + 0x94643B84, + 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, + 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, + 0x806567CB, + 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, + 0x67DD4ACC, + 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, + 0xA1D1937E, + 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, + 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, + 0xA867DF55, + 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, + 0x5268E236, + 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, + 0xB2BD0B28, + 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, + 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, + 0xEB0E363F, + 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, + 0x0CB61B38, + 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, + 0xF1D4E242, + 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, + 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, + 0xF862AE69, + 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, + 0x3903B3C2, + 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, + 0xD9D65ADC, + 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, + 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, + 0xCDD70693, + 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, + 0x2A6F2B94, + 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D + }; + + unsigned int crc; /* CRC value */ + int i; + + crc = 0xFFFFFFFF; /* preconditioning sets non zero value */ + /* loop through the file and calculate CRC */ + for (i = 0; string[i] != '\0'; i++) { + int v = (crc ^ string[i]) & 0x000000FF; + crc = ((crc >> 8) & 0x00FFFFFF) ^ crc32_table[v]; + } + + return ~crc; /* postconditioning */ +} + +/*---------------------------------------------------------------------------- + * Returns true if the URL is found in the statically routed page table. + */ +int isStaticallyRoutedPage(const char *url) +{ + RoutedPage *rp; + + for (rp = PageTable; rp != NULL; rp = rp->next) { + if (rp->prefixLen > 0) { /* compare URL prefix rather than a whole URL */ + if (!strncmp(rp->url, url, rp->prefixLen)) + return 1; + } else { + if (!strcmp(rp->url, url)) + return 1; + } + } + return 0; +} diff --git a/mk4/moddynamo/pageroute.h b/mk4/moddynamo/pageroute.h new file mode 100644 index 0000000..991fd30 --- /dev/null +++ b/mk4/moddynamo/pageroute.h @@ -0,0 +1,31 @@ +/* pageroute.h: + * + * jim frost 11.10.97 + * + * Copyright (C) 1997 Art Technology Group, Inc. + * All Rights Reserved. No use, copying or distribution of this + * work may be made except in accordance with a valid license + * agreement from Art Technology Group. This notice must be + * included on all copies, modifications and derivatives of this + * work. + */ + +/* Adds another statically routed page to the table. + */ +int addStaticallyRoutedPage(const char* pageUrl); + +/* Adds a list of URLs (comma-delimited) to the statically routed page table. + */ +int addStaticallyRoutedPageList(const char* pageList); + +/* Clears the statically routed page table. + */ +void clearStaticallyRoutedPages(void); + +/* Computes a hash value for a string using a 32-bit CRC. + */ +int getStringHashValue(const char* url); + +/* Returns true if the URL is found in the statically routed page table. + */ +int isStaticallyRoutedPage(const char* url); diff --git a/mk4/moddynamo/rwLocks.h b/mk4/moddynamo/rwLocks.h new file mode 100644 index 0000000..45c96c7 --- /dev/null +++ b/mk4/moddynamo/rwLocks.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 1997 Art Technology Group, Inc. + * All Rights Reserved. No use, copying or distribution of this + * work may be made except in accordance with a valid license + * agreement from Art Technology Group. This notice must be + * included on all copies, modifications and derivatives of this + * work. + * + * Art Technology Group (ATG) MAKES NO REPRESENTATIONS OR WARRANTIES + * ABOUT THE SUITABILITY OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. ATG SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, + * MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. + * + * "Dynamo" is a trademark of Art Technology Group, Inc. + */ + +/* + rwLocks.h - interface for read-write locks + */ + + + +#ifndef _RWLOCKS_H_ +#define _RWLOCKS_H_ + + +#ifdef _DRP_MTHREAD + +#include "threadabstr.h" + + +/*typedef struct _RWLock RWLock; */ + + +/* RWLock: read-write lock object */ +struct _RWLock { + Thread_CSKey critKey; /* critical-section key for this read-write + lock (see threadabstr.h) */ + unsigned int readLocks; /* number of read locks currently held on + this rwlock */ + unsigned int writeLocks; /* number of write locks currently held on + this rwLock (should be 0 or 1) */ + unsigned int writersWaiting; /* number of entities that are currently + trying to obtain a write lock */ +}; + + +/* default timeout values for obtaining read and write locks */ +#define kRWL_DefaultReadTimeout 50 +#define kRWL_DefaultWriteTimeout 100 + + +int initializeRWLock(RWLock * oLock); +void discardRWLock(RWLock * oLock); + +int getReadLock(RWLock * iLock, unsigned long iTimeout); +int releaseReadLock(RWLock * iLock); +int getWriteLock(RWLock * iLock, unsigned long iTimeout); +int releaseWriteLock(RWLock * iLock); + +#else /* i.e. ndef _DRP_MTHREAD */ + +/* define functions to empty macros */ +#define initializeRWLock(l) 0 +#define discardRWLock(l) 0 +#define getReadLock(l,t) 0 +#define releaseReadLock(l) 0 +#define getWriteLock(l,t) 0 +#define releaseWriteLock(l) 0 + +#endif + +#endif diff --git a/mk4/moddynamo/sockerrs.c b/mk4/moddynamo/sockerrs.c new file mode 100644 index 0000000..71d00c6 --- /dev/null +++ b/mk4/moddynamo/sockerrs.c @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2001 Art Technology Group, Inc. + * All Rights Reserved. No use, copying or distribution of this + * work may be made except in accordance with a valid license + * agreement from Art Technology Group. This notice must be + * included on all copies, modifications and derivatives of this + * work. + * + * Art Technology Group (ATG) MAKES NO REPRESENTATIONS OR WARRANTIES + * ABOUT THE SUITABILITY OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. ATG SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, + * MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. + * + * "Dynamo" is a trademark of Art Technology Group, Inc. + */ + +/* + * sockerrs.c -- provides a method for getting human-readable strings from + * error codes (errno on Unix, WSAGetLastError on NT) + */ + +#ifdef WIN32 +/* NT */ +#include +#else +/* UNIXEN */ +#include +#endif + +#include "sockerrs.h" + +/* + * Return the appropriate message string for the error + * pErrno is errno on Unix, the return from WSAGetLastError() on NT + */ +const char *getMessageStringForSocketError(int pErrno) +{ +#if (defined (WIN32)) + char *message; + switch (pErrno) { + case WSAEINTR: + message = "A blocking operation was cancelled (WASEINTR)"; + break; + case WSAEBADF: + message = "Bad file number (WSAEBADF)"; + break; + case WSAEACCES: + message = + "Permission to access socket forbidden by its access permissions (WSAEACCES)"; + break; + case WSAEFAULT: + message = + "Invalid pointer address specified in function call (WSAEFAULT)"; + break; + case WSAEINVAL: + message = "Invalid argument passed to a function (WSAEINVAL)"; + break; + case WSAEMFILE: + message = "Too many open sockets (WSAEMFILE)"; + break; + case WSAEWOULDBLOCK: + message = "Resources temporarily unavailable (WSAEWOULDBLOCK)"; + break; + case WSAEINPROGRESS: + message = "Blocking operation now in progress (WSAEINPROGRESS)"; + break; + case WSAEALREADY: + message = + "Operation already in progress on a non-binding socket (WSAEALREADY)"; + break; + case WSAENOTSOCK: + message = + "Socket operation attempted on a non-socket (WSAENOTSOCK)"; + break; + case WSAEDESTADDRREQ: + message = "Destination address required (WSAEDESTADDRREQ)"; + break; + case WSAEMSGSIZE: + message = "Message too long (WSAEMSGSIZE)"; + break; + case WSAEPROTOTYPE: + message = "Protocol wrong type for socket (WSAEPROTOTYPE)"; + break; + case WSAENOPROTOOPT: + message = + "Unknown, invalid, or unsupported protocol option or level was specified (WSAENOPROTOOPT)"; + break; + case WSAEPROTONOSUPPORT: + message = "Protocol not supported (WSAEPROTONOSUPPORT)"; + break; + case WSAESOCKTNOSUPPORT: + message = + "Socket type not supported in the address family (WSAESOCKTNOSUPPORT)"; + break; + case WSAEOPNOTSUPP: + message = "Operation not supported on socket (WSAEOPNOTSUPP)"; + break; + case WSAEPFNOSUPPORT: + message = "Protocol family not supported (WSAEPFNOSUPPORT)"; + break; + case WSAEAFNOSUPPORT: + message = + "Address family not supported by protocol family (WSAEAFNOSUPPORT)"; + break; + case WSAEADDRINUSE: + message = "Address already in use (WSAEADDRINUSE)"; + break; + case WSAEADDRNOTAVAIL: + message = "Cannot assign requested address (WSAEADDRNOTAVAIL)"; + break; + case WSAENETDOWN: + message = "Network is down (WSAENETDOWN)"; + break; + case WSAENETUNREACH: + message = "Network is unreachable (WSAENETUNREACH)"; + break; + case WSAENETRESET: + message = "Network dropped connection on reset (WSAENETRESET)"; + break; + case WSAECONNABORTED: + message = "Software caused connection abort (WSAECONNABORTED)"; + break; + case WSAECONNRESET: + message = "Connection reset by peer (WSAECONNRESET)"; + break; + case WSAENOBUFS: + message = "No buffer space available (WSAENOBUFS)"; + break; + case WSAEISCONN: + message = "Socket is already connected (WSAEISCONN)"; + break; + case WSAENOTCONN: + message = "Socket is not connected (WSAENOTCONN)"; + break; + case WSAESHUTDOWN: + message = "Cannot send after socket shutdown (WSAESHUTDOWN)"; + break; + case WSAETOOMANYREFS: + message = "Too many references, cannot splice (WSAETOOMANYREFS)"; + break; + case WSAETIMEDOUT: + message = "Connection timed out (WSAETIMEDOUT)"; + break; + case WSAECONNREFUSED: + message = "Connection refused (WSAECONNREFUSED)"; + break; + case WSAELOOP: + message = "Too many levles of symbolic links (WSAELOOP)"; + break; + case WSAENAMETOOLONG: + message = "File name is too long (WSAENAMETOOLONG)"; + break; + case WSAEHOSTDOWN: + message = "Host is down (WSAEHOSTDOWN)"; + break; + case WSAEHOSTUNREACH: + message = "No route to host (WSAEHOSTUNREACH)"; + break; + case WSAENOTEMPTY: + message = "Directory not empty (WSAENOTEMPTY)"; + break; + case WSAEPROCLIM: + message = "Too many processes (WSAEPROCLIM)"; + break; + case WSAEUSERS: + message = "Too many users (WSAEUSERS)"; + break; + case WSAEDQUOT: + message = "Disc quota exceeded (WSAEDQUOT)"; + break; + case WSAESTALE: + message = "Stale NFS file handle (WSAESTALE)"; + break; + case WSAEREMOTE: + message = "Too many levels of remote in path (WSAEREMOTE)"; + break; + case WSAEDISCON: + message = "Graceful shutdown in progress (WSAEDISCON)"; + break; + case WSASYSNOTREADY: + message = "Network subsystem is unavailable (WSASYSNOTREADY)"; + break; + case WSAVERNOTSUPPORTED: + message = "Winsock.dll version out of range (WSAVERNOTSUPPORTED)"; + break; + case WSANOTINITIALISED: + message = + "Successful WSASTARTUP not yet performed (WSANOTINITIALISED)"; + break; + case 10109: /* case WSATYPE_NOT_FOUND */ + message = "Class type not found (WSATYPE_NOT_FOUND)"; + break; + case WSAHOST_NOT_FOUND: + message = "Host not found (WSA_HOST_NOT_FOUND)"; + break; + case WSATRY_AGAIN: + message = "Non-authoritative host not found (WSATRY_AGAIN)"; + break; + case WSANO_RECOVERY: + message = "Non-recoverable error (WSANO_RECOVERY)"; + break; + case WSANO_DATA: + message = + "Valid name, no data record or requested name (WSANO_DATA)"; + break; + default: + message = "WSA error not recognized"; + } + return (message); +#else + if (pErrno == 0) { + const char *message = "Uninterpretable socket error occurred."; + return message; + } else { + return (strerror(pErrno)); + } +#endif +} diff --git a/mk4/moddynamo/sockerrs.h b/mk4/moddynamo/sockerrs.h new file mode 100644 index 0000000..eb55756 --- /dev/null +++ b/mk4/moddynamo/sockerrs.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2001 Art Technology Group, Inc. + * All Rights Reserved. No use, copying or distribution of this + * work may be made except in accordance with a valid license + * agreement from Art Technology Group. This notice must be + * included on all copies, modifications and derivatives of this + * work. + * + * Art Technology Group (ATG) MAKES NO REPRESENTATIONS OR WARRANTIES + * ABOUT THE SUITABILITY OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. ATG SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, + * MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. + * + * "Dynamo" is a trademark of Art Technology Group, Inc. + */ + +/* + sockerrs.h -- provide string messages for socket errors + */ + +#ifndef _SOCKERRS_H +#define _SOCKERRS_H + +/* PROTYPES */ +const char * getMessageStringForSocketError(int pErrno); + +#endif /* _SOCKERRS_H */ diff --git a/mk4/moddynamo/system.h b/mk4/moddynamo/system.h new file mode 100644 index 0000000..637bbc2 --- /dev/null +++ b/mk4/moddynamo/system.h @@ -0,0 +1,52 @@ +#ifndef _ATG_SYSTEM_H_ +#define _ATG_SYSTEM_H_ +/* system.h: + * + * system-specific includes and definitions. + * + * Copyright (C) 1997 Art Technology Group, Inc. + * All Rights Reserved. No use, copying or distribution of this + * work may be made except in accordance with a valid license + * agreement from Art Technology Group. This notice must be + * included on all copies, modifications and derivatives of this + * work. + */ +#ifdef WIN32 +#include +#include +#include + +#else /* assume it is UNIX */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(SOLARIS) || defined(SOLARIS2) +/* we need to pick up FIONBIO from ioctl.h, which is only defined in BSD + * compatibility mode in Solaris. + */ +#define BSD_COMP +#endif /* SOLARIS */ + +#if defined(AIX) || defined(_AIX) || defined(LINUX) || defined(_HPUX) || defined(OPENBSD) +#include +#endif /* AIX */ + +#include + +#define stricmp strcasecmp +#define strnicmp strncasecmp + +#ifndef LINUX +char* strdup(const char*); +#endif + +#endif /* WIN32 */ + +#endif /* !_ATG_SYSTEM_H_ */ diff --git a/mk4/moddynamo/threadabstr.c b/mk4/moddynamo/threadabstr.c new file mode 100644 index 0000000..b86ae7d --- /dev/null +++ b/mk4/moddynamo/threadabstr.c @@ -0,0 +1,94 @@ +#pragma ident "$Header: /san01/cvs/ashpool/csrc/moddynamo/Attic/threadabstr.c,v 1.2 2004/03/18 15:04:15 aleigh Exp $" + +/* Copyright (c) 1994, 2001 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH + * The copyright notice above does not evidence any + * actual or intended publication of such source code. + * + * Disclosure, copying, distribution, or transmission of of + * this code without express permission is prohibited. + */ + +/* + * threadabstr.c : evolution thread interface for dynamo CM PURE LIQUID EVIL + * Alex Leigh (aleigh@tessier.com) 2001 + */ + +#include +#include + +#include "threadabstr.h" + +/* + * thread_startNewThread(kThread_defaultStackSize, cmldrpThreadFunction, + * (kThread_argType) pBlock); if (gCMLDRPThread == kThread_InvalidThread) { + * gCMLDRPBlock.logFunction(gCMLDRPBlock.logShellData, kLog_Error, + * kLogMessage_CannotStartCMLDRPThread, NULL, NULL); returnValue = -1; } + */ + +Thread_t thread_startNewThread(int StackSize, void *start_func(void *), + void *arg) +{ + pthread_t tid; + + pthread_create(&tid, NULL, start_func, arg); + + return tid; +} + +/* TODO: This function does not support the timeout value */ +int getReadLock(RWLock * lock, int timeout) +{ + return pthread_rwlock_rdlock(lock); +} + +/* TODO: This function does not support the timeout value */ +int getWriteLock(RWLock * lock, int timeout) +{ + return pthread_rwlock_wrlock(lock); +} + +int releaseWriteLock(RWLock * lock) +{ + return pthread_rwlock_unlock(lock); +} + +int releaseReadLock(RWLock * lock) +{ + return pthread_rwlock_unlock(lock); +} + + +/* if (initializeRWLock(&gLoadDataLock)) { */ +int initializeRWLock(RWLock * lock) +{ + return pthread_rwlock_init(lock, NULL); +} + +int thread_return(int retval) +{ + pthread_exit(NULL); +} + +/* TODO: Unsafe assumptions about timespec and tm */ +int thread_sleep(int ms) +{ + pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; + pthread_cond_t cond = PTHREAD_COND_INITIALIZER; + struct timeval now; + struct timespec then; + int deltams; + +/* logFmsg(0,"thread_sleep: called [tid: 0x%x] [ms: %d]", pthread_self(), ms); */ + gettimeofday(&now, NULL); + + deltams = (now.tv_usec / 1000) + ms; + + then.tv_sec = now.tv_sec + (deltams / 1000); + then.tv_nsec = (deltams % 1000) * 1000000; + + pthread_cond_timedwait(&cond, &mut, (struct timespec *) &then); + + return 0; +} diff --git a/mk4/moddynamo/threadabstr.h b/mk4/moddynamo/threadabstr.h new file mode 100644 index 0000000..8d644a7 --- /dev/null +++ b/mk4/moddynamo/threadabstr.h @@ -0,0 +1,28 @@ +/* Copyright (c) 1994, 2001 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH + * The copyright notice above does not evidence any + * actual or intended publication of such source code. + * + * Disclosure, copying, distribution, or transmission of of + * this code without express permission is prohibited. + */ + +#ifndef _TA_THREADABSTR_H +#define _TA_THREADABSTR_H + +#pragma ident "$Header: /san01/cvs/ashpool/csrc/moddynamo/Attic/threadabstr.h,v 1.1 2003/12/12 15:08:04 aleigh Exp $" + +#include + +#define Thread_CSKey pthread_mutex_t * +#define kThread_returnType void * +#define kThread_argType void * +#define Thread_t pthread_t +#define kThread_defaultStackSize 4096 /* !! */ +#define kThread_InvalidThread NULL + +typedef pthread_rwlock_t RWLock; + +#endif + diff --git a/mk4/modexample/CVS/Entries b/mk4/modexample/CVS/Entries new file mode 100644 index 0000000..b86e922 --- /dev/null +++ b/mk4/modexample/CVS/Entries @@ -0,0 +1,5 @@ +/Makefile/1.2/Mon Apr 26 14:28:52 2004//Tmk4_mod6_rc2 +/auth.c/1.2/Thu Mar 18 15:04:15 2004//Tmk4_mod6_rc2 +/example.c/1.2/Thu Mar 18 15:04:15 2004//Tmk4_mod6_rc2 +/hello.c/1.2/Thu Mar 18 15:04:15 2004//Tmk4_mod6_rc2 +D diff --git a/mk4/modexample/CVS/Repository b/mk4/modexample/CVS/Repository new file mode 100644 index 0000000..2717d10 --- /dev/null +++ b/mk4/modexample/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/modexample diff --git a/mk4/modexample/CVS/Root b/mk4/modexample/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/modexample/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/modexample/CVS/Tag b/mk4/modexample/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/modexample/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/modexample/Makefile b/mk4/modexample/Makefile new file mode 100644 index 0000000..c33ded2 --- /dev/null +++ b/mk4/modexample/Makefile @@ -0,0 +1,23 @@ +# $Header: /san01/cvs/ashpool/csrc/modexample/Attic/Makefile,v 1.2 2004/04/26 14:28:52 aleigh Exp $ + +include ../continuity/lib/env.mk + +SRCS=example.c +OBJS=example.o + +CFLAGS=-I../continuity/include $(CONT_FLAGS) + +world: install + +example.so: $(OBJS) + $(LD_SHARECMD) -o example.so $(OBJS) +clean: + $(RM) $(OBJS) *~ example.so + +install: example.so + cp example.so ../continuity/lib + + +depend: + makedepend $(DEPFLAGS) -I ../continuity/include $(SRCS) + diff --git a/mk4/modexample/auth.c b/mk4/modexample/auth.c new file mode 100644 index 0000000..8f7bbe1 --- /dev/null +++ b/mk4/modexample/auth.c @@ -0,0 +1,59 @@ +#include +#include + +int check_user(const char *username, const char *password); +int require_authentication(httpTtrans * t, lstTset * opt); + +/* + * Check to see if the username and password are valid. + * Return 1 if they are, 0 if they are not + */ +int check_user(const char *username, const char *password) +{ + if (strcmp(username, "admin") == 0 && strcmp(password, "pencil") == 0) + return 1; + return 0; +} + +int require_authentication(httpTtrans * t, lstTset * opt) +{ + char *authorization = lstFset_get(t->req_hdrs, "authorization"); + char b64decode[64]; + int ret; + char *u = NULL, *p = NULL; + char *st_p; + + authorization = lstFset_get(t->req_hdrs, "authorization"); + + if (authorization != NULL) { + bzero(b64decode, 64); + + ret = + b64Fdecode(authorization + 6, (unsigned char *) b64decode, + sizeof(b64decode)); + b64decode[ret] = '\0'; + + u = strtok_r(b64decode, ":", &st_p); + p = strtok_r(NULL, ":", &st_p); + + if (u != NULL && p != NULL) { + ret = check_user(u, p); + + if (ret == 1) { + lstFset_add(t->vars, "auth-type", "basic"); + lstFset_add(t->vars, "auth-user", u); + return STATUS_PROCEED; + } + } + } + + /* require authentication */ + httpFset_status(t, HTTP_UNAUTHORIZED, NULL); + lstFset_add(t->res_hdrs, "WWW-authenticate", + "basic realm=\"Members Area\""); + + httpFstart_response(t); + httpFwrite(t, "Authorization required.", 24); + + return STATUS_EXIT; +} diff --git a/mk4/modexample/example.c b/mk4/modexample/example.c new file mode 100644 index 0000000..e18efb1 --- /dev/null +++ b/mk4/modexample/example.c @@ -0,0 +1,16 @@ +#include +#include + +int redirector(httpTtrans * t, lstTset * opt); + +int redirector(httpTtrans * t, lstTset * opt) +{ + const char *target; + + target = httpFquery_val(t, "target"); + + if (target == NULL) + return STATUS_PROCEED; + + return httpFredirect(t, target); +} diff --git a/mk4/modexample/hello.c b/mk4/modexample/hello.c new file mode 100644 index 0000000..b220845 --- /dev/null +++ b/mk4/modexample/hello.c @@ -0,0 +1,19 @@ +#include +#include + +int my_handler(httpTtrans * t, lstTset * opts); + +int my_handler(httpTtrans * t, lstTset * opts) +{ + const char *hello = "Hello World\n"; + + assert(t != NULL); + + httpFset_status(t, 200, NULL); + httpFstart_response(t); + + httpFwrite(t, hello, strlen(hello)); + + /* we have served the request, so exit the pipeline */ + return STATUS_EXIT; +} diff --git a/mk4/modharmony/CVS/Entries b/mk4/modharmony/CVS/Entries new file mode 100644 index 0000000..8ef189f --- /dev/null +++ b/mk4/modharmony/CVS/Entries @@ -0,0 +1,5 @@ +/Makefile.in/1.1/Fri May 7 20:22:30 2004//Tmk4_mod6_rc2 +/harmony.c/1.4/Mon May 10 15:38:03 2004//Tmk4_mod6_rc2 +/harmony.h/1.2/Fri May 7 20:38:46 2004//Tmk4_mod6_rc2 +/hproto.h/1.1/Mon May 10 15:38:03 2004//Tmk4_mod6_rc2 +D diff --git a/mk4/modharmony/CVS/Repository b/mk4/modharmony/CVS/Repository new file mode 100644 index 0000000..dd8ab09 --- /dev/null +++ b/mk4/modharmony/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/modharmony diff --git a/mk4/modharmony/CVS/Root b/mk4/modharmony/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/modharmony/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/modharmony/CVS/Tag b/mk4/modharmony/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/modharmony/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/modharmony/Makefile.in b/mk4/modharmony/Makefile.in new file mode 100644 index 0000000..16674fa --- /dev/null +++ b/mk4/modharmony/Makefile.in @@ -0,0 +1,21 @@ +# $Header: /san01/cvs/ashpool/csrc/modharmony/Attic/Makefile.in,v 1.1 2004/05/07 20:22:30 aleigh Exp $ + +include ../continuity/lib/env.mk + +SRCS=harmony.c +OBJS=harmony.o + +CFLAGS=-I../continuity/include $(CONT_FLAGS) + +world: install + +harmony.so: $(OBJS) + $(LD_SHARECMD) -o harmony.so $(OBJS) +clean: + $(RM) $(OBJS) *~ harmony.so + +install: harmony.so + (rm -f ../continuity/lib/harmony.so ; cp harmony.so ../continuity/lib) + cp harmony.h ../continuity/include +depend: + $(MAKEDEPEND) -I../continuity/include $(DEPFLAGS) $(SRCS) diff --git a/mk4/modharmony/harmony.c b/mk4/modharmony/harmony.c new file mode 100644 index 0000000..7f4fdaf --- /dev/null +++ b/mk4/modharmony/harmony.c @@ -0,0 +1,140 @@ +/* $Id: harmony.c,v 1.4 2004/05/10 15:38:03 aleigh Exp $ */ + +/* + * Copyright (c) 1994, 2001 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Use, disclosure, copying, distribution, or transmission of this code without + * express permission is prohibited. + */ + +#include "harmony.h" +#include "hproto.h" + +#define MCAST_GROUP "225.0.0.37" + +static int harGbcast_socket; +static int harGcid; +static unsigned int harGhostid; + +static int harFhandle_pkt(const char *data, size_t data_len); +static void harFlisten_thread(void); +static uint32_t harFframe_crc(const harTframe_hdr *hdr); + +#define MSGBUFSIZE 1024 + +static uint32_t harFframe_crc(const harTframe_hdr *hdr) { + return htonl(crcFcrc32((const unsigned char *)hdr,sizeof(uint32_t)*4)); +} + +static void harFlisten_thread(void) +{ + struct sockaddr_in addr; + char msgbuf[MSGBUFSIZE]; + int nbytes,addrlen; + + logFmsg(3,"Started."); + + while (1) { + addrlen=sizeof(addr); + + if ((nbytes=recvfrom(harGbcast_socket,msgbuf,MSGBUFSIZE,0, + NULL,0)) < 0) { + logFmsg(2,"recvfrom() failed. [e: %d]", errno); + } + harFhandle_pkt(msgbuf,nbytes); + } +} + +static int harFhandle_pkt(const char *data, size_t data_len) { + harTframe_hdr *frame; + + frame=(harTframe_hdr *)data; + + if(data_lenframe_crc) { + logFmsg(3,"CRC does not match; discarding corrupt packet."); + return 0; + } + + logFmsg(3,"rcv'd packet %u -> %u", frame->from_addr, frame->rcpt_addr); + + if(frame->from_addr==harGhostid) { + logFmsg(3,"discarding echo"); + return 0; + } + + if(frame->rcpt_addr!=harGhostid && frame->rcpt_addr!=HARMONY_BROADCAST_ADDR) { + logFmsg(3,"discarding 3rd party unicast packet"); + return 0; + } + + logFmsg(3,"Received unicast packet for me."); + + return 0; +} + +static int harFadvertise(void) +{ + harTframe_hdr pkt; + ssize_t ret; + + pkt.from_addr=harGhostid; + pkt.rcpt_addr=HARMONY_BROADCAST_ADDR; + pkt.msg_type=1; + pkt.data_len=0; + pkt.frame_crc=harFframe_crc(&pkt); + + if(ret=netFudp_send(harGbcast_socket,&pkt,sizeof(pkt), + harGcid,utlFstr_to_ip(MCAST_GROUP))==-1) { + logFmsg(3,"netFudp_send() returns error. [e: %d]", errno); + } else { + logFmsg(3,"cluster advertisement sent. %d", ret); + } + + return 0; +} + +int harFinit(void *p, lstTset *opt) +{ + const char *constellation; + pthread_t listen_thread; + + logFmsg(0, "mod/harmony: Clustering Engine"); + logFmsg(0, "Copyright (c) 2004, Alex Leigh"); + + constellation=lstFset_get(opt,"constellation"); + + if(constellation==NULL) { + logFmsg(2,"Constellation not configured. Aborting."); + exit(1); + } + + harGcid=atoi(constellation); + harGhostid=utlFgethostid(); + + logFmsg(0,"Rigging cluster constellation for id %u.", harGcid); + logFmsg(0,"Assumed cluster address %u.",harGhostid); + + harGbcast_socket=netFipv4_mcast_create(harGcid,MCAST_GROUP); + + if(harGbcast_socket<0) { + logFmsg(2,"Unable to create network transport. [e: %d]", errno); + exit(1); + } + + logFmsg(0,"Transport created."); + + harFadvertise(); + + pthread_create(&listen_thread,NULL,harFlisten_thread,NULL); + + return STATUS_OK; +} diff --git a/mk4/modharmony/harmony.h b/mk4/modharmony/harmony.h new file mode 100644 index 0000000..f2e8464 --- /dev/null +++ b/mk4/modharmony/harmony.h @@ -0,0 +1,8 @@ +#ifndef _HARMONY_H +#define _HARMONY_H + +#include + +int harFinit(void *p, lstTset *opt); + +#endif diff --git a/mk4/modharmony/hproto.h b/mk4/modharmony/hproto.h new file mode 100644 index 0000000..3e2fd57 --- /dev/null +++ b/mk4/modharmony/hproto.h @@ -0,0 +1,15 @@ +#ifndef HARMONY_PROTO_H +#define HARMONY_PROTO_H + +struct harSframe_hdr { + uint32_t from_addr; + uint32_t rcpt_addr; + uint32_t msg_type; + uint32_t data_len; + uint32_t frame_crc; +}; +typedef struct harSframe_hdr harTframe_hdr; + +#define HARMONY_BROADCAST_ADDR 0 + +#endif diff --git a/mk4/modhtaccess/CVS/Entries b/mk4/modhtaccess/CVS/Entries new file mode 100644 index 0000000..392e83c --- /dev/null +++ b/mk4/modhtaccess/CVS/Entries @@ -0,0 +1,3 @@ +/Makefile/1.3/Fri May 14 17:30:52 2004//Tmk4_mod6_rc2 +D/include//// +D/src//// diff --git a/mk4/modhtaccess/CVS/Repository b/mk4/modhtaccess/CVS/Repository new file mode 100644 index 0000000..7023115 --- /dev/null +++ b/mk4/modhtaccess/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/modhtaccess diff --git a/mk4/modhtaccess/CVS/Root b/mk4/modhtaccess/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/modhtaccess/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/modhtaccess/CVS/Tag b/mk4/modhtaccess/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/modhtaccess/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/modhtaccess/Makefile b/mk4/modhtaccess/Makefile new file mode 100644 index 0000000..c8bbe4e --- /dev/null +++ b/mk4/modhtaccess/Makefile @@ -0,0 +1,15 @@ +CONTINUITY = ../continuity + +INCLUDES += -Iinclude +#INCLUDES += -I../lib/aura/include + +LOCAL_CFLAGS += + +#STATIC_LIBS += $(AURA)/libaura.a + +SOURCES = src/htaccess.c src/htaccess_parser.c \ + src/htaccess_basic_auth.c src/htaccess_engine.c + +TARGET = htaccess + +include $(CONTINUITY)/lib/build.mk diff --git a/mk4/modhtaccess/include/CVS/Entries b/mk4/modhtaccess/include/CVS/Entries new file mode 100644 index 0000000..c0728c3 --- /dev/null +++ b/mk4/modhtaccess/include/CVS/Entries @@ -0,0 +1,5 @@ +/htaccess_basic_auth.h/1.1/Fri May 14 06:07:47 2004//Tmk4_mod6_rc2 +/htaccess_engine.h/1.1/Fri May 14 06:07:47 2004//Tmk4_mod6_rc2 +/htaccess_parser.h/1.1/Fri May 14 06:07:47 2004//Tmk4_mod6_rc2 +/iauthentication_scheme.h/1.1/Fri May 14 06:07:47 2004//Tmk4_mod6_rc2 +D diff --git a/mk4/modhtaccess/include/CVS/Repository b/mk4/modhtaccess/include/CVS/Repository new file mode 100644 index 0000000..818ab1f --- /dev/null +++ b/mk4/modhtaccess/include/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/modhtaccess/include diff --git a/mk4/modhtaccess/include/CVS/Root b/mk4/modhtaccess/include/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/modhtaccess/include/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/modhtaccess/include/CVS/Tag b/mk4/modhtaccess/include/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/modhtaccess/include/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/modhtaccess/include/htaccess_basic_auth.h b/mk4/modhtaccess/include/htaccess_basic_auth.h new file mode 100644 index 0000000..bd61a64 --- /dev/null +++ b/mk4/modhtaccess/include/htaccess_basic_auth.h @@ -0,0 +1,10 @@ + +#ifndef __HTACCESS_BASIC_AUTH_H__ +#define __HTACCESS_BASIC_AUTH_H__ + +typedef struct s_HtaccessBasicAuth HtaccessBasicAuth; + +HtaccessBasicAuth * htaccess_basic_auth_new (void); +void htaccess_basic_auth_destroy (void *ptr); + +#endif diff --git a/mk4/modhtaccess/include/htaccess_engine.h b/mk4/modhtaccess/include/htaccess_engine.h new file mode 100644 index 0000000..8f7f6f5 --- /dev/null +++ b/mk4/modhtaccess/include/htaccess_engine.h @@ -0,0 +1,14 @@ + +#ifndef __HTACCESS_ENGINE_H__ +#define __HTACCESS_ENGINE_H__ + +#include "http.h" + +typedef struct s_HtaccessEngine HtaccessEngine; + +HtaccessEngine * htaccess_engine_new (httpTtrans *t); +void htaccess_engine_destroy (void *ptr); + +int htaccess_engine_process (HtaccessEngine *instance); + +#endif diff --git a/mk4/modhtaccess/include/htaccess_parser.h b/mk4/modhtaccess/include/htaccess_parser.h new file mode 100644 index 0000000..96e0229 --- /dev/null +++ b/mk4/modhtaccess/include/htaccess_parser.h @@ -0,0 +1,16 @@ + +#ifndef __HTACCESS_PARSER_H__ +#define __HTACCESS_PARSER_H__ + +#include "mecha.h" + +typedef struct s_HtaccessParser HtaccessParser; + +HtaccessParser * htaccess_parser_new (const char *filename); +void htaccess_parser_destroy (void *ptr); + +bool htaccess_parser_parse (HtaccessParser *instance); + +const char * htaccess_parser_get_value (HtaccessParser *instance, const char *key); + +#endif diff --git a/mk4/modhtaccess/include/iauthentication_scheme.h b/mk4/modhtaccess/include/iauthentication_scheme.h new file mode 100644 index 0000000..e4aed35 --- /dev/null +++ b/mk4/modhtaccess/include/iauthentication_scheme.h @@ -0,0 +1,33 @@ +#ifndef __IAUTHENTICATION_SCHEME_H__ +#define __IAUTHENTICATION_SCHEME_H__ + +#include "htaccess_parser.h" + +#include "http.h" + +#include "mecha.h" + +typedef struct IAuthenticationScheme_s IAuthenticationScheme; + +typedef void (*IAuthenticationSchemeDestroy) (IAuthenticationScheme *instance); + +enum AuthenticateResult_e +{ + AuthenticateResultReject, + AuthenticateResultAccept +}; + +typedef enum AuthenticateResult_e AuthenticateResult; + +struct IAuthenticationScheme_s +{ + bool (*read_config) (IAuthenticationScheme *instance, HtaccessParser *config); + + AuthenticateResult (*auth_user) (IAuthenticationScheme *instance, + httpTtrans *trans, const char *authData); + + IAuthenticationSchemeDestroy destroy; +}; + + +#endif diff --git a/mk4/modhtaccess/src/CVS/Entries b/mk4/modhtaccess/src/CVS/Entries new file mode 100644 index 0000000..371e934 --- /dev/null +++ b/mk4/modhtaccess/src/CVS/Entries @@ -0,0 +1,5 @@ +/htaccess.c/1.1/Fri May 14 06:07:47 2004//Tmk4_mod6_rc2 +/htaccess_basic_auth.c/1.2/Fri May 14 17:31:35 2004//Tmk4_mod6_rc2 +/htaccess_engine.c/1.2/Fri May 14 16:51:26 2004//Tmk4_mod6_rc2 +/htaccess_parser.c/1.1/Fri May 14 06:07:47 2004//Tmk4_mod6_rc2 +D diff --git a/mk4/modhtaccess/src/CVS/Repository b/mk4/modhtaccess/src/CVS/Repository new file mode 100644 index 0000000..28f550a --- /dev/null +++ b/mk4/modhtaccess/src/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/modhtaccess/src diff --git a/mk4/modhtaccess/src/CVS/Root b/mk4/modhtaccess/src/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/modhtaccess/src/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/modhtaccess/src/CVS/Tag b/mk4/modhtaccess/src/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/modhtaccess/src/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/modhtaccess/src/htaccess.c b/mk4/modhtaccess/src/htaccess.c new file mode 100644 index 0000000..90e0598 --- /dev/null +++ b/mk4/modhtaccess/src/htaccess.c @@ -0,0 +1,20 @@ + +#include "mecha.h" +#include "http.h" + +#include "htaccess_engine.h" + +int htaccess_handler (httpTtrans *t, lstTset *opts); + +int +htaccess_handler (httpTtrans *t, MECHA_UNUSED_ARGUMENT lstTset *opts) +{ + HtaccessEngine *engine = htaccess_engine_new (t); + int retVal; + + retVal = htaccess_engine_process (engine); + + htaccess_engine_destroy (engine); + + return (retVal); +} diff --git a/mk4/modhtaccess/src/htaccess_basic_auth.c b/mk4/modhtaccess/src/htaccess_basic_auth.c new file mode 100644 index 0000000..78f0a88 --- /dev/null +++ b/mk4/modhtaccess/src/htaccess_basic_auth.c @@ -0,0 +1,253 @@ + +#include + +#include "htaccess_basic_auth.h" + +#include "iauthentication_scheme.h" + +#include "mecha.h" +#include "http.h" + +#ifdef SOLARIS +#include +#endif + +enum RequireType_e +{ + RequireTypeValidUser, + RequireTypeUser, + RequireTypeGroup, + RequireTypeNone +}; + +typedef enum RequireType_e RequireType; + +struct s_HtaccessBasicAuth +{ + IAuthenticationScheme authInterface; + + const char *realm; + const char *userFile; + const char *groupFile; + RequireType requireType; + + char *requestedUser; + char *requestedPassword; +}; + + +static bool htaccess_basic_auth_read_config (IAuthenticationScheme *inst, HtaccessParser *config); +static AuthenticateResult htaccess_basic_auth_auth_user (IAuthenticationScheme *inst, httpTtrans *trans, const char *data); +static bool htaccess_basic_auth_parse_data (HtaccessBasicAuth *instance, const char *data); + +HtaccessBasicAuth * +htaccess_basic_auth_new (void) +{ + HtaccessBasicAuth *instance = (HtaccessBasicAuth *) malloc (sizeof (HtaccessBasicAuth)); + + instance->authInterface.read_config = htaccess_basic_auth_read_config; + instance->authInterface.auth_user = htaccess_basic_auth_auth_user; + instance->authInterface.destroy = (IAuthenticationSchemeDestroy) htaccess_basic_auth_destroy; + + instance->realm = NULL; + instance->userFile = NULL; + instance->groupFile = NULL; + instance->requireType = RequireTypeNone; + + instance->requestedUser = NULL; + instance->requestedPassword = NULL; + + return (instance); +} + +void +htaccess_basic_auth_destroy (void *ptr) +{ + HtaccessBasicAuth *instance = (HtaccessBasicAuth *) ptr; + + if (instance->requestedUser != NULL) + { + free (instance->requestedUser); + } + + if (instance->requestedPassword != NULL) + { + free (instance->requestedPassword); + } + + free (instance); +} + +static bool +htaccess_basic_auth_read_config (IAuthenticationScheme *inst, HtaccessParser *config) +{ + HtaccessBasicAuth *instance = (HtaccessBasicAuth *) inst; + const char *requireField; + + requireField = htaccess_parser_get_value (config, "Require"); + + if (requireField == NULL) + { + instance->requireType = RequireTypeNone; + } + else if (strncmp (requireField, "valid-user", 10) == 0) + { + instance->requireType = RequireTypeValidUser; + } + else if (strncmp (requireField, "user ", 5) == 0) + { + instance->requireType = RequireTypeUser; + + logFmsg (CONT_LOG_ERROR, "mod/htaccess: 'Require user' unsupported."); + + return (false); + } + else if (strncmp (requireField, "group ", 5) == 0) + { + instance->requireType = RequireTypeGroup; + + logFmsg (CONT_LOG_ERROR, "mod/htaccess: 'Require group' unsupported."); + + return (false); + } + + instance->userFile = htaccess_parser_get_value (config, "AuthUserFile"); + instance->groupFile = htaccess_parser_get_value (config, "AuthGroupFile"); + + instance->realm = htaccess_parser_get_value (config, "AuthName"); + + return (true); +} + +static bool +htaccess_basic_auth_parse_data (HtaccessBasicAuth *instance, const char *data) +{ + char decodeBuf[1024]; + char *user, *pass; + char *st_p; + int ret; + + ret = b64Fdecode (data, (unsigned char *) decodeBuf, sizeof (decodeBuf)); + + decodeBuf[ret] = 0; + + user = strtok_r (decodeBuf, ":", &st_p); + pass = strtok_r (NULL, ":", &st_p); + + if (user != NULL && pass != NULL) + { + instance->requestedUser = strFcopy (user); + instance->requestedPassword = strFcopy (pass); + + return (true); + } + else + { + return (false); + } +} + +static AuthenticateResult +htaccess_basic_auth_auth_user (IAuthenticationScheme *inst, + httpTtrans *trans, const char *data) +{ + HtaccessBasicAuth *instance = (HtaccessBasicAuth *) inst; + FILE *fp; + char line[1024]; + bool retSuccess = false; + + if (htaccess_basic_auth_parse_data (instance, data) == false) + { + if (instance->requireType == RequireTypeNone) + { + return (AuthenticateResultAccept); + } + else + { + return (AuthenticateResultReject); + } + } + + fp = fopen (instance->userFile, "r"); + + if (fp == NULL) + { + if (instance->requireType == RequireTypeNone) + { + logFmsg (CONT_LOG_WARN, "mod/htaccess: Could not open UserFile: %s. Authentication succeeding.", + instance->userFile); + + return (AuthenticateResultAccept); + } + else + { + logFmsg (CONT_LOG_WARN, "mod/htaccess: Could not open UserFile: %s. Authentication failing.", + instance->userFile); + + return (AuthenticateResultReject); + } + } + + while (fgets (line, sizeof (line), fp) != NULL) + { + char *tokCtx; + char *curUser, *curPassword; + + strFstrip_crlf (line, strlen (line)); + + curUser = strtok_r (line, ":", &tokCtx); + + curPassword = strtok_r (NULL, ":", &tokCtx); + + if (curPassword == NULL) + { + continue; + } + + /* if we found the user */ + if (strcmp (instance->requestedUser, curUser) == 0) + { + char *encryptedPass; + + encryptedPass = crypt (instance->requestedPassword, curPassword); + + if (strcmp (encryptedPass, curPassword) == 0) + { + retSuccess = true; + } + else + { +#if HTACCESS_DEBUG + logFmsg (CONT_LOG_DEBUG, "mod/htaccess: File password %s does not match encrypted: %s", + curPassword, encryptedPass); +#endif + + retSuccess = false; + } + + break; + } + } + + fclose (fp); + + if (retSuccess == true) + { + lstFset_update (trans->vars, "auth-type", "basic"); + lstFset_update (trans->vars, "auth-user", instance->requestedUser); + + return (AuthenticateResultAccept); + } + else + { + if (instance->requireType == RequireTypeNone) + { + return (AuthenticateResultAccept); + } + else + { + return (AuthenticateResultReject); + } + } +} + diff --git a/mk4/modhtaccess/src/htaccess_engine.c b/mk4/modhtaccess/src/htaccess_engine.c new file mode 100644 index 0000000..9896b32 --- /dev/null +++ b/mk4/modhtaccess/src/htaccess_engine.c @@ -0,0 +1,260 @@ + +#include + +#include "mecha.h" + +#include "htaccess_engine.h" + +#include "htaccess_basic_auth.h" + +#include "htaccess_parser.h" +#include "iauthentication_scheme.h" + +#define HTACCESS_FILENAME ".htaccess" + +struct s_HtaccessEngine +{ + httpTtrans *trans; + + HtaccessParser *parser; + + IAuthenticationScheme *authScheme; + + dynTstring *requestAuthType; + dynTstring *requestAuthData; + + char *htaccessFilename; +}; + +HtaccessEngine * +htaccess_engine_new (httpTtrans *t) +{ + HtaccessEngine *instance = (HtaccessEngine *) malloc (sizeof (HtaccessEngine)); + + instance->trans = t; + + instance->parser = NULL; + + instance->requestAuthType = NULL; + instance->requestAuthData = NULL; + + instance->htaccessFilename = NULL; + + instance->authScheme = NULL; + + return (instance); +} + +void +htaccess_engine_destroy (void *ptr) +{ + HtaccessEngine *instance = (HtaccessEngine *) ptr; + + if (instance->parser != NULL) + { + htaccess_parser_destroy (instance->parser); + } + + if (instance->requestAuthType != NULL) + { + dynFfree (instance->requestAuthType); + } + + if (instance->requestAuthData != NULL) + { + dynFfree (instance->requestAuthData); + } + + if (instance->htaccessFilename != NULL) + { + free (instance->htaccessFilename); + } + + if (instance->authScheme != NULL) + { + instance->authScheme->destroy (instance->authScheme); + } + + free (instance); +} + +static bool +htaccess_engine_find_file (HtaccessEngine *instance) +{ + const lstTfield *path = lstFset_get_field (instance->trans->vars, "path", 4); + char pathBuf[1024]; + char htfileBuf[1024]; + char *slashPtr; + + strncpy (pathBuf, lstFfield_value (path), sizeof (pathBuf)); + + while ((slashPtr = rindex (pathBuf, '/')) != NULL) + { + struct stat sbuf; + + *slashPtr = 0; + + snprintf (htfileBuf, sizeof (htfileBuf), "%s/%s", pathBuf, HTACCESS_FILENAME); + + if (stat (htfileBuf, &sbuf) != -1) + { + if (S_ISREG (sbuf.st_mode)) + { + instance->htaccessFilename = strFcopy (htfileBuf); + + instance->parser = htaccess_parser_new (htfileBuf); + + if (htaccess_parser_parse (instance->parser) == true) + { + return (true); + } + else + { + return (false); + } + } + } + } + + return (false); +} + +static void +htaccess_engine_populate_auth_data (HtaccessEngine *instance) +{ + char *spacePtr; + const lstTfield *auth = lstFset_get_field (instance->trans->req_hdrs, + "authorization", 13); + + if (auth == NULL) + { + return; + } + + spacePtr = index (lstFfield_value (auth), ' '); + + if (spacePtr == NULL) + { + return; + } + + { + int wordLen = spacePtr - lstFfield_value (auth); + + instance->requestAuthType = dynFinit(); + + dynFappend (instance->requestAuthType, lstFfield_value (auth), wordLen); + } + + instance->requestAuthData = dynFinit(); + + spacePtr++; + + dynFsappend (instance->requestAuthData, spacePtr); +} + +static int +htaccess_engine_send_unauthorized_response (HtaccessEngine *instance) +{ + char authResp[1024]; + const char *authRealm; + const char *authType; + + httpFset_status (instance->trans, HTTP_UNAUTHORIZED, NULL); + + authRealm = htaccess_parser_get_value (instance->parser, "AuthName"); + authType = htaccess_parser_get_value (instance->parser, "AuthType"); + + snprintf (authResp, sizeof (authResp), "%s realm=\"%s\"", + authType, authRealm); + + lstFset_update (instance->trans->res_hdrs, "WWW-Authenticate", authResp); + + httpFstart_response (instance->trans); + + httpFwrite (instance->trans, "Authorization required.", 23); + + return (STATUS_EXIT); +} + +static IAuthenticationScheme * +htaccess_engine_get_auth_scheme (HtaccessEngine *instance) +{ + if (strcmp (htaccess_parser_get_value (instance->parser, "AuthType"), "Basic") == 0) + { + return ((IAuthenticationScheme *) htaccess_basic_auth_new()); + } + + /* + * we only support the Basic authentication type right now because we're + * lazy. + * + * -eric@5stops.com 3.14.2004 + */ + return (NULL); +} + +int +htaccess_engine_process (HtaccessEngine *instance) +{ + AuthenticateResult authResult = AuthenticateResultReject; + const char *authType; + + if (htaccess_engine_find_file (instance) == false) + { + return (STATUS_PROCEED); + } + + htaccess_engine_populate_auth_data (instance); + + authType = htaccess_parser_get_value (instance->parser, "AuthType"); + + if (authType == NULL) + { + logFmsg (CONT_LOG_WARN, "mod/htaccess: Could not find an AuthType. Ignoring %s.", + instance->htaccessFilename); + + return (STATUS_PROCEED); + } + + if (instance->requestAuthType == NULL || instance->requestAuthData == NULL) + { + return (htaccess_engine_send_unauthorized_response (instance)); + } + + if (strcmp (authType, dynFgetstr (instance->requestAuthType)) != 0) + { + logFmsg (CONT_LOG_ERROR, "mod/htaccess: The requested authentication type \"%s\" did not match the expected type \"%s\".", + dynFgetstr (instance->requestAuthType), authType); + + return (htaccess_engine_send_unauthorized_response (instance)); + } + + instance->authScheme = htaccess_engine_get_auth_scheme (instance); + + if (instance->authScheme == NULL) + { + logFmsg (CONT_LOG_ERROR, "mod/htaccess: %s: The authentication type \"%s\" is not supported.", + instance->htaccessFilename, authType); + + return (STATUS_PROCEED); + } + + if (instance->authScheme->read_config (instance->authScheme, instance->parser) == false) + { + logFmsg (CONT_LOG_WARN, "mod/htaccess: %s: An error occured while reading config data.", + instance->htaccessFilename); + + return (STATUS_PROCEED); + } + + authResult = instance->authScheme->auth_user (instance->authScheme, instance->trans, + dynFgetstr (instance->requestAuthData)); + + if (authResult == AuthenticateResultReject) + { + return (htaccess_engine_send_unauthorized_response (instance)); + } + + return (STATUS_PROCEED); +} diff --git a/mk4/modhtaccess/src/htaccess_parser.c b/mk4/modhtaccess/src/htaccess_parser.c new file mode 100644 index 0000000..a8db88b --- /dev/null +++ b/mk4/modhtaccess/src/htaccess_parser.c @@ -0,0 +1,96 @@ + +#include + +#include "mecha.h" + +#include "htaccess_parser.h" + +struct s_HtaccessParser +{ + char *filename; + hshTvoid_list *data; +}; + +HtaccessParser * +htaccess_parser_new (const char *file) +{ + HtaccessParser *instance = (HtaccessParser *) malloc (sizeof (HtaccessParser)); + + instance->filename = strFcopy (file); + + instance->data = hshFvoid_init (free); + + return (instance); +} + +void +htaccess_parser_destroy (void *ptr) +{ + HtaccessParser *instance = (HtaccessParser *) ptr; + + free (instance->filename); + + hshFvoid_destroy (instance->data); + + free (instance); +} + +const char * +htaccess_parser_get_value (HtaccessParser *instance, const char *key) +{ + return ((const char *) hshFvoid_find (instance->data, key)); +} + +bool +htaccess_parser_parse (HtaccessParser *instance) +{ + FILE *fp; + char line[1024]; + + fp = fopen (instance->filename, "r"); + + if (fp == NULL) + { + return (false); + } + + while (fgets (line, sizeof (line), fp) != NULL) + { + char *firstSpace; + + strFstrip_crlf (line, strlen (line)); + + firstSpace = index (line, ' '); + + if (firstSpace == NULL) + { + logFmsg (CONT_LOG_WARN, "htaccess: unknown line: %s", line); + } + + *firstSpace = 0; + + firstSpace++; + + if (*firstSpace == '"') + { + firstSpace++; + } + + { + int secondLength = strlen (firstSpace); + + + + if (firstSpace[secondLength - 1] == '"') + { + firstSpace[secondLength - 1] = 0; + } + } + + hshFvoid_add (instance->data, line, strFcopy (firstSpace)); + } + + fclose (fp); + + return (true); +} diff --git a/mk4/modhttp/CVS/Entries b/mk4/modhttp/CVS/Entries new file mode 100644 index 0000000..a44f713 --- /dev/null +++ b/mk4/modhttp/CVS/Entries @@ -0,0 +1,5 @@ +/Makefile.in/1.3/Wed May 12 13:50:37 2004//Tmk4_mod6_rc2 +/http.c/1.49/Sun May 23 21:35:50 2004//Tmk4_mod6_rc2 +/http.h/1.18/Fri Apr 2 16:17:18 2004//Tmk4_mod6_rc2 +/http.xml/1.2/Wed May 12 14:29:44 2004//Tmk4_mod6_rc2 +D diff --git a/mk4/modhttp/CVS/Repository b/mk4/modhttp/CVS/Repository new file mode 100644 index 0000000..f62db10 --- /dev/null +++ b/mk4/modhttp/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/modhttp diff --git a/mk4/modhttp/CVS/Root b/mk4/modhttp/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/modhttp/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/modhttp/CVS/Tag b/mk4/modhttp/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/modhttp/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/modhttp/Makefile.in b/mk4/modhttp/Makefile.in new file mode 100644 index 0000000..4ab769f --- /dev/null +++ b/mk4/modhttp/Makefile.in @@ -0,0 +1,24 @@ +# $Header: /san01/cvs/ashpool/csrc/modhttp/Attic/Makefile.in,v 1.3 2004/05/12 13:50:37 aleigh Exp $ + +include ../continuity/lib/env.mk + +SRCS=http.c +OBJS=http.o + +CFLAGS=-I../continuity/include $(CONT_FLAGS) + +world: install + +http.so: $(OBJS) + $(LD_SHARECMD) -o http.so $(OBJS) +clean: + $(RM) $(OBJS) *~ http.so + +install: http.so http.h + (rm -f ../continuity/lib/http.so ; cp http.so ../continuity/lib) + cp http.h ../continuity/include + cp http.xml ../continuity/lib + +depend: + $(MAKEDEPEND) $(DEPFLAGS) -I ../continuity/include $(SRCS) + diff --git a/mk4/modhttp/http.c b/mk4/modhttp/http.c new file mode 100644 index 0000000..5221638 --- /dev/null +++ b/mk4/modhttp/http.c @@ -0,0 +1,1030 @@ +/* + * $Header: /cvsroot/csrc/modhttp/http.c,v 1.18 2003/12/02 14:49:22 aleigh + * Exp $ + */ + +/* + * Copyright (c) 1994, 2004 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Disclosure, copying, distribution, or transmission of this code without + * express permission is prohibited. + */ + +#include "../continuity/include/csys.h" +#include "../continuity/mecha/dyn.h" +#include "../continuity/mecha/net.h" +#include "../continuity/include/continuity.h" +#include "../continuity/mecha/lst.h" +#include "http.h" + +#define EAGAIN_TRYCOUNT 100 +#define EAGAIN_WAIT 250 + +static void httpFat_end(char **sPtr, char **ePtr); +static int httpFparse_multiquery(httpTtrans * t, char *start, char *end, + lstTset * set); + +pthread_key_t httpKtrans_key = 0; +int natr_id; +int srvc_id; +int mime_id; +int wlog_id; + +static void httpFcleanup(httpTtrans * t) +{ + httpFthread_settrans(NULL); + t->conn->io_close(t->conn); + tlsFclean(); + httpFtrans_free(t); +} + +/* + * This function is called by the dispatcher when a new connection is + * received on the listen socket. This overall controls the flow of the HTTP + * transaction, from start to finish, and dictates which module classes are + * going to be called in order to service the transaction. + */ +void httpFhandler(void *p, MECHA_UNUSED_ARGUMENT const lstTset * arg) +{ + netTconn *conn = (netTconn *) p; + httpTtrans *trans; + int ret; + + trans = httpFtrans_alloc(); + + trans->sd = conn->sd; + trans->cli_ipv4_addr = conn->cli_ipv4_addr; + trans->conn = p; + + /* + * Set the new transaction structure to be associated with the thread, so + * that httpFthread_gettrans will work later. + */ + httpFthread_settrans(trans); + + ret = httpFparse(trans); + + if (ret == STATUS_ERROR) { + /* There was something totally wrong with the query so we are going + * to return a 400. Since there is no valid information in the transaction + * the pipelines are not executed, so 400 requests do not log. + */ + httpFset_status(trans, 400, NULL); + httpFstart_response(trans); + httpFerror_page(trans, NULL); + httpFcleanup(trans); + return; + } + + ret = dlFpipeline_exec(trans, natr_id, NULL, NULL); + + if (trans->started == REQ_UNSTARTED) { + + ret = dlFpipeline_exec(trans, mime_id, NULL, NULL); + } + if (trans->started == REQ_UNSTARTED) { + + ret = + dlFpipeline_exec(trans, srvc_id, "type", + lstFset_get(trans->res_hdrs, "Content-Type")); + } + if (ret != STATUS_EXIT) { + httpFset_status(trans, 500, NULL); + httpFstart_response(trans); + httpFerror_page(trans, NULL); + } + if (trans->started == REQ_STARTED) + httpFsend_response(trans); + + dlFpipeline_exec(trans, wlog_id, NULL, NULL); + + httpFcleanup(trans); + + return; +} + +int httpFinit(MECHA_UNUSED_ARGUMENT void *p, + MECHA_UNUSED_ARGUMENT const lstTset * opts) +{ + if (pthread_key_create(&httpKtrans_key, NULL) != 0) { + logFmsg(2, "Unable to create httpKtrans_key. [e: %d]", + errno); + abort(); + } + logFmsg(0, "mod/http: Hyper-Text Transfer Protocol Engine"); + logFmsg(0, "Copyright (c) 2002, Alex Leigh"); + + natr_id = dlFpipeline_getid("http_natr"); + mime_id = dlFpipeline_getid("http_mime"); + srvc_id = dlFpipeline_getid("http_srvc"); + wlog_id = dlFpipeline_getid("http_log"); + + return STATUS_OK; +} + +int httpFthread_settrans(httpTtrans * t) +{ + return pthread_setspecific(httpKtrans_key, t); +} + +httpTtrans *httpFthread_gettrans(void) +{ + return (httpTtrans *) pthread_getspecific(httpKtrans_key); +} + +httpTtrans *httpFtrans_alloc(void) +{ + httpTtrans *t; + + t = (httpTtrans *) malloc(sizeof(httpTtrans)); + + t->req_hdrs = lstFset_create("request headers"); + t->res_hdrs = lstFset_create("response headers"); + t->vars = lstFset_create("vars"); + t->response = dynFinit(); + t->reader = netFreader_init(); + t->query = NULL; + + t->res_code = 200; + t->res_reason = "OK"; + t->started = REQ_UNSTARTED; + t->client_read = 0; + + memFclear(&t->statb, sizeof(t->statb)); + + assert(t->req_hdrs != NULL); + assert(t->res_hdrs != NULL); + assert(t->vars != NULL); + + return t; +} + +void httpFtrans_free(httpTtrans * t) +{ + assert(t != NULL); + assert(t->req_hdrs != NULL); + assert(t->res_hdrs != NULL); + assert(t->vars != NULL); + assert(t->conn != NULL); + + netFconn_free(t->conn); + + lstFset_free(t->req_hdrs); + lstFset_free(t->res_hdrs); + lstFset_free(t->vars); + lstFset_free(t->query); + + dynFfree(t->response); + netFreader_free(t->reader); + + free(t); +} + +int httpFerror_page(httpTtrans * t, const char *msg) +{ + char buf[1024]; + + assert(t != NULL); + + httpFsend_response(t); + + snprintf(buf, sizeof(buf), + "ERROR: No functions handled this request.\n\n%s", + conFget_build()); + + httpFwrite(t, buf, strlen(buf)); + + if (msg != NULL) { + httpFwrite(t, msg, strlen(msg)); + } + return STATUS_PROCEED; +} + +void httpFset_status(httpTtrans * t, int status, const char *reason) +{ + assert(t != NULL); + + t->res_code = status; + if (reason != NULL) { + t->res_reason = reason; + } +} + +/* + * This just outputs the headers. It's useful if your module has served the + * HTTP response line, or you are returning a non HTTP response and you want + * to send the entities. + */ + +int httpFsend_resp_headers(httpTtrans * t) +{ + int i; + char buf[128]; + size_t length = 0; + + assert(t != NULL); + assert(t->res_hdrs != NULL); + + for (i = 0; i < t->res_hdrs->size; i++) { + if (t->res_hdrs->fields[i].name != NULL + && t->res_hdrs->fields[i].value != NULL) { + snprintf(buf, sizeof(buf), "%s: %s\r\n", + t->res_hdrs->fields[i].name, + t->res_hdrs->fields[i].value); + length += + t->res_hdrs->fields[i].n_len + + t->res_hdrs->fields[i].v_len + 4; + + buf[0] = toupper(buf[0]); + + httpFwrite(t, buf, length); + } + } + return 0; +} + +/* + * this function is used in case we have never called httpFwrite() by the + * time the request is finished, or if we don't intend to call it. + */ +void httpFsend_response(httpTtrans * t) +{ + netFconn_write(t->conn, t->response->str, t->response->strlen); + + t->started = REQ_HEADERSENT; +} + +void httpFstart_response(httpTtrans * t) +{ + int i; + + assert(t != NULL); + assert(t->res_hdrs != NULL); + + /* we only need to send these once */ + if (t->started == REQ_STARTED || t->started == REQ_HEADERSENT) { + return; + } + + t->started = REQ_STARTED; + + switch (t->res_code) { + case HTTP_OK: + dynFappend(t->response, "HTTP/1.0 200 OK\r\n", 17); + break; + case HTTP_CREATED: + dynFappend(t->response, "HTTP/1.0 201 CREATED\r\n", 22); + break; + case HTTP_ACCEPTED: + dynFappend(t->response, "HTTP/1.0 202 ACCEPTED\r\n", 23); + break; + case HTTP_PARTIAL: + dynFappend(t->response, "HTTP/1.0 203 PARTIAL\r\n", 22); + break; + case HTTP_NORESPONSE: + dynFappend(t->response, "HTTP/1.0 204 NO RESPONSE\r\n", 26); + break; + case HTTP_MOVED: + dynFappend(t->response, "HTTP/1.0 301 MOVED\r\n", 20); + break; + case HTTP_FOUND: + dynFappend(t->response, "HTTP/1.0 302 FOUND\r\n", 20); + break; + case HTTP_NOTMODIFIED: + dynFappend(t->response, "HTTP/1.0 304 NOT MODIFIED\r\n", 27); + break; + case HTTP_BADREQUEST: + dynFappend(t->response, "HTTP/1.0 400 BAD REQUEST\r\n", 26); + break; + case HTTP_UNAUTHORIZED: + dynFappend(t->response, "HTTP/1.0 401 UNAUTHORIZED\r\n", 27); + break; + case HTTP_PAYMENTREQUIRED: + dynFappend(t->response, "HTTP/1.0 402 PAYMENT REQUIRED\r\n", 31); + break; + case HTTP_FORBIDDEN: + dynFappend(t->response, "HTTP/1.0 403 FORBIDDEN\r\n", 24); + break; + case HTTP_NOTFOUND: + dynFappend(t->response, "HTTP/1.0 404 NOT FOUND\r\n", 24); + break; + case HTTP_ERROR: + dynFappend(t->response, "HTTP/1.0 500 ERROR\r\n", 20); + break; + case HTTP_UNIMPLEMENTED: + dynFappend(t->response, "HTTP/1.0 501 NOT IMPLEMENTED\r\n", 30); + break; + case HTTP_TIMEDOUT: + dynFappend(t->response, "HTTP/1.0 502 TIMED OUT\r\n", 24); + break; + default: + dynFappend(t->response, "HTTP/1.0 500 ERROR\r\n", 20); + break; + } + + for (i = 0; i < t->res_hdrs->size; i++) { + if (t->res_hdrs->fields[i].name != NULL + && t->res_hdrs->fields[i].value != NULL) { + + + /* dynFsappend(t->response, t->res_hdrs->fields[i].name); */ + + dynFappend(t->response, t->res_hdrs->fields[i].name, + t->res_hdrs->fields[i].n_len); + + dynFappend(t->response, ": ", 2); + + /* dynFsappend(t->response, t->res_hdrs->fields[i].value); */ + + dynFappend(t->response, t->res_hdrs->fields[i].value, + t->res_hdrs->fields[i].v_len); + + dynFappend(t->response, "\r\n", 2); + } + } + + dynFappend(t->response, "\r\n", 2); +} + +/* + * httpFparse + * + * Read a HTTP request from the network and fill out the transaction. This + * function assumes that t->vars are empty and that the network socket + * descriptor is at the beginning of the input stream. + * + * After this function exits, the transaction will contain the following + * + * t->vars clf-request The complete request line the client provided. t->vars + * uri The URI of the request, stripped of any query information. t->vars + * query Anything after the first ? in clf-request. t->vars method The method + * of the request, as specified by the client. Uppercase. t->vars protocol + * The protocol the client provided, if any. Uppercase. + * + * STATUS_PROCEED A request was read. STATUS_ERROR The request could not be + * read. Discard the connection. + */ + +int httpFparse(httpTtrans * t) +{ + /* 1024 hardocded later */ + char req_line[1024]; + dynTstring *decoded; + char *st_p; /* strtok pointer */ + char *method_p = NULL, *uri_p = NULL, *proto_p = NULL, *query_p = NULL; + int method_len, proto_len; + int ret; + size_t rqsize; + + ret = + netFconn_read_line(t->conn, t->reader, req_line, sizeof(req_line)); + + if (ret < 1) { + return STATUS_ERROR; + } + + if (req_line[0] == '\0') + return STATUS_ERROR; + + if (ret >= 1024) { + /* + * The input buffer was of insufficient size for us to store the entire + * line. + */ + logFmsg(1, "Request would not fit in buffer."); + return STATUS_ERROR; + } + rqsize = ret; + + lstFset_badd(t->vars, "clf-request", 11, req_line, ret); + + method_p = (char *) strtok_r(req_line, " ", &st_p); + + /* we don't want to include the " " in this calculation */ + method_len = st_p - method_p - 1; + + uri_p = (char *) strtok_r(NULL, " ", &st_p); + proto_p = (char *) strtok_r(NULL, " ", &st_p); + + proto_len = (req_line + ret) - proto_p; + + if (method_p == NULL || uri_p == NULL) { + /* logFmsg (1, "short request"); */ + return STATUS_ERROR; + } + lstFset_badd(t->res_hdrs, "Server", 6, "continuity/" BUILD_REV, + 11 + BUILD_LEV_LEN); + + strFtoupper(method_p); + lstFset_badd(t->vars, "method", 6, method_p, method_len); + + if (proto_p != NULL) { + strFtoupper(proto_p); + lstFset_badd(t->vars, "protocol", 8, proto_p, proto_len); + } + /* Check to see if we had GET query parameters */ + st_p = NULL; + query_p = (char *) strtok_r(uri_p, "?", &st_p); + + decoded = dynFinit(); + + /* decode the portion of the uri before the query */ + utlFurl_decode(decoded, query_p); + + lstFset_badd(t->vars, "uri", 3, decoded->str, decoded->strlen); + lstFset_badd(t->vars, "req_uri", 7, decoded->str, decoded->strlen); + + dynFfree(decoded); + + query_p = (char *) strtok_r(NULL, "?", &st_p); + + if (query_p != NULL) { + lstFset_badd(t->vars, "query", 5, query_p, strlen(query_p)); + } + + /* + * 4.2 Message Headers + * + * HTTP header fields, which include General-Header (Section 4.3), + * Request-Header (Section 5.2), Response-Header (Section 6.2), and + * Entity-Header (Section 7.1) fields, follow the same generic format as + * that given in Section 3.1 of RFC 822 [7]. Each header field consists + * of a name followed immediately by a colon (":"), a single space (SP) + * character, and the field value. Field names are case-insensitive. + * Header fields can be extended over multiple lines by preceding each + * extra line with at least one SP or HT, though this is not + * recommended. + */ + while (1) { + char *name_p; + char *colon_location; + int name_len; + + char *value_p; + int value_len; + + ret = + netFconn_read_line(t->conn, t->reader, req_line, + sizeof(req_line)); + + if (ret <= 1) + break; + + rqsize += ret; + + name_p = req_line; + + colon_location = index(name_p, ':'); + + if (colon_location == NULL) { + continue; + } + + *colon_location = 0; + + name_len = colon_location - name_p; + + value_p = colon_location + 1; + + /* We should only have to look for one space */ + if (*value_p == ' ') { + value_p++; + } + + if (value_p == NULL) { + continue; + } + + value_len = (req_line + ret) - value_p; + + strFtolower(name_p); + lstFset_badd(t->req_hdrs, name_p, name_len, value_p, value_len); + } + + return STATUS_PROCEED; +} + +/* + * read the conte-type from the request, and break out the boundry + * information. + */ +int httpFget_boundry(dynTstring * str, httpTtrans * t) +{ + const char *type, *bs, *be; + + type = lstFset_get(t->req_hdrs, "content-type"); + + if (type != NULL) { + if (strstr(type, "multipart/form-data") != NULL) { + if ((bs = strstr(type, "boundary=")) != NULL) { + bs += 9; + be = bs; + while (*be && !isspace(*be)) { + ++be; + } + dynFappend(str, "--", 2); + dynFappend(str, bs, be - bs); + return 1; + } + } + } + return 0; +} + +/* + * Trim a string of unescessary crap, from sPtr to ePtr + */ +static void httpFat_end(char **sPtr, char **ePtr) +{ + char *s, *e; + + s = *sPtr; + e = s; + while (*e && !isspace(*e)) { + ++e; + } + if (e > s && e[-1] == ';') { + --e; + } + if (*s == '"' && (e - s) > 1 && e[-1] == '"') { + ++s; + --e; + } + *sPtr = s; + *ePtr = e; +} + +/* + * Read additional POST data off of the connection. This would normally be + * called by httpFparse() in response to the method being post. If there is + * no content-type in the request, then this will simply return -1, otherwise + * it will try to read and process any available post data from the client. A + * -1 return indicates a bad response and should probably generate a + * malformed protocol error. + * + * After the post data is read, it will be t->vars:post_query in it's original + * encoded form. + */ + +int httpFread_post(httpTtrans * t) +{ + dynTstring *query; + char buf[1024]; + const char *clength; + ssize_t ret; + size_t ilength; + + query = dynFinit(); + + clength = lstFset_get(t->req_hdrs, "content-length"); + + if (clength == NULL) + return -1; + + ilength = atoi(clength); + + while (ilength > 0) { + if (ilength > sizeof(buf)) + ret = httpFread(t, buf, sizeof(buf)); + else { + ret = httpFread(t, buf, ilength); + } + + if (ret == 0) + break; + + if (ret < 0) { + dynFfree(query); + return -1; + } + dynFappend(query, buf, ret); + ilength -= ret; + } + + lstFset_badd(t->vars, "post_query", 10, dynFgetstr(query), + dynFgetlen(query)); + dynFfree(query); + + return ret; +} + +/* + * Parse a get string query into set + */ +int httpFparse_query(httpTtrans * t, lstTset * set) +{ + char *p, *k, *v; + char query_buf[1024]; + const char *query; + dynTstring *kds, *vds; + + query = lstFset_get(t->vars, "post_query"); + + if (query == NULL) + return 0; + + strncpy(query_buf, query, sizeof(query_buf)); + + p = query_buf; + + kds = dynFinit(); + vds = dynFinit(); + + while (p != NULL) { + k = p; + p = strchr(p, '&'); + if (p != NULL) { + *p++ = '\0'; + } + v = strchr(k, '='); + if (v != NULL) { + *v = '\0'; + } + utlFurl_decode(kds, k); + k = kds->str; + if (v != NULL) { + utlFurl_decode(vds, v + 1); + *v = '='; + v = vds->str; + } + lstFset_add(set, k, v); + } + + dynFfree(kds); + dynFfree(vds); + + return 1; +} + +/* + * Parse a multiquery between start and end into set + */ +static int httpFparse_multiquery(MECHA_UNUSED_ARGUMENT httpTtrans * t, + char *start, char *end, lstTset * set) +{ + dynTstring *kds, *vds; + char *s, *e, *ks, *ke, *fs, *fe, save, saveend; + + kds = dynFinit(); + vds = dynFinit(); + + /* + * Trim off the trailing \r\n and null terminate the input. + */ + + if (end > start && end[-1] == '\n') + --end; + if (end > start && end[-1] == '\r') + --end; + saveend = *end; + *end = '\0'; + + /* + * Scan non-blank lines for the content-disposition header. + */ + + ks = fs = NULL; + while ((e = strchr(start, '\n')) != NULL) { + s = start; + start = e + 1; + if (e > s && e[-1] == '\r') { + --e; + } + if (s == e) { + break; + } + save = *e; + *e = '\0'; + if (strncasecmp(s, "content-disposition", 19) == 0 + && (ks = strstr(s + 19, "name=")) != NULL) { + + /* + * Save the key name and filename. + */ + + ks += 5; + httpFat_end(&ks, &ke); + if ((fs = strstr(s + 19, "filename=")) != NULL) { + fs += 9; + httpFat_end(&fs, &fe); + } + } + *e = save; + } + + /* + * Save the key/value and file contents if found. + */ + + if (ks != NULL) { + dynFappend(kds, ks, ke - ks); + + if (fs == NULL) { + dynFappend(vds, start, end - start); + } else { + /* Handle File Content */ + } + + lstFset_add(set, kds->str, vds->str); + logFmsg(3, "kv: [%s] [%s]", kds->str, vds->str); + } + *end = saveend; + dynFfree(vds); + dynFfree(kds); + + return 0; +} + +const lstTset *httpFget_query(httpTtrans * t) +{ + const char *q_str; + dynTstring *tmp_query; + + if (t->query != NULL) + return t->query; + + q_str = lstFset_get(t->vars, "query"); + if (q_str == NULL) + return NULL; + + tmp_query = dynFinit(); + + utlFurl_decode(tmp_query, q_str); + + t->query = qryFlst_parse(tmp_query->str); + + dynFfree(tmp_query); + + return t->query; +} + +const lstTset *httpFget_post_query(httpTtrans * t) +{ + dynTstring *bound; + char *s, *e; + const char *form; + lstTset *set; + + form = lstFset_get(t->vars, "post_query"); + + if (form == NULL) + return NULL; + + set = lstFset_create("post_query"); + + bound = dynFinit(); + + if (!httpFget_boundry(bound, t)) { + httpFparse_query(t, set); + } else { + s = strstr(form, bound->str); + logFmsg(3, "caught 0x%x", s); + while (s != NULL) { + s += bound->strlen; + if (*s == '\r') + ++s; + if (*s == '\n') + ++s; + e = strstr(s, bound->str); + if (e != NULL) { + httpFparse_multiquery(t, s, e, set); + } + s = e; + } + } + + dynFfree(bound); + + return set; +} + +void httpFset_state(httpTtrans * t, int state) +{ + t->started = state; +} + +int httpFset_nph(httpTtrans * t) +{ + if (t->started == REQ_UNSTARTED) { + t->started = REQ_HEADERSENT; + + return (1); + } else { + return (0); + } +} + +int httpFread(httpTtrans * t, char *buf, size_t len) +{ + return netFconn_read(t->conn, t->reader, buf, len); +} + + +int httpFwrite(httpTtrans * t, const char *buf, size_t len) +{ + int ret; + + if (t->started == REQ_UNSTARTED) { + httpFstart_response(t); + } + + if (t->started == REQ_STARTED) { + t->started = REQ_HEADERSENT; + + ret = netFconn_write_two(t->conn, t->response->str, + t->response->strlen, buf, len); + + return ret; + } + + ret = netFconn_write(t->conn, buf, len); + + return ret; +} + +const char *httpFquery_val(httpTtrans * t, const char *name) +{ + const char *q_str; + dynTstring *tmp_query; + + if (t->query != NULL) + return lstFset_get(t->query, name); + + q_str = lstFset_get(t->vars, "query"); + if (q_str == NULL) + return NULL; + + tmp_query = dynFinit(); + + utlFurl_decode(tmp_query, q_str); + + t->query = qryFlst_parse(tmp_query->str); + + dynFfree(tmp_query); + + if (t->query == NULL) + return NULL; + + return lstFset_get(t->query, name); +} + +int httpFwritef(httpTtrans * t, const char *fmt, ...) +{ + va_list ap; + int ret1 = 0; + int ret2 = 0; + + if (t->started == REQ_UNSTARTED) { + httpFstart_response(t); + } + + if (t->started == REQ_STARTED) { + t->started = REQ_HEADERSENT; + + ret1 = + netFconn_write(t->conn, t->response->str, t->response->strlen); + + if (ret1 < 1) { + return (ret1); + } + } + + va_start(ap, fmt); + + ret2 = _netFconn_writef(t->conn, fmt, &ap); + + va_end(ap); + + if (ret2 < 1) { + return (ret2); + } + + return (ret1 + ret2); +} + + +int httpFdebug_page(httpTtrans * t, MECHA_UNUSED_ARGUMENT char *msg) +{ + int i = 0, ret; + char buf[256]; + const char *m1 = "

t->vars

\n"; + const char *m2 = "

t->req_hdrs

\n"; + const char *m3 = "

t->res_hdrs

\n"; + dynTstring outbuf; + char hostname[64]; + + lstFset_update(t->res_hdrs, "Content-Type", "text/html"); + + gethostname(hostname, 64); + + bzero(&outbuf, sizeof(dynTstring)); + + dynFsappend(&outbuf, "

"); + dynFsappend(&outbuf, hostname); + dynFsappend(&outbuf, "

"); + dynFsappend(&outbuf, m1); + + while (1) { + ret = lstFnth_find(t->vars, i); + if (ret == -1) + break; + snprintf(buf, sizeof(buf), "%s : %s
\n", + t->vars->fields[i].name, t->vars->fields[i].value); + dynFappend(&outbuf, buf, strlen(buf)); + + i++; + } + + i = 0; + dynFsappend(&outbuf, m2); + + while (1) { + ret = lstFnth_find(t->req_hdrs, i); + if (ret == -1) + break; + snprintf(buf, sizeof(buf), "%s : %s
\n", + t->req_hdrs->fields[i].name, + t->req_hdrs->fields[i].value); + dynFappend(&outbuf, buf, strlen(buf)); + i++; + } + + i = 0; + dynFsappend(&outbuf, m3); + + while (1) { + ret = lstFnth_find(t->res_hdrs, i); + if (ret == -1) + break; + snprintf(buf, sizeof(buf), "%s : %s
\n", + t->res_hdrs->fields[i].name, + t->res_hdrs->fields[i].value); + dynFappend(&outbuf, buf, strlen(buf)); + i++; + } + + httpFwrite(t, outbuf.str, strlen(outbuf.str)); + free(outbuf.str); + + return STATUS_EXIT; +} + +int httpFredirect(httpTtrans * t, const char *dest) +{ + assert(t != NULL); + assert(dest != NULL); + + tasFstat_counter_add("http_svc", 0, "httpFredirect", 1); + + lstFset_update(t->res_hdrs, "Location", dest); + + httpFset_status(t, HTTP_FOUND, NULL); + httpFstart_response(t); + + return STATUS_EXIT; +} + +/* + * httpFmaterial_compare checks to see if a is materially similar to b. 0 = + * not similar 1 = similar 2 = provisionally similar (POST data) + */ +int httpFmaterial_compare(const httpTtrans * a, const httpTtrans * b) +{ + const lstTfield *as, *bs; + + assert(a != NULL); + assert(b != NULL); + + as = lstFset_get_field(a->vars, "clf-request", 11); + bs = lstFset_get_field(b->vars, "clf-request", 11); + + if (as == NULL || bs == NULL) { + return (0); + } + + if (lstFfield_value_len(as) != lstFfield_value_len(bs)) { + return (0); + } + + if (memcmp(lstFfield_value(as), lstFfield_value(bs), + lstFfield_value_len(as)) != 0) { + return (0); + } + + /* + * If we got a content-length, there was POST, and we cannot compare the + * post data + */ + + as = lstFset_get_field(a->req_hdrs, "content-length", 14); + + if (as != NULL) { + return 2; + } + + return 1; +} diff --git a/mk4/modhttp/http.h b/mk4/modhttp/http.h new file mode 100644 index 0000000..93b5997 --- /dev/null +++ b/mk4/modhttp/http.h @@ -0,0 +1,102 @@ +/* $Header: /san01/cvs/ashpool/csrc/modhttp/Attic/http.h,v 1.18 2004/04/02 16:17:18 aleigh Exp $ */ + +/* Copyright (c) 1994, 2001 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH + * The copyright notice above does not evidence any + * actual or intended publication of such source code. + * + * Disclosure, copying, distribution, or transmission of + * this code without express permission is prohibited. + */ + +#ifndef HTTP_H +#define HTTP_H + +#include "continuity.h" +#include "mecha.h" + +#define HTTP_OK 200 +#define HTTP_CREATED 201 +#define HTTP_ACCEPTED 202 +#define HTTP_PARTIAL 203 +#define HTTP_NORESPONSE 204 +#define HTTP_MOVED 301 +#define HTTP_FOUND 302 +#define HTTP_METHOD 303 +#define HTTP_NOTMODIFIED 304 +#define HTTP_BADREQUEST 400 +#define HTTP_UNAUTHORIZED 401 +#define HTTP_PAYMENTREQUIRED 402 +#define HTTP_FORBIDDEN 403 +#define HTTP_NOTFOUND 404 +#define HTTP_ERROR 500 +#define HTTP_UNIMPLEMENTED 501 +#define HTTP_TIMEDOUT 502 /* unofficial */ + +#define REQ_UNSTARTED 0 +#define REQ_STARTED 1 +#define REQ_HEADERSENT 2 + +struct httpStrans { + int sd; /* Socket Descriptor */ + uint32_t cli_ipv4_addr; /* Remote IPv4 Address */ + netTreader *reader; /* Network Reader */ + + struct stat statb; /* A stat of the response file */ + + lstTset *req_hdrs; /* Client HTTP headers */ + lstTset *res_hdrs; /* Response HTTP headers */ + lstTset *vars; /* Working Variables */ + lstTset *query; /* Query Cache */ + + int res_code; /* Response Code */ + const char *res_reason; /* Response Message */ + + int started; /* Transaction status */ + int client_read; /* Client status */ + + dynTstring *response; /* HTTP Protocol Response */ + netTconn *conn; + + int has_statb; /* Indicate if statb has been filled in */ +}; +typedef struct httpStrans httpTtrans; + +int httpFcreate_dispatcher(int ipv4port, int ipv4ip); +int httpFthread_settrans(httpTtrans * t); + +/* Handlers */ +void httpFhandler(void *p, const lstTset *arg); +int httpFinit(void *p, const lstTset *opts); + +/* Public Functions */ +httpTtrans *httpFtrans_alloc(void); +void httpFtrans_free(httpTtrans * t); +httpTtrans *httpFthread_gettrans(void); +void httpFset_status(httpTtrans * t, int status, const char *reason); +void httpFstart_response(httpTtrans * t); +void httpFsend_response(httpTtrans * t); +int httpFsend_resp_headers(httpTtrans * t); +int httpFread (httpTtrans * t, char *buf, size_t len); +int httpFwrite(httpTtrans * t, const char *buf, size_t len); +int httpFwritef(httpTtrans *t, const char *fmt, ...); +int httpFredirect(httpTtrans *t, const char *dest); +const lstTset *httpFget_query(httpTtrans * t); +const lstTset *httpFget_post_query(httpTtrans * t); +const char *httpFquery_val(httpTtrans *t, const char *name); + +int httpFread_post(httpTtrans * t); +int httpFdebug_page (httpTtrans * t, char *msg); +int httpFlog_trans(httpTtrans * t, char *msg); +int httpFparse(httpTtrans * t); +int httpFget_boundry(dynTstring * str, httpTtrans * t); +int httpFparse_query(httpTtrans * t, lstTset *set); +int httpFerror_page (httpTtrans * t, const char *msg); +int httpFmaterial_compare(const httpTtrans *trans, const httpTtrans *b); + +void httpFset_state (httpTtrans *t, int state); + +int httpFset_nph (httpTtrans *t); + +#endif diff --git a/mk4/modhttp/http.xml b/mk4/modhttp/http.xml new file mode 100644 index 0000000..eeee635 --- /dev/null +++ b/mk4/modhttp/http.xml @@ -0,0 +1,4 @@ + + http + httpFinit + diff --git a/mk4/modimage/CVS/Entries b/mk4/modimage/CVS/Entries new file mode 100644 index 0000000..4a483c9 --- /dev/null +++ b/mk4/modimage/CVS/Entries @@ -0,0 +1,18 @@ +/Makefile.in/1.3/Wed May 12 13:59:10 2004//Tmk4_mod6_rc2 +/cderror.h/1.1/Wed Oct 29 20:54:58 2003//Tmk4_mod6_rc2 +/cdjpeg.h/1.1/Wed Oct 29 20:54:58 2003//Tmk4_mod6_rc2 +/image.c/1.2/Thu Mar 18 15:04:15 2004//Tmk4_mod6_rc2 +/image.xml/1.1/Wed May 12 13:59:10 2004//Tmk4_mod6_rc2 +/jchuff.h/1.1/Wed Oct 29 20:54:58 2003//Tmk4_mod6_rc2 +/jconfig.h/1.1/Wed Oct 29 20:54:58 2003//Tmk4_mod6_rc2 +/jdct.h/1.1/Wed Oct 29 20:54:58 2003//Tmk4_mod6_rc2 +/jdhuff.h/1.1/Wed Oct 29 20:54:58 2003//Tmk4_mod6_rc2 +/jerror.h/1.1/Wed Oct 29 20:54:58 2003//Tmk4_mod6_rc2 +/jinclude.h/1.1/Wed Oct 29 20:54:58 2003//Tmk4_mod6_rc2 +/jmemsys.h/1.1/Wed Oct 29 20:54:58 2003//Tmk4_mod6_rc2 +/jmorecfg.h/1.1/Wed Oct 29 20:54:58 2003//Tmk4_mod6_rc2 +/jpegint.h/1.1/Wed Oct 29 20:54:58 2003//Tmk4_mod6_rc2 +/jpeglib.h/1.1/Wed Oct 29 20:54:58 2003//Tmk4_mod6_rc2 +/jversion.h/1.1/Wed Oct 29 20:54:58 2003//Tmk4_mod6_rc2 +/transupp.h/1.1/Wed Oct 29 20:54:58 2003//Tmk4_mod6_rc2 +D/jpeg-6b//// diff --git a/mk4/modimage/CVS/Repository b/mk4/modimage/CVS/Repository new file mode 100644 index 0000000..b918a9e --- /dev/null +++ b/mk4/modimage/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/modimage diff --git a/mk4/modimage/CVS/Root b/mk4/modimage/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/modimage/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/modimage/CVS/Tag b/mk4/modimage/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/modimage/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/modimage/Makefile.in b/mk4/modimage/Makefile.in new file mode 100644 index 0000000..10c68aa --- /dev/null +++ b/mk4/modimage/Makefile.in @@ -0,0 +1,28 @@ +# $Header: /san01/cvs/ashpool/csrc/modimage/Attic/Makefile.in,v 1.3 2004/05/12 13:59:10 aleigh Exp $ + +include ../continuity/lib/env.mk + +SRCS=image.c +OBJS=image.o + +CFLAGS=-I../continuity/include $(CONT_FLAGS) + +world: install + +jpeg-6b/libjpeg.a: + (cd jpeg-6b;./configure;make) + +image.so: jpeg-6b/libjpeg.a $(OBJS) + $(LD_SHARECMD) -o image.so $(OBJS) jpeg-6b/libjpeg.a +clean: + $(RM) $(OBJS) *~ image.so + +install: image.so + cp image.so ../continuity/lib + cp *.h ../continuity/include + cp image.xml ../continuity/lib + + +depend: + $(MAKEDEPEND) $(DEPFLAGS) -I ../continuity/include $(SRCS) + diff --git a/mk4/modimage/cderror.h b/mk4/modimage/cderror.h new file mode 100644 index 0000000..70435e1 --- /dev/null +++ b/mk4/modimage/cderror.h @@ -0,0 +1,132 @@ +/* + * cderror.h + * + * Copyright (C) 1994-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file defines the error and message codes for the cjpeg/djpeg + * applications. These strings are not needed as part of the JPEG library + * proper. + * Edit this file to add new codes, or to translate the message strings to + * some other language. + */ + +/* + * To define the enum list of message codes, include this file without + * defining macro JMESSAGE. To create a message string table, include it + * again with a suitable JMESSAGE definition (see jerror.c for an example). + */ +#ifndef JMESSAGE +#ifndef CDERROR_H +#define CDERROR_H +/* First time through, define the enum list */ +#define JMAKE_ENUM_LIST +#else +/* Repeated inclusions of this file are no-ops unless JMESSAGE is defined */ +#define JMESSAGE(code,string) +#endif /* CDERROR_H */ +#endif /* JMESSAGE */ + +#ifdef JMAKE_ENUM_LIST + +typedef enum { + +#define JMESSAGE(code,string) code , + +#endif /* JMAKE_ENUM_LIST */ + +JMESSAGE(JMSG_FIRSTADDONCODE=1000, NULL) /* Must be first entry! */ + +#ifdef BMP_SUPPORTED +JMESSAGE(JERR_BMP_BADCMAP, "Unsupported BMP colormap format") +JMESSAGE(JERR_BMP_BADDEPTH, "Only 8- and 24-bit BMP files are supported") +JMESSAGE(JERR_BMP_BADHEADER, "Invalid BMP file: bad header length") +JMESSAGE(JERR_BMP_BADPLANES, "Invalid BMP file: biPlanes not equal to 1") +JMESSAGE(JERR_BMP_COLORSPACE, "BMP output must be grayscale or RGB") +JMESSAGE(JERR_BMP_COMPRESSED, "Sorry, compressed BMPs not yet supported") +JMESSAGE(JERR_BMP_NOT, "Not a BMP file - does not start with BM") +JMESSAGE(JTRC_BMP, "%ux%u 24-bit BMP image") +JMESSAGE(JTRC_BMP_MAPPED, "%ux%u 8-bit colormapped BMP image") +JMESSAGE(JTRC_BMP_OS2, "%ux%u 24-bit OS2 BMP image") +JMESSAGE(JTRC_BMP_OS2_MAPPED, "%ux%u 8-bit colormapped OS2 BMP image") +#endif /* BMP_SUPPORTED */ + +#ifdef GIF_SUPPORTED +JMESSAGE(JERR_GIF_BUG, "GIF output got confused") +JMESSAGE(JERR_GIF_CODESIZE, "Bogus GIF codesize %d") +JMESSAGE(JERR_GIF_COLORSPACE, "GIF output must be grayscale or RGB") +JMESSAGE(JERR_GIF_IMAGENOTFOUND, "Too few images in GIF file") +JMESSAGE(JERR_GIF_NOT, "Not a GIF file") +JMESSAGE(JTRC_GIF, "%ux%ux%d GIF image") +JMESSAGE(JTRC_GIF_BADVERSION, + "Warning: unexpected GIF version number '%c%c%c'") +JMESSAGE(JTRC_GIF_EXTENSION, "Ignoring GIF extension block of type 0x%02x") +JMESSAGE(JTRC_GIF_NONSQUARE, "Caution: nonsquare pixels in input") +JMESSAGE(JWRN_GIF_BADDATA, "Corrupt data in GIF file") +JMESSAGE(JWRN_GIF_CHAR, "Bogus char 0x%02x in GIF file, ignoring") +JMESSAGE(JWRN_GIF_ENDCODE, "Premature end of GIF image") +JMESSAGE(JWRN_GIF_NOMOREDATA, "Ran out of GIF bits") +#endif /* GIF_SUPPORTED */ + +#ifdef PPM_SUPPORTED +JMESSAGE(JERR_PPM_COLORSPACE, "PPM output must be grayscale or RGB") +JMESSAGE(JERR_PPM_NONNUMERIC, "Nonnumeric data in PPM file") +JMESSAGE(JERR_PPM_NOT, "Not a PPM/PGM file") +JMESSAGE(JTRC_PGM, "%ux%u PGM image") +JMESSAGE(JTRC_PGM_TEXT, "%ux%u text PGM image") +JMESSAGE(JTRC_PPM, "%ux%u PPM image") +JMESSAGE(JTRC_PPM_TEXT, "%ux%u text PPM image") +#endif /* PPM_SUPPORTED */ + +#ifdef RLE_SUPPORTED +JMESSAGE(JERR_RLE_BADERROR, "Bogus error code from RLE library") +JMESSAGE(JERR_RLE_COLORSPACE, "RLE output must be grayscale or RGB") +JMESSAGE(JERR_RLE_DIMENSIONS, "Image dimensions (%ux%u) too large for RLE") +JMESSAGE(JERR_RLE_EMPTY, "Empty RLE file") +JMESSAGE(JERR_RLE_EOF, "Premature EOF in RLE header") +JMESSAGE(JERR_RLE_MEM, "Insufficient memory for RLE header") +JMESSAGE(JERR_RLE_NOT, "Not an RLE file") +JMESSAGE(JERR_RLE_TOOMANYCHANNELS, "Cannot handle %d output channels for RLE") +JMESSAGE(JERR_RLE_UNSUPPORTED, "Cannot handle this RLE setup") +JMESSAGE(JTRC_RLE, "%ux%u full-color RLE file") +JMESSAGE(JTRC_RLE_FULLMAP, "%ux%u full-color RLE file with map of length %d") +JMESSAGE(JTRC_RLE_GRAY, "%ux%u grayscale RLE file") +JMESSAGE(JTRC_RLE_MAPGRAY, "%ux%u grayscale RLE file with map of length %d") +JMESSAGE(JTRC_RLE_MAPPED, "%ux%u colormapped RLE file with map of length %d") +#endif /* RLE_SUPPORTED */ + +#ifdef TARGA_SUPPORTED +JMESSAGE(JERR_TGA_BADCMAP, "Unsupported Targa colormap format") +JMESSAGE(JERR_TGA_BADPARMS, "Invalid or unsupported Targa file") +JMESSAGE(JERR_TGA_COLORSPACE, "Targa output must be grayscale or RGB") +JMESSAGE(JTRC_TGA, "%ux%u RGB Targa image") +JMESSAGE(JTRC_TGA_GRAY, "%ux%u grayscale Targa image") +JMESSAGE(JTRC_TGA_MAPPED, "%ux%u colormapped Targa image") +#else +JMESSAGE(JERR_TGA_NOTCOMP, "Targa support was not compiled") +#endif /* TARGA_SUPPORTED */ + +JMESSAGE(JERR_BAD_CMAP_FILE, + "Color map file is invalid or of unsupported format") +JMESSAGE(JERR_TOO_MANY_COLORS, + "Output file format cannot handle %d colormap entries") +JMESSAGE(JERR_UNGETC_FAILED, "ungetc failed") +#ifdef TARGA_SUPPORTED +JMESSAGE(JERR_UNKNOWN_FORMAT, + "Unrecognized input file format --- perhaps you need -targa") +#else +JMESSAGE(JERR_UNKNOWN_FORMAT, "Unrecognized input file format") +#endif +JMESSAGE(JERR_UNSUPPORTED_FORMAT, "Unsupported output file format") + +#ifdef JMAKE_ENUM_LIST + + JMSG_LASTADDONCODE +} ADDON_MESSAGE_CODE; + +#undef JMAKE_ENUM_LIST +#endif /* JMAKE_ENUM_LIST */ + +/* Zap JMESSAGE macro so that future re-inclusions do nothing by default */ +#undef JMESSAGE diff --git a/mk4/modimage/cdjpeg.h b/mk4/modimage/cdjpeg.h new file mode 100644 index 0000000..2b387b6 --- /dev/null +++ b/mk4/modimage/cdjpeg.h @@ -0,0 +1,184 @@ +/* + * cdjpeg.h + * + * Copyright (C) 1994-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains common declarations for the sample applications + * cjpeg and djpeg. It is NOT used by the core JPEG library. + */ + +#define JPEG_CJPEG_DJPEG /* define proper options in jconfig.h */ +#define JPEG_INTERNAL_OPTIONS /* cjpeg.c,djpeg.c need to see xxx_SUPPORTED */ +#include "jinclude.h" +#include "jpeglib.h" +#include "jerror.h" /* get library error codes too */ +#include "cderror.h" /* get application-specific error codes */ + + +/* + * Object interface for cjpeg's source file decoding modules + */ + +typedef struct cjpeg_source_struct * cjpeg_source_ptr; + +struct cjpeg_source_struct { + JMETHOD(void, start_input, (j_compress_ptr cinfo, + cjpeg_source_ptr sinfo)); + JMETHOD(JDIMENSION, get_pixel_rows, (j_compress_ptr cinfo, + cjpeg_source_ptr sinfo)); + JMETHOD(void, finish_input, (j_compress_ptr cinfo, + cjpeg_source_ptr sinfo)); + + FILE *input_file; + + JSAMPARRAY buffer; + JDIMENSION buffer_height; +}; + + +/* + * Object interface for djpeg's output file encoding modules + */ + +typedef struct djpeg_dest_struct * djpeg_dest_ptr; + +struct djpeg_dest_struct { + /* start_output is called after jpeg_start_decompress finishes. + * The color map will be ready at this time, if one is needed. + */ + JMETHOD(void, start_output, (j_decompress_ptr cinfo, + djpeg_dest_ptr dinfo)); + /* Emit the specified number of pixel rows from the buffer. */ + JMETHOD(void, put_pixel_rows, (j_decompress_ptr cinfo, + djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied)); + /* Finish up at the end of the image. */ + JMETHOD(void, finish_output, (j_decompress_ptr cinfo, + djpeg_dest_ptr dinfo)); + + /* Target file spec; filled in by djpeg.c after object is created. */ + FILE * output_file; + + /* Output pixel-row buffer. Created by module init or start_output. + * Width is cinfo->output_width * cinfo->output_components; + * height is buffer_height. + */ + JSAMPARRAY buffer; + JDIMENSION buffer_height; +}; + + +/* + * cjpeg/djpeg may need to perform extra passes to convert to or from + * the source/destination file format. The JPEG library does not know + * about these passes, but we'd like them to be counted by the progress + * monitor. We use an expanded progress monitor object to hold the + * additional pass count. + */ + +struct cdjpeg_progress_mgr { + struct jpeg_progress_mgr pub; /* fields known to JPEG library */ + int completed_extra_passes; /* extra passes completed */ + int total_extra_passes; /* total extra */ + /* last printed percentage stored here to avoid multiple printouts */ + int percent_done; +}; + +typedef struct cdjpeg_progress_mgr * cd_progress_ptr; + + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jinit_read_bmp jIRdBMP +#define jinit_write_bmp jIWrBMP +#define jinit_read_gif jIRdGIF +#define jinit_write_gif jIWrGIF +#define jinit_read_ppm jIRdPPM +#define jinit_write_ppm jIWrPPM +#define jinit_read_rle jIRdRLE +#define jinit_write_rle jIWrRLE +#define jinit_read_targa jIRdTarga +#define jinit_write_targa jIWrTarga +#define read_quant_tables RdQTables +#define read_scan_script RdScnScript +#define set_quant_slots SetQSlots +#define set_sample_factors SetSFacts +#define read_color_map RdCMap +#define enable_signal_catcher EnSigCatcher +#define start_progress_monitor StProgMon +#define end_progress_monitor EnProgMon +#define read_stdin RdStdin +#define write_stdout WrStdout +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + +/* Module selection routines for I/O modules. */ + +EXTERN(cjpeg_source_ptr) jinit_read_bmp JPP((j_compress_ptr cinfo)); +EXTERN(djpeg_dest_ptr) jinit_write_bmp JPP((j_decompress_ptr cinfo, + boolean is_os2)); +EXTERN(cjpeg_source_ptr) jinit_read_gif JPP((j_compress_ptr cinfo)); +EXTERN(djpeg_dest_ptr) jinit_write_gif JPP((j_decompress_ptr cinfo)); +EXTERN(cjpeg_source_ptr) jinit_read_ppm JPP((j_compress_ptr cinfo)); +EXTERN(djpeg_dest_ptr) jinit_write_ppm JPP((j_decompress_ptr cinfo)); +EXTERN(cjpeg_source_ptr) jinit_read_rle JPP((j_compress_ptr cinfo)); +EXTERN(djpeg_dest_ptr) jinit_write_rle JPP((j_decompress_ptr cinfo)); +EXTERN(cjpeg_source_ptr) jinit_read_targa JPP((j_compress_ptr cinfo)); +EXTERN(djpeg_dest_ptr) jinit_write_targa JPP((j_decompress_ptr cinfo)); + +/* cjpeg support routines (in rdswitch.c) */ + +EXTERN(boolean) read_quant_tables JPP((j_compress_ptr cinfo, char * filename, + int scale_factor, boolean force_baseline)); +EXTERN(boolean) read_scan_script JPP((j_compress_ptr cinfo, char * filename)); +EXTERN(boolean) set_quant_slots JPP((j_compress_ptr cinfo, char *arg)); +EXTERN(boolean) set_sample_factors JPP((j_compress_ptr cinfo, char *arg)); + +/* djpeg support routines (in rdcolmap.c) */ + +EXTERN(void) read_color_map JPP((j_decompress_ptr cinfo, FILE * infile)); + +/* common support routines (in cdjpeg.c) */ + +EXTERN(void) enable_signal_catcher JPP((j_common_ptr cinfo)); +EXTERN(void) start_progress_monitor JPP((j_common_ptr cinfo, + cd_progress_ptr progress)); +EXTERN(void) end_progress_monitor JPP((j_common_ptr cinfo)); +EXTERN(boolean) keymatch JPP((char * arg, const char * keyword, int minchars)); +EXTERN(FILE *) read_stdin JPP((void)); +EXTERN(FILE *) write_stdout JPP((void)); + +/* miscellaneous useful macros */ + +#ifdef DONT_USE_B_MODE /* define mode parameters for fopen() */ +#define READ_BINARY "r" +#define WRITE_BINARY "w" +#else +#ifdef VMS /* VMS is very nonstandard */ +#define READ_BINARY "rb", "ctx=stm" +#define WRITE_BINARY "wb", "ctx=stm" +#else /* standard ANSI-compliant case */ +#define READ_BINARY "rb" +#define WRITE_BINARY "wb" +#endif +#endif + +#ifndef EXIT_FAILURE /* define exit() codes if not provided */ +#define EXIT_FAILURE 1 +#endif +#ifndef EXIT_SUCCESS +#ifdef VMS +#define EXIT_SUCCESS 1 /* VMS is very nonstandard */ +#else +#define EXIT_SUCCESS 0 +#endif +#endif +#ifndef EXIT_WARNING +#ifdef VMS +#define EXIT_WARNING 1 /* VMS is very nonstandard */ +#else +#define EXIT_WARNING 2 +#endif +#endif diff --git a/mk4/modimage/image.c b/mk4/modimage/image.c new file mode 100644 index 0000000..18aee10 --- /dev/null +++ b/mk4/modimage/image.c @@ -0,0 +1,29 @@ +#include +#include +#include "jpeg-6b/jpeglib.h" + +int imgFjpeg_size(char *filename, int *width, int *height) +{ + struct jpeg_decompress_struct cinfo; + struct jpeg_error_mgr jerr; + FILE *infile; + + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_decompress(&cinfo); + + if ((infile = fopen(filename, "rb")) == NULL) { + jpeg_destroy_decompress(&cinfo); + return -1; + } + jpeg_stdio_src(&cinfo, infile); + jpeg_read_header(&cinfo, TRUE); + + fclose(infile); + + *width = cinfo.image_width; + *height = cinfo.image_height; + + jpeg_destroy_decompress(&cinfo); + + return 0; +} diff --git a/mk4/modimage/image.xml b/mk4/modimage/image.xml new file mode 100644 index 0000000..791a006 --- /dev/null +++ b/mk4/modimage/image.xml @@ -0,0 +1,3 @@ + + image + diff --git a/mk4/modimage/jchuff.h b/mk4/modimage/jchuff.h new file mode 100644 index 0000000..a9599fc --- /dev/null +++ b/mk4/modimage/jchuff.h @@ -0,0 +1,47 @@ +/* + * jchuff.h + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains declarations for Huffman entropy encoding routines + * that are shared between the sequential encoder (jchuff.c) and the + * progressive encoder (jcphuff.c). No other modules need to see these. + */ + +/* The legal range of a DCT coefficient is + * -1024 .. +1023 for 8-bit data; + * -16384 .. +16383 for 12-bit data. + * Hence the magnitude should always fit in 10 or 14 bits respectively. + */ + +#if BITS_IN_JSAMPLE == 8 +#define MAX_COEF_BITS 10 +#else +#define MAX_COEF_BITS 14 +#endif + +/* Derived data constructed for each Huffman table */ + +typedef struct { + unsigned int ehufco[256]; /* code for each symbol */ + char ehufsi[256]; /* length of code for each symbol */ + /* If no code has been allocated for a symbol S, ehufsi[S] contains 0 */ +} c_derived_tbl; + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_make_c_derived_tbl jMkCDerived +#define jpeg_gen_optimal_table jGenOptTbl +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + +/* Expand a Huffman table definition into the derived format */ +EXTERN(void) jpeg_make_c_derived_tbl + JPP((j_compress_ptr cinfo, boolean isDC, int tblno, + c_derived_tbl ** pdtbl)); + +/* Generate an optimal table definition given the specified counts */ +EXTERN(void) jpeg_gen_optimal_table + JPP((j_compress_ptr cinfo, JHUFF_TBL * htbl, long freq[])); diff --git a/mk4/modimage/jconfig.h b/mk4/modimage/jconfig.h new file mode 100644 index 0000000..b01fe7b --- /dev/null +++ b/mk4/modimage/jconfig.h @@ -0,0 +1,45 @@ +/* jconfig.h. Generated automatically by configure. */ +/* jconfig.cfg --- source file edited by configure script */ +/* see jconfig.doc for explanations */ + +#define HAVE_PROTOTYPES +#define HAVE_UNSIGNED_CHAR +#define HAVE_UNSIGNED_SHORT +#undef void +#undef const +#undef CHAR_IS_UNSIGNED +#define HAVE_STDDEF_H +#define HAVE_STDLIB_H +#undef NEED_BSD_STRINGS +#undef NEED_SYS_TYPES_H +#undef NEED_FAR_POINTERS +#undef NEED_SHORT_EXTERNAL_NAMES +/* Define this if you get warnings about undefined structures. */ +#undef INCOMPLETE_TYPES_BROKEN + +#ifdef JPEG_INTERNALS + +#undef RIGHT_SHIFT_IS_UNSIGNED +#define INLINE +/* These are for configuring the JPEG memory manager. */ +#undef DEFAULT_MAX_MEM +#undef NO_MKTEMP + +#endif /* JPEG_INTERNALS */ + +#ifdef JPEG_CJPEG_DJPEG + +#define BMP_SUPPORTED /* BMP image file format */ +#define GIF_SUPPORTED /* GIF image file format */ +#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */ +#undef RLE_SUPPORTED /* Utah RLE image file format */ +#define TARGA_SUPPORTED /* Targa image file format */ + +#undef TWO_FILE_COMMANDLINE +#undef NEED_SIGNAL_CATCHER +#undef DONT_USE_B_MODE + +/* Define this if you want percent-done progress reports from cjpeg/djpeg. */ +#undef PROGRESS_REPORT + +#endif /* JPEG_CJPEG_DJPEG */ diff --git a/mk4/modimage/jdct.h b/mk4/modimage/jdct.h new file mode 100644 index 0000000..04192a2 --- /dev/null +++ b/mk4/modimage/jdct.h @@ -0,0 +1,176 @@ +/* + * jdct.h + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This include file contains common declarations for the forward and + * inverse DCT modules. These declarations are private to the DCT managers + * (jcdctmgr.c, jddctmgr.c) and the individual DCT algorithms. + * The individual DCT algorithms are kept in separate files to ease + * machine-dependent tuning (e.g., assembly coding). + */ + + +/* + * A forward DCT routine is given a pointer to a work area of type DCTELEM[]; + * the DCT is to be performed in-place in that buffer. Type DCTELEM is int + * for 8-bit samples, INT32 for 12-bit samples. (NOTE: Floating-point DCT + * implementations use an array of type FAST_FLOAT, instead.) + * The DCT inputs are expected to be signed (range +-CENTERJSAMPLE). + * The DCT outputs are returned scaled up by a factor of 8; they therefore + * have a range of +-8K for 8-bit data, +-128K for 12-bit data. This + * convention improves accuracy in integer implementations and saves some + * work in floating-point ones. + * Quantization of the output coefficients is done by jcdctmgr.c. + */ + +#if BITS_IN_JSAMPLE == 8 +typedef int DCTELEM; /* 16 or 32 bits is fine */ +#else +typedef INT32 DCTELEM; /* must have 32 bits */ +#endif + +typedef JMETHOD(void, forward_DCT_method_ptr, (DCTELEM * data)); +typedef JMETHOD(void, float_DCT_method_ptr, (FAST_FLOAT * data)); + + +/* + * An inverse DCT routine is given a pointer to the input JBLOCK and a pointer + * to an output sample array. The routine must dequantize the input data as + * well as perform the IDCT; for dequantization, it uses the multiplier table + * pointed to by compptr->dct_table. The output data is to be placed into the + * sample array starting at a specified column. (Any row offset needed will + * be applied to the array pointer before it is passed to the IDCT code.) + * Note that the number of samples emitted by the IDCT routine is + * DCT_scaled_size * DCT_scaled_size. + */ + +/* typedef inverse_DCT_method_ptr is declared in jpegint.h */ + +/* + * Each IDCT routine has its own ideas about the best dct_table element type. + */ + +typedef MULTIPLIER ISLOW_MULT_TYPE; /* short or int, whichever is faster */ +#if BITS_IN_JSAMPLE == 8 +typedef MULTIPLIER IFAST_MULT_TYPE; /* 16 bits is OK, use short if faster */ +#define IFAST_SCALE_BITS 2 /* fractional bits in scale factors */ +#else +typedef INT32 IFAST_MULT_TYPE; /* need 32 bits for scaled quantizers */ +#define IFAST_SCALE_BITS 13 /* fractional bits in scale factors */ +#endif +typedef FAST_FLOAT FLOAT_MULT_TYPE; /* preferred floating type */ + + +/* + * Each IDCT routine is responsible for range-limiting its results and + * converting them to unsigned form (0..MAXJSAMPLE). The raw outputs could + * be quite far out of range if the input data is corrupt, so a bulletproof + * range-limiting step is required. We use a mask-and-table-lookup method + * to do the combined operations quickly. See the comments with + * prepare_range_limit_table (in jdmaster.c) for more info. + */ + +#define IDCT_range_limit(cinfo) ((cinfo)->sample_range_limit + CENTERJSAMPLE) + +#define RANGE_MASK (MAXJSAMPLE * 4 + 3) /* 2 bits wider than legal samples */ + + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_fdct_islow jFDislow +#define jpeg_fdct_ifast jFDifast +#define jpeg_fdct_float jFDfloat +#define jpeg_idct_islow jRDislow +#define jpeg_idct_ifast jRDifast +#define jpeg_idct_float jRDfloat +#define jpeg_idct_4x4 jRD4x4 +#define jpeg_idct_2x2 jRD2x2 +#define jpeg_idct_1x1 jRD1x1 +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + +/* Extern declarations for the forward and inverse DCT routines. */ + +EXTERN(void) jpeg_fdct_islow JPP((DCTELEM * data)); +EXTERN(void) jpeg_fdct_ifast JPP((DCTELEM * data)); +EXTERN(void) jpeg_fdct_float JPP((FAST_FLOAT * data)); + +EXTERN(void) jpeg_idct_islow + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_ifast + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_float + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_4x4 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_2x2 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_1x1 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); + + +/* + * Macros for handling fixed-point arithmetic; these are used by many + * but not all of the DCT/IDCT modules. + * + * All values are expected to be of type INT32. + * Fractional constants are scaled left by CONST_BITS bits. + * CONST_BITS is defined within each module using these macros, + * and may differ from one module to the next. + */ + +#define ONE ((INT32) 1) +#define CONST_SCALE (ONE << CONST_BITS) + +/* Convert a positive real constant to an integer scaled by CONST_SCALE. + * Caution: some C compilers fail to reduce "FIX(constant)" at compile time, + * thus causing a lot of useless floating-point operations at run time. + */ + +#define FIX(x) ((INT32) ((x) * CONST_SCALE + 0.5)) + +/* Descale and correctly round an INT32 value that's scaled by N bits. + * We assume RIGHT_SHIFT rounds towards minus infinity, so adding + * the fudge factor is correct for either sign of X. + */ + +#define DESCALE(x,n) RIGHT_SHIFT((x) + (ONE << ((n)-1)), n) + +/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result. + * This macro is used only when the two inputs will actually be no more than + * 16 bits wide, so that a 16x16->32 bit multiply can be used instead of a + * full 32x32 multiply. This provides a useful speedup on many machines. + * Unfortunately there is no way to specify a 16x16->32 multiply portably + * in C, but some C compilers will do the right thing if you provide the + * correct combination of casts. + */ + +#ifdef SHORTxSHORT_32 /* may work if 'int' is 32 bits */ +#define MULTIPLY16C16(var,const) (((INT16) (var)) * ((INT16) (const))) +#endif +#ifdef SHORTxLCONST_32 /* known to work with Microsoft C 6.0 */ +#define MULTIPLY16C16(var,const) (((INT16) (var)) * ((INT32) (const))) +#endif + +#ifndef MULTIPLY16C16 /* default definition */ +#define MULTIPLY16C16(var,const) ((var) * (const)) +#endif + +/* Same except both inputs are variables. */ + +#ifdef SHORTxSHORT_32 /* may work if 'int' is 32 bits */ +#define MULTIPLY16V16(var1,var2) (((INT16) (var1)) * ((INT16) (var2))) +#endif + +#ifndef MULTIPLY16V16 /* default definition */ +#define MULTIPLY16V16(var1,var2) ((var1) * (var2)) +#endif diff --git a/mk4/modimage/jdhuff.h b/mk4/modimage/jdhuff.h new file mode 100644 index 0000000..ae19b6c --- /dev/null +++ b/mk4/modimage/jdhuff.h @@ -0,0 +1,201 @@ +/* + * jdhuff.h + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains declarations for Huffman entropy decoding routines + * that are shared between the sequential decoder (jdhuff.c) and the + * progressive decoder (jdphuff.c). No other modules need to see these. + */ + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_make_d_derived_tbl jMkDDerived +#define jpeg_fill_bit_buffer jFilBitBuf +#define jpeg_huff_decode jHufDecode +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* Derived data constructed for each Huffman table */ + +#define HUFF_LOOKAHEAD 8 /* # of bits of lookahead */ + +typedef struct { + /* Basic tables: (element [0] of each array is unused) */ + INT32 maxcode[18]; /* largest code of length k (-1 if none) */ + /* (maxcode[17] is a sentinel to ensure jpeg_huff_decode terminates) */ + INT32 valoffset[17]; /* huffval[] offset for codes of length k */ + /* valoffset[k] = huffval[] index of 1st symbol of code length k, less + * the smallest code of length k; so given a code of length k, the + * corresponding symbol is huffval[code + valoffset[k]] + */ + + /* Link to public Huffman table (needed only in jpeg_huff_decode) */ + JHUFF_TBL *pub; + + /* Lookahead tables: indexed by the next HUFF_LOOKAHEAD bits of + * the input data stream. If the next Huffman code is no more + * than HUFF_LOOKAHEAD bits long, we can obtain its length and + * the corresponding symbol directly from these tables. + */ + int look_nbits[1< 32 bits on your machine, and shifting/masking longs is + * reasonably fast, making bit_buf_type be long and setting BIT_BUF_SIZE + * appropriately should be a win. Unfortunately we can't define the size + * with something like #define BIT_BUF_SIZE (sizeof(bit_buf_type)*8) + * because not all machines measure sizeof in 8-bit bytes. + */ + +typedef struct { /* Bitreading state saved across MCUs */ + bit_buf_type get_buffer; /* current bit-extraction buffer */ + int bits_left; /* # of unused bits in it */ +} bitread_perm_state; + +typedef struct { /* Bitreading working state within an MCU */ + /* Current data source location */ + /* We need a copy, rather than munging the original, in case of suspension */ + const JOCTET * next_input_byte; /* => next byte to read from source */ + size_t bytes_in_buffer; /* # of bytes remaining in source buffer */ + /* Bit input buffer --- note these values are kept in register variables, + * not in this struct, inside the inner loops. + */ + bit_buf_type get_buffer; /* current bit-extraction buffer */ + int bits_left; /* # of unused bits in it */ + /* Pointer needed by jpeg_fill_bit_buffer. */ + j_decompress_ptr cinfo; /* back link to decompress master record */ +} bitread_working_state; + +/* Macros to declare and load/save bitread local variables. */ +#define BITREAD_STATE_VARS \ + register bit_buf_type get_buffer; \ + register int bits_left; \ + bitread_working_state br_state + +#define BITREAD_LOAD_STATE(cinfop,permstate) \ + br_state.cinfo = cinfop; \ + br_state.next_input_byte = cinfop->src->next_input_byte; \ + br_state.bytes_in_buffer = cinfop->src->bytes_in_buffer; \ + get_buffer = permstate.get_buffer; \ + bits_left = permstate.bits_left; + +#define BITREAD_SAVE_STATE(cinfop,permstate) \ + cinfop->src->next_input_byte = br_state.next_input_byte; \ + cinfop->src->bytes_in_buffer = br_state.bytes_in_buffer; \ + permstate.get_buffer = get_buffer; \ + permstate.bits_left = bits_left + +/* + * These macros provide the in-line portion of bit fetching. + * Use CHECK_BIT_BUFFER to ensure there are N bits in get_buffer + * before using GET_BITS, PEEK_BITS, or DROP_BITS. + * The variables get_buffer and bits_left are assumed to be locals, + * but the state struct might not be (jpeg_huff_decode needs this). + * CHECK_BIT_BUFFER(state,n,action); + * Ensure there are N bits in get_buffer; if suspend, take action. + * val = GET_BITS(n); + * Fetch next N bits. + * val = PEEK_BITS(n); + * Fetch next N bits without removing them from the buffer. + * DROP_BITS(n); + * Discard next N bits. + * The value N should be a simple variable, not an expression, because it + * is evaluated multiple times. + */ + +#define CHECK_BIT_BUFFER(state,nbits,action) \ + { if (bits_left < (nbits)) { \ + if (! jpeg_fill_bit_buffer(&(state),get_buffer,bits_left,nbits)) \ + { action; } \ + get_buffer = (state).get_buffer; bits_left = (state).bits_left; } } + +#define GET_BITS(nbits) \ + (((int) (get_buffer >> (bits_left -= (nbits)))) & ((1<<(nbits))-1)) + +#define PEEK_BITS(nbits) \ + (((int) (get_buffer >> (bits_left - (nbits)))) & ((1<<(nbits))-1)) + +#define DROP_BITS(nbits) \ + (bits_left -= (nbits)) + +/* Load up the bit buffer to a depth of at least nbits */ +EXTERN(boolean) jpeg_fill_bit_buffer + JPP((bitread_working_state * state, register bit_buf_type get_buffer, + register int bits_left, int nbits)); + + +/* + * Code for extracting next Huffman-coded symbol from input bit stream. + * Again, this is time-critical and we make the main paths be macros. + * + * We use a lookahead table to process codes of up to HUFF_LOOKAHEAD bits + * without looping. Usually, more than 95% of the Huffman codes will be 8 + * or fewer bits long. The few overlength codes are handled with a loop, + * which need not be inline code. + * + * Notes about the HUFF_DECODE macro: + * 1. Near the end of the data segment, we may fail to get enough bits + * for a lookahead. In that case, we do it the hard way. + * 2. If the lookahead table contains no entry, the next code must be + * more than HUFF_LOOKAHEAD bits long. + * 3. jpeg_huff_decode returns -1 if forced to suspend. + */ + +#define HUFF_DECODE(result,state,htbl,failaction,slowlabel) \ +{ register int nb, look; \ + if (bits_left < HUFF_LOOKAHEAD) { \ + if (! jpeg_fill_bit_buffer(&state,get_buffer,bits_left, 0)) {failaction;} \ + get_buffer = state.get_buffer; bits_left = state.bits_left; \ + if (bits_left < HUFF_LOOKAHEAD) { \ + nb = 1; goto slowlabel; \ + } \ + } \ + look = PEEK_BITS(HUFF_LOOKAHEAD); \ + if ((nb = htbl->look_nbits[look]) != 0) { \ + DROP_BITS(nb); \ + result = htbl->look_sym[look]; \ + } else { \ + nb = HUFF_LOOKAHEAD+1; \ +slowlabel: \ + if ((result=jpeg_huff_decode(&state,get_buffer,bits_left,htbl,nb)) < 0) \ + { failaction; } \ + get_buffer = state.get_buffer; bits_left = state.bits_left; \ + } \ +} + +/* Out-of-line case for Huffman code fetching */ +EXTERN(int) jpeg_huff_decode + JPP((bitread_working_state * state, register bit_buf_type get_buffer, + register int bits_left, d_derived_tbl * htbl, int min_bits)); diff --git a/mk4/modimage/jerror.h b/mk4/modimage/jerror.h new file mode 100644 index 0000000..fc2fffe --- /dev/null +++ b/mk4/modimage/jerror.h @@ -0,0 +1,291 @@ +/* + * jerror.h + * + * Copyright (C) 1994-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file defines the error and message codes for the JPEG library. + * Edit this file to add new codes, or to translate the message strings to + * some other language. + * A set of error-reporting macros are defined too. Some applications using + * the JPEG library may wish to include this file to get the error codes + * and/or the macros. + */ + +/* + * To define the enum list of message codes, include this file without + * defining macro JMESSAGE. To create a message string table, include it + * again with a suitable JMESSAGE definition (see jerror.c for an example). + */ +#ifndef JMESSAGE +#ifndef JERROR_H +/* First time through, define the enum list */ +#define JMAKE_ENUM_LIST +#else +/* Repeated inclusions of this file are no-ops unless JMESSAGE is defined */ +#define JMESSAGE(code,string) +#endif /* JERROR_H */ +#endif /* JMESSAGE */ + +#ifdef JMAKE_ENUM_LIST + +typedef enum { + +#define JMESSAGE(code,string) code , + +#endif /* JMAKE_ENUM_LIST */ + +JMESSAGE(JMSG_NOMESSAGE, "Bogus message code %d") /* Must be first entry! */ + +/* For maintenance convenience, list is alphabetical by message code name */ +JMESSAGE(JERR_ARITH_NOTIMPL, + "Sorry, there are legal restrictions on arithmetic coding") +JMESSAGE(JERR_BAD_ALIGN_TYPE, "ALIGN_TYPE is wrong, please fix") +JMESSAGE(JERR_BAD_ALLOC_CHUNK, "MAX_ALLOC_CHUNK is wrong, please fix") +JMESSAGE(JERR_BAD_BUFFER_MODE, "Bogus buffer control mode") +JMESSAGE(JERR_BAD_COMPONENT_ID, "Invalid component ID %d in SOS") +JMESSAGE(JERR_BAD_DCT_COEF, "DCT coefficient out of range") +JMESSAGE(JERR_BAD_DCTSIZE, "IDCT output block size %d not supported") +JMESSAGE(JERR_BAD_HUFF_TABLE, "Bogus Huffman table definition") +JMESSAGE(JERR_BAD_IN_COLORSPACE, "Bogus input colorspace") +JMESSAGE(JERR_BAD_J_COLORSPACE, "Bogus JPEG colorspace") +JMESSAGE(JERR_BAD_LENGTH, "Bogus marker length") +JMESSAGE(JERR_BAD_LIB_VERSION, + "Wrong JPEG library version: library is %d, caller expects %d") +JMESSAGE(JERR_BAD_MCU_SIZE, "Sampling factors too large for interleaved scan") +JMESSAGE(JERR_BAD_POOL_ID, "Invalid memory pool code %d") +JMESSAGE(JERR_BAD_PRECISION, "Unsupported JPEG data precision %d") +JMESSAGE(JERR_BAD_PROGRESSION, + "Invalid progressive parameters Ss=%d Se=%d Ah=%d Al=%d") +JMESSAGE(JERR_BAD_PROG_SCRIPT, + "Invalid progressive parameters at scan script entry %d") +JMESSAGE(JERR_BAD_SAMPLING, "Bogus sampling factors") +JMESSAGE(JERR_BAD_SCAN_SCRIPT, "Invalid scan script at entry %d") +JMESSAGE(JERR_BAD_STATE, "Improper call to JPEG library in state %d") +JMESSAGE(JERR_BAD_STRUCT_SIZE, + "JPEG parameter struct mismatch: library thinks size is %u, caller expects %u") +JMESSAGE(JERR_BAD_VIRTUAL_ACCESS, "Bogus virtual array access") +JMESSAGE(JERR_BUFFER_SIZE, "Buffer passed to JPEG library is too small") +JMESSAGE(JERR_CANT_SUSPEND, "Suspension not allowed here") +JMESSAGE(JERR_CCIR601_NOTIMPL, "CCIR601 sampling not implemented yet") +JMESSAGE(JERR_COMPONENT_COUNT, "Too many color components: %d, max %d") +JMESSAGE(JERR_CONVERSION_NOTIMPL, "Unsupported color conversion request") +JMESSAGE(JERR_DAC_INDEX, "Bogus DAC index %d") +JMESSAGE(JERR_DAC_VALUE, "Bogus DAC value 0x%x") +JMESSAGE(JERR_DHT_INDEX, "Bogus DHT index %d") +JMESSAGE(JERR_DQT_INDEX, "Bogus DQT index %d") +JMESSAGE(JERR_EMPTY_IMAGE, "Empty JPEG image (DNL not supported)") +JMESSAGE(JERR_EMS_READ, "Read from EMS failed") +JMESSAGE(JERR_EMS_WRITE, "Write to EMS failed") +JMESSAGE(JERR_EOI_EXPECTED, "Didn't expect more than one scan") +JMESSAGE(JERR_FILE_READ, "Input file read error") +JMESSAGE(JERR_FILE_WRITE, "Output file write error --- out of disk space?") +JMESSAGE(JERR_FRACT_SAMPLE_NOTIMPL, "Fractional sampling not implemented yet") +JMESSAGE(JERR_HUFF_CLEN_OVERFLOW, "Huffman code size table overflow") +JMESSAGE(JERR_HUFF_MISSING_CODE, "Missing Huffman code table entry") +JMESSAGE(JERR_IMAGE_TOO_BIG, "Maximum supported image dimension is %u pixels") +JMESSAGE(JERR_INPUT_EMPTY, "Empty input file") +JMESSAGE(JERR_INPUT_EOF, "Premature end of input file") +JMESSAGE(JERR_MISMATCHED_QUANT_TABLE, + "Cannot transcode due to multiple use of quantization table %d") +JMESSAGE(JERR_MISSING_DATA, "Scan script does not transmit all data") +JMESSAGE(JERR_MODE_CHANGE, "Invalid color quantization mode change") +JMESSAGE(JERR_NOTIMPL, "Not implemented yet") +JMESSAGE(JERR_NOT_COMPILED, "Requested feature was omitted at compile time") +JMESSAGE(JERR_NO_BACKING_STORE, "Backing store not supported") +JMESSAGE(JERR_NO_HUFF_TABLE, "Huffman table 0x%02x was not defined") +JMESSAGE(JERR_NO_IMAGE, "JPEG datastream contains no image") +JMESSAGE(JERR_NO_QUANT_TABLE, "Quantization table 0x%02x was not defined") +JMESSAGE(JERR_NO_SOI, "Not a JPEG file: starts with 0x%02x 0x%02x") +JMESSAGE(JERR_OUT_OF_MEMORY, "Insufficient memory (case %d)") +JMESSAGE(JERR_QUANT_COMPONENTS, + "Cannot quantize more than %d color components") +JMESSAGE(JERR_QUANT_FEW_COLORS, "Cannot quantize to fewer than %d colors") +JMESSAGE(JERR_QUANT_MANY_COLORS, "Cannot quantize to more than %d colors") +JMESSAGE(JERR_SOF_DUPLICATE, "Invalid JPEG file structure: two SOF markers") +JMESSAGE(JERR_SOF_NO_SOS, "Invalid JPEG file structure: missing SOS marker") +JMESSAGE(JERR_SOF_UNSUPPORTED, "Unsupported JPEG process: SOF type 0x%02x") +JMESSAGE(JERR_SOI_DUPLICATE, "Invalid JPEG file structure: two SOI markers") +JMESSAGE(JERR_SOS_NO_SOF, "Invalid JPEG file structure: SOS before SOF") +JMESSAGE(JERR_TFILE_CREATE, "Failed to create temporary file %s") +JMESSAGE(JERR_TFILE_READ, "Read failed on temporary file") +JMESSAGE(JERR_TFILE_SEEK, "Seek failed on temporary file") +JMESSAGE(JERR_TFILE_WRITE, + "Write failed on temporary file --- out of disk space?") +JMESSAGE(JERR_TOO_LITTLE_DATA, "Application transferred too few scanlines") +JMESSAGE(JERR_UNKNOWN_MARKER, "Unsupported marker type 0x%02x") +JMESSAGE(JERR_VIRTUAL_BUG, "Virtual array controller messed up") +JMESSAGE(JERR_WIDTH_OVERFLOW, "Image too wide for this implementation") +JMESSAGE(JERR_XMS_READ, "Read from XMS failed") +JMESSAGE(JERR_XMS_WRITE, "Write to XMS failed") +JMESSAGE(JMSG_COPYRIGHT, JCOPYRIGHT) +JMESSAGE(JMSG_VERSION, JVERSION) +JMESSAGE(JTRC_16BIT_TABLES, + "Caution: quantization tables are too coarse for baseline JPEG") +JMESSAGE(JTRC_ADOBE, + "Adobe APP14 marker: version %d, flags 0x%04x 0x%04x, transform %d") +JMESSAGE(JTRC_APP0, "Unknown APP0 marker (not JFIF), length %u") +JMESSAGE(JTRC_APP14, "Unknown APP14 marker (not Adobe), length %u") +JMESSAGE(JTRC_DAC, "Define Arithmetic Table 0x%02x: 0x%02x") +JMESSAGE(JTRC_DHT, "Define Huffman Table 0x%02x") +JMESSAGE(JTRC_DQT, "Define Quantization Table %d precision %d") +JMESSAGE(JTRC_DRI, "Define Restart Interval %u") +JMESSAGE(JTRC_EMS_CLOSE, "Freed EMS handle %u") +JMESSAGE(JTRC_EMS_OPEN, "Obtained EMS handle %u") +JMESSAGE(JTRC_EOI, "End Of Image") +JMESSAGE(JTRC_HUFFBITS, " %3d %3d %3d %3d %3d %3d %3d %3d") +JMESSAGE(JTRC_JFIF, "JFIF APP0 marker: version %d.%02d, density %dx%d %d") +JMESSAGE(JTRC_JFIF_BADTHUMBNAILSIZE, + "Warning: thumbnail image size does not match data length %u") +JMESSAGE(JTRC_JFIF_EXTENSION, + "JFIF extension marker: type 0x%02x, length %u") +JMESSAGE(JTRC_JFIF_THUMBNAIL, " with %d x %d thumbnail image") +JMESSAGE(JTRC_MISC_MARKER, "Miscellaneous marker 0x%02x, length %u") +JMESSAGE(JTRC_PARMLESS_MARKER, "Unexpected marker 0x%02x") +JMESSAGE(JTRC_QUANTVALS, " %4u %4u %4u %4u %4u %4u %4u %4u") +JMESSAGE(JTRC_QUANT_3_NCOLORS, "Quantizing to %d = %d*%d*%d colors") +JMESSAGE(JTRC_QUANT_NCOLORS, "Quantizing to %d colors") +JMESSAGE(JTRC_QUANT_SELECTED, "Selected %d colors for quantization") +JMESSAGE(JTRC_RECOVERY_ACTION, "At marker 0x%02x, recovery action %d") +JMESSAGE(JTRC_RST, "RST%d") +JMESSAGE(JTRC_SMOOTH_NOTIMPL, + "Smoothing not supported with nonstandard sampling ratios") +JMESSAGE(JTRC_SOF, "Start Of Frame 0x%02x: width=%u, height=%u, components=%d") +JMESSAGE(JTRC_SOF_COMPONENT, " Component %d: %dhx%dv q=%d") +JMESSAGE(JTRC_SOI, "Start of Image") +JMESSAGE(JTRC_SOS, "Start Of Scan: %d components") +JMESSAGE(JTRC_SOS_COMPONENT, " Component %d: dc=%d ac=%d") +JMESSAGE(JTRC_SOS_PARAMS, " Ss=%d, Se=%d, Ah=%d, Al=%d") +JMESSAGE(JTRC_TFILE_CLOSE, "Closed temporary file %s") +JMESSAGE(JTRC_TFILE_OPEN, "Opened temporary file %s") +JMESSAGE(JTRC_THUMB_JPEG, + "JFIF extension marker: JPEG-compressed thumbnail image, length %u") +JMESSAGE(JTRC_THUMB_PALETTE, + "JFIF extension marker: palette thumbnail image, length %u") +JMESSAGE(JTRC_THUMB_RGB, + "JFIF extension marker: RGB thumbnail image, length %u") +JMESSAGE(JTRC_UNKNOWN_IDS, + "Unrecognized component IDs %d %d %d, assuming YCbCr") +JMESSAGE(JTRC_XMS_CLOSE, "Freed XMS handle %u") +JMESSAGE(JTRC_XMS_OPEN, "Obtained XMS handle %u") +JMESSAGE(JWRN_ADOBE_XFORM, "Unknown Adobe color transform code %d") +JMESSAGE(JWRN_BOGUS_PROGRESSION, + "Inconsistent progression sequence for component %d coefficient %d") +JMESSAGE(JWRN_EXTRANEOUS_DATA, + "Corrupt JPEG data: %u extraneous bytes before marker 0x%02x") +JMESSAGE(JWRN_HIT_MARKER, "Corrupt JPEG data: premature end of data segment") +JMESSAGE(JWRN_HUFF_BAD_CODE, "Corrupt JPEG data: bad Huffman code") +JMESSAGE(JWRN_JFIF_MAJOR, "Warning: unknown JFIF revision number %d.%02d") +JMESSAGE(JWRN_JPEG_EOF, "Premature end of JPEG file") +JMESSAGE(JWRN_MUST_RESYNC, + "Corrupt JPEG data: found marker 0x%02x instead of RST%d") +JMESSAGE(JWRN_NOT_SEQUENTIAL, "Invalid SOS parameters for sequential JPEG") +JMESSAGE(JWRN_TOO_MUCH_DATA, "Application transferred too many scanlines") + +#ifdef JMAKE_ENUM_LIST + + JMSG_LASTMSGCODE +} J_MESSAGE_CODE; + +#undef JMAKE_ENUM_LIST +#endif /* JMAKE_ENUM_LIST */ + +/* Zap JMESSAGE macro so that future re-inclusions do nothing by default */ +#undef JMESSAGE + + +#ifndef JERROR_H +#define JERROR_H + +/* Macros to simplify using the error and trace message stuff */ +/* The first parameter is either type of cinfo pointer */ + +/* Fatal errors (print message and exit) */ +#define ERREXIT(cinfo,code) \ + ((cinfo)->err->msg_code = (code), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT1(cinfo,code,p1) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT2(cinfo,code,p1,p2) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT3(cinfo,code,p1,p2,p3) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (cinfo)->err->msg_parm.i[2] = (p3), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT4(cinfo,code,p1,p2,p3,p4) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (cinfo)->err->msg_parm.i[2] = (p3), \ + (cinfo)->err->msg_parm.i[3] = (p4), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXITS(cinfo,code,str) \ + ((cinfo)->err->msg_code = (code), \ + strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) + +#define MAKESTMT(stuff) do { stuff } while (0) + +/* Nonfatal errors (we can keep going, but the data is probably corrupt) */ +#define WARNMS(cinfo,code) \ + ((cinfo)->err->msg_code = (code), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1)) +#define WARNMS1(cinfo,code,p1) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1)) +#define WARNMS2(cinfo,code,p1,p2) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1)) + +/* Informational/debugging messages */ +#define TRACEMS(cinfo,lvl,code) \ + ((cinfo)->err->msg_code = (code), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) +#define TRACEMS1(cinfo,lvl,code,p1) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) +#define TRACEMS2(cinfo,lvl,code,p1,p2) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) +#define TRACEMS3(cinfo,lvl,code,p1,p2,p3) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMS4(cinfo,lvl,code,p1,p2,p3,p4) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMS5(cinfo,lvl,code,p1,p2,p3,p4,p5) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \ + _mp[4] = (p5); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMS8(cinfo,lvl,code,p1,p2,p3,p4,p5,p6,p7,p8) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \ + _mp[4] = (p5); _mp[5] = (p6); _mp[6] = (p7); _mp[7] = (p8); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMSS(cinfo,lvl,code,str) \ + ((cinfo)->err->msg_code = (code), \ + strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) + +#endif /* JERROR_H */ diff --git a/mk4/modimage/jinclude.h b/mk4/modimage/jinclude.h new file mode 100644 index 0000000..0a4f151 --- /dev/null +++ b/mk4/modimage/jinclude.h @@ -0,0 +1,91 @@ +/* + * jinclude.h + * + * Copyright (C) 1991-1994, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file exists to provide a single place to fix any problems with + * including the wrong system include files. (Common problems are taken + * care of by the standard jconfig symbols, but on really weird systems + * you may have to edit this file.) + * + * NOTE: this file is NOT intended to be included by applications using the + * JPEG library. Most applications need only include jpeglib.h. + */ + + +/* Include auto-config file to find out which system include files we need. */ + +#include "jconfig.h" /* auto configuration options */ +#define JCONFIG_INCLUDED /* so that jpeglib.h doesn't do it again */ + +/* + * We need the NULL macro and size_t typedef. + * On an ANSI-conforming system it is sufficient to include . + * Otherwise, we get them from or ; we may have to + * pull in as well. + * Note that the core JPEG library does not require ; + * only the default error handler and data source/destination modules do. + * But we must pull it in because of the references to FILE in jpeglib.h. + * You can remove those references if you want to compile without . + */ + +#ifdef HAVE_STDDEF_H +#include +#endif + +#ifdef HAVE_STDLIB_H +#include +#endif + +#ifdef NEED_SYS_TYPES_H +#include +#endif + +#include + +/* + * We need memory copying and zeroing functions, plus strncpy(). + * ANSI and System V implementations declare these in . + * BSD doesn't have the mem() functions, but it does have bcopy()/bzero(). + * Some systems may declare memset and memcpy in . + * + * NOTE: we assume the size parameters to these functions are of type size_t. + * Change the casts in these macros if not! + */ + +#ifdef NEED_BSD_STRINGS + +#include +#define MEMZERO(target,size) bzero((void *)(target), (size_t)(size)) +#define MEMCOPY(dest,src,size) bcopy((const void *)(src), (void *)(dest), (size_t)(size)) + +#else /* not BSD, assume ANSI/SysV string lib */ + +#include +#define MEMZERO(target,size) memset((void *)(target), 0, (size_t)(size)) +#define MEMCOPY(dest,src,size) memcpy((void *)(dest), (const void *)(src), (size_t)(size)) + +#endif + +/* + * In ANSI C, and indeed any rational implementation, size_t is also the + * type returned by sizeof(). However, it seems there are some irrational + * implementations out there, in which sizeof() returns an int even though + * size_t is defined as long or unsigned long. To ensure consistent results + * we always use this SIZEOF() macro in place of using sizeof() directly. + */ + +#define SIZEOF(object) ((size_t) sizeof(object)) + +/* + * The modules that use fread() and fwrite() always invoke them through + * these macros. On some systems you may need to twiddle the argument casts. + * CAUTION: argument order is different from underlying functions! + */ + +#define JFREAD(file,buf,sizeofbuf) \ + ((size_t) fread((void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) +#define JFWRITE(file,buf,sizeofbuf) \ + ((size_t) fwrite((const void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) diff --git a/mk4/modimage/jmemsys.h b/mk4/modimage/jmemsys.h new file mode 100644 index 0000000..6c3c6d3 --- /dev/null +++ b/mk4/modimage/jmemsys.h @@ -0,0 +1,198 @@ +/* + * jmemsys.h + * + * Copyright (C) 1992-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This include file defines the interface between the system-independent + * and system-dependent portions of the JPEG memory manager. No other + * modules need include it. (The system-independent portion is jmemmgr.c; + * there are several different versions of the system-dependent portion.) + * + * This file works as-is for the system-dependent memory managers supplied + * in the IJG distribution. You may need to modify it if you write a + * custom memory manager. If system-dependent changes are needed in + * this file, the best method is to #ifdef them based on a configuration + * symbol supplied in jconfig.h, as we have done with USE_MSDOS_MEMMGR + * and USE_MAC_MEMMGR. + */ + + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_get_small jGetSmall +#define jpeg_free_small jFreeSmall +#define jpeg_get_large jGetLarge +#define jpeg_free_large jFreeLarge +#define jpeg_mem_available jMemAvail +#define jpeg_open_backing_store jOpenBackStore +#define jpeg_mem_init jMemInit +#define jpeg_mem_term jMemTerm +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* + * These two functions are used to allocate and release small chunks of + * memory. (Typically the total amount requested through jpeg_get_small is + * no more than 20K or so; this will be requested in chunks of a few K each.) + * Behavior should be the same as for the standard library functions malloc + * and free; in particular, jpeg_get_small must return NULL on failure. + * On most systems, these ARE malloc and free. jpeg_free_small is passed the + * size of the object being freed, just in case it's needed. + * On an 80x86 machine using small-data memory model, these manage near heap. + */ + +EXTERN(void *) jpeg_get_small JPP((j_common_ptr cinfo, size_t sizeofobject)); +EXTERN(void) jpeg_free_small JPP((j_common_ptr cinfo, void * object, + size_t sizeofobject)); + +/* + * These two functions are used to allocate and release large chunks of + * memory (up to the total free space designated by jpeg_mem_available). + * The interface is the same as above, except that on an 80x86 machine, + * far pointers are used. On most other machines these are identical to + * the jpeg_get/free_small routines; but we keep them separate anyway, + * in case a different allocation strategy is desirable for large chunks. + */ + +EXTERN(void FAR *) jpeg_get_large JPP((j_common_ptr cinfo, + size_t sizeofobject)); +EXTERN(void) jpeg_free_large JPP((j_common_ptr cinfo, void FAR * object, + size_t sizeofobject)); + +/* + * The macro MAX_ALLOC_CHUNK designates the maximum number of bytes that may + * be requested in a single call to jpeg_get_large (and jpeg_get_small for that + * matter, but that case should never come into play). This macro is needed + * to model the 64Kb-segment-size limit of far addressing on 80x86 machines. + * On those machines, we expect that jconfig.h will provide a proper value. + * On machines with 32-bit flat address spaces, any large constant may be used. + * + * NB: jmemmgr.c expects that MAX_ALLOC_CHUNK will be representable as type + * size_t and will be a multiple of sizeof(align_type). + */ + +#ifndef MAX_ALLOC_CHUNK /* may be overridden in jconfig.h */ +#define MAX_ALLOC_CHUNK 1000000000L +#endif + +/* + * This routine computes the total space still available for allocation by + * jpeg_get_large. If more space than this is needed, backing store will be + * used. NOTE: any memory already allocated must not be counted. + * + * There is a minimum space requirement, corresponding to the minimum + * feasible buffer sizes; jmemmgr.c will request that much space even if + * jpeg_mem_available returns zero. The maximum space needed, enough to hold + * all working storage in memory, is also passed in case it is useful. + * Finally, the total space already allocated is passed. If no better + * method is available, cinfo->mem->max_memory_to_use - already_allocated + * is often a suitable calculation. + * + * It is OK for jpeg_mem_available to underestimate the space available + * (that'll just lead to more backing-store access than is really necessary). + * However, an overestimate will lead to failure. Hence it's wise to subtract + * a slop factor from the true available space. 5% should be enough. + * + * On machines with lots of virtual memory, any large constant may be returned. + * Conversely, zero may be returned to always use the minimum amount of memory. + */ + +EXTERN(long) jpeg_mem_available JPP((j_common_ptr cinfo, + long min_bytes_needed, + long max_bytes_needed, + long already_allocated)); + + +/* + * This structure holds whatever state is needed to access a single + * backing-store object. The read/write/close method pointers are called + * by jmemmgr.c to manipulate the backing-store object; all other fields + * are private to the system-dependent backing store routines. + */ + +#define TEMP_NAME_LENGTH 64 /* max length of a temporary file's name */ + + +#ifdef USE_MSDOS_MEMMGR /* DOS-specific junk */ + +typedef unsigned short XMSH; /* type of extended-memory handles */ +typedef unsigned short EMSH; /* type of expanded-memory handles */ + +typedef union { + short file_handle; /* DOS file handle if it's a temp file */ + XMSH xms_handle; /* handle if it's a chunk of XMS */ + EMSH ems_handle; /* handle if it's a chunk of EMS */ +} handle_union; + +#endif /* USE_MSDOS_MEMMGR */ + +#ifdef USE_MAC_MEMMGR /* Mac-specific junk */ +#include +#endif /* USE_MAC_MEMMGR */ + + +typedef struct backing_store_struct * backing_store_ptr; + +typedef struct backing_store_struct { + /* Methods for reading/writing/closing this backing-store object */ + JMETHOD(void, read_backing_store, (j_common_ptr cinfo, + backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count)); + JMETHOD(void, write_backing_store, (j_common_ptr cinfo, + backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count)); + JMETHOD(void, close_backing_store, (j_common_ptr cinfo, + backing_store_ptr info)); + + /* Private fields for system-dependent backing-store management */ +#ifdef USE_MSDOS_MEMMGR + /* For the MS-DOS manager (jmemdos.c), we need: */ + handle_union handle; /* reference to backing-store storage object */ + char temp_name[TEMP_NAME_LENGTH]; /* name if it's a file */ +#else +#ifdef USE_MAC_MEMMGR + /* For the Mac manager (jmemmac.c), we need: */ + short temp_file; /* file reference number to temp file */ + FSSpec tempSpec; /* the FSSpec for the temp file */ + char temp_name[TEMP_NAME_LENGTH]; /* name if it's a file */ +#else + /* For a typical implementation with temp files, we need: */ + FILE * temp_file; /* stdio reference to temp file */ + char temp_name[TEMP_NAME_LENGTH]; /* name of temp file */ +#endif +#endif +} backing_store_info; + + +/* + * Initial opening of a backing-store object. This must fill in the + * read/write/close pointers in the object. The read/write routines + * may take an error exit if the specified maximum file size is exceeded. + * (If jpeg_mem_available always returns a large value, this routine can + * just take an error exit.) + */ + +EXTERN(void) jpeg_open_backing_store JPP((j_common_ptr cinfo, + backing_store_ptr info, + long total_bytes_needed)); + + +/* + * These routines take care of any system-dependent initialization and + * cleanup required. jpeg_mem_init will be called before anything is + * allocated (and, therefore, nothing in cinfo is of use except the error + * manager pointer). It should return a suitable default value for + * max_memory_to_use; this may subsequently be overridden by the surrounding + * application. (Note that max_memory_to_use is only important if + * jpeg_mem_available chooses to consult it ... no one else will.) + * jpeg_mem_term may assume that all requested memory has been freed and that + * all opened backing-store objects have been closed. + */ + +EXTERN(long) jpeg_mem_init JPP((j_common_ptr cinfo)); +EXTERN(void) jpeg_mem_term JPP((j_common_ptr cinfo)); diff --git a/mk4/modimage/jmorecfg.h b/mk4/modimage/jmorecfg.h new file mode 100644 index 0000000..54a7d1c --- /dev/null +++ b/mk4/modimage/jmorecfg.h @@ -0,0 +1,363 @@ +/* + * jmorecfg.h + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains additional configuration options that customize the + * JPEG software for special applications or support machine-dependent + * optimizations. Most users will not need to touch this file. + */ + + +/* + * Define BITS_IN_JSAMPLE as either + * 8 for 8-bit sample values (the usual setting) + * 12 for 12-bit sample values + * Only 8 and 12 are legal data precisions for lossy JPEG according to the + * JPEG standard, and the IJG code does not support anything else! + * We do not support run-time selection of data precision, sorry. + */ + +#define BITS_IN_JSAMPLE 8 /* use 8 or 12 */ + + +/* + * Maximum number of components (color channels) allowed in JPEG image. + * To meet the letter of the JPEG spec, set this to 255. However, darn + * few applications need more than 4 channels (maybe 5 for CMYK + alpha + * mask). We recommend 10 as a reasonable compromise; use 4 if you are + * really short on memory. (Each allowed component costs a hundred or so + * bytes of storage, whether actually used in an image or not.) + */ + +#define MAX_COMPONENTS 10 /* maximum number of image components */ + + +/* + * Basic data types. + * You may need to change these if you have a machine with unusual data + * type sizes; for example, "char" not 8 bits, "short" not 16 bits, + * or "long" not 32 bits. We don't care whether "int" is 16 or 32 bits, + * but it had better be at least 16. + */ + +/* Representation of a single sample (pixel element value). + * We frequently allocate large arrays of these, so it's important to keep + * them small. But if you have memory to burn and access to char or short + * arrays is very slow on your hardware, you might want to change these. + */ + +#if BITS_IN_JSAMPLE == 8 +/* JSAMPLE should be the smallest type that will hold the values 0..255. + * You can use a signed char by having GETJSAMPLE mask it with 0xFF. + */ + +#ifdef HAVE_UNSIGNED_CHAR + +typedef unsigned char JSAMPLE; +#define GETJSAMPLE(value) ((int) (value)) + +#else /* not HAVE_UNSIGNED_CHAR */ + +typedef char JSAMPLE; +#ifdef CHAR_IS_UNSIGNED +#define GETJSAMPLE(value) ((int) (value)) +#else +#define GETJSAMPLE(value) ((int) (value) & 0xFF) +#endif /* CHAR_IS_UNSIGNED */ + +#endif /* HAVE_UNSIGNED_CHAR */ + +#define MAXJSAMPLE 255 +#define CENTERJSAMPLE 128 + +#endif /* BITS_IN_JSAMPLE == 8 */ + + +#if BITS_IN_JSAMPLE == 12 +/* JSAMPLE should be the smallest type that will hold the values 0..4095. + * On nearly all machines "short" will do nicely. + */ + +typedef short JSAMPLE; +#define GETJSAMPLE(value) ((int) (value)) + +#define MAXJSAMPLE 4095 +#define CENTERJSAMPLE 2048 + +#endif /* BITS_IN_JSAMPLE == 12 */ + + +/* Representation of a DCT frequency coefficient. + * This should be a signed value of at least 16 bits; "short" is usually OK. + * Again, we allocate large arrays of these, but you can change to int + * if you have memory to burn and "short" is really slow. + */ + +typedef short JCOEF; + + +/* Compressed datastreams are represented as arrays of JOCTET. + * These must be EXACTLY 8 bits wide, at least once they are written to + * external storage. Note that when using the stdio data source/destination + * managers, this is also the data type passed to fread/fwrite. + */ + +#ifdef HAVE_UNSIGNED_CHAR + +typedef unsigned char JOCTET; +#define GETJOCTET(value) (value) + +#else /* not HAVE_UNSIGNED_CHAR */ + +typedef char JOCTET; +#ifdef CHAR_IS_UNSIGNED +#define GETJOCTET(value) (value) +#else +#define GETJOCTET(value) ((value) & 0xFF) +#endif /* CHAR_IS_UNSIGNED */ + +#endif /* HAVE_UNSIGNED_CHAR */ + + +/* These typedefs are used for various table entries and so forth. + * They must be at least as wide as specified; but making them too big + * won't cost a huge amount of memory, so we don't provide special + * extraction code like we did for JSAMPLE. (In other words, these + * typedefs live at a different point on the speed/space tradeoff curve.) + */ + +/* UINT8 must hold at least the values 0..255. */ + +#ifdef HAVE_UNSIGNED_CHAR +typedef unsigned char UINT8; +#else /* not HAVE_UNSIGNED_CHAR */ +#ifdef CHAR_IS_UNSIGNED +typedef char UINT8; +#else /* not CHAR_IS_UNSIGNED */ +typedef short UINT8; +#endif /* CHAR_IS_UNSIGNED */ +#endif /* HAVE_UNSIGNED_CHAR */ + +/* UINT16 must hold at least the values 0..65535. */ + +#ifdef HAVE_UNSIGNED_SHORT +typedef unsigned short UINT16; +#else /* not HAVE_UNSIGNED_SHORT */ +typedef unsigned int UINT16; +#endif /* HAVE_UNSIGNED_SHORT */ + +/* INT16 must hold at least the values -32768..32767. */ + +#ifndef XMD_H /* X11/xmd.h correctly defines INT16 */ +typedef short INT16; +#endif + +/* INT32 must hold at least signed 32-bit values. */ + +#ifndef XMD_H /* X11/xmd.h correctly defines INT32 */ +typedef long INT32; +#endif + +/* Datatype used for image dimensions. The JPEG standard only supports + * images up to 64K*64K due to 16-bit fields in SOF markers. Therefore + * "unsigned int" is sufficient on all machines. However, if you need to + * handle larger images and you don't mind deviating from the spec, you + * can change this datatype. + */ + +typedef unsigned int JDIMENSION; + +#define JPEG_MAX_DIMENSION 65500L /* a tad under 64K to prevent overflows */ + + +/* These macros are used in all function definitions and extern declarations. + * You could modify them if you need to change function linkage conventions; + * in particular, you'll need to do that to make the library a Windows DLL. + * Another application is to make all functions global for use with debuggers + * or code profilers that require it. + */ + +/* a function called through method pointers: */ +#define METHODDEF(type) static type +/* a function used only in its module: */ +#define LOCAL(type) static type +/* a function referenced thru EXTERNs: */ +#define GLOBAL(type) type +/* a reference to a GLOBAL function: */ +#define EXTERN(type) extern type + + +/* This macro is used to declare a "method", that is, a function pointer. + * We want to supply prototype parameters if the compiler can cope. + * Note that the arglist parameter must be parenthesized! + * Again, you can customize this if you need special linkage keywords. + */ + +#ifdef HAVE_PROTOTYPES +#define JMETHOD(type,methodname,arglist) type (*methodname) arglist +#else +#define JMETHOD(type,methodname,arglist) type (*methodname) () +#endif + + +/* Here is the pseudo-keyword for declaring pointers that must be "far" + * on 80x86 machines. Most of the specialized coding for 80x86 is handled + * by just saying "FAR *" where such a pointer is needed. In a few places + * explicit coding is needed; see uses of the NEED_FAR_POINTERS symbol. + */ + +#ifdef NEED_FAR_POINTERS +#define FAR far +#else +#define FAR +#endif + + +/* + * On a few systems, type boolean and/or its values FALSE, TRUE may appear + * in standard header files. Or you may have conflicts with application- + * specific header files that you want to include together with these files. + * Defining HAVE_BOOLEAN before including jpeglib.h should make it work. + */ + +#ifndef HAVE_BOOLEAN +typedef int boolean; +#endif +#ifndef FALSE /* in case these macros already exist */ +#define FALSE 0 /* values of boolean */ +#endif +#ifndef TRUE +#define TRUE 1 +#endif + + +/* + * The remaining options affect code selection within the JPEG library, + * but they don't need to be visible to most applications using the library. + * To minimize application namespace pollution, the symbols won't be + * defined unless JPEG_INTERNALS or JPEG_INTERNAL_OPTIONS has been defined. + */ + +#ifdef JPEG_INTERNALS +#define JPEG_INTERNAL_OPTIONS +#endif + +#ifdef JPEG_INTERNAL_OPTIONS + + +/* + * These defines indicate whether to include various optional functions. + * Undefining some of these symbols will produce a smaller but less capable + * library. Note that you can leave certain source files out of the + * compilation/linking process if you've #undef'd the corresponding symbols. + * (You may HAVE to do that if your compiler doesn't like null source files.) + */ + +/* Arithmetic coding is unsupported for legal reasons. Complaints to IBM. */ + +/* Capability options common to encoder and decoder: */ + +#define DCT_ISLOW_SUPPORTED /* slow but accurate integer algorithm */ +#define DCT_IFAST_SUPPORTED /* faster, less accurate integer method */ +#define DCT_FLOAT_SUPPORTED /* floating-point: accurate, fast on fast HW */ + +/* Encoder capability options: */ + +#undef C_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */ +#define C_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ +#define C_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/ +#define ENTROPY_OPT_SUPPORTED /* Optimization of entropy coding parms? */ +/* Note: if you selected 12-bit data precision, it is dangerous to turn off + * ENTROPY_OPT_SUPPORTED. The standard Huffman tables are only good for 8-bit + * precision, so jchuff.c normally uses entropy optimization to compute + * usable tables for higher precision. If you don't want to do optimization, + * you'll have to supply different default Huffman tables. + * The exact same statements apply for progressive JPEG: the default tables + * don't work for progressive mode. (This may get fixed, however.) + */ +#define INPUT_SMOOTHING_SUPPORTED /* Input image smoothing option? */ + +/* Decoder capability options: */ + +#undef D_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */ +#define D_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ +#define D_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/ +#define SAVE_MARKERS_SUPPORTED /* jpeg_save_markers() needed? */ +#define BLOCK_SMOOTHING_SUPPORTED /* Block smoothing? (Progressive only) */ +#define IDCT_SCALING_SUPPORTED /* Output rescaling via IDCT? */ +#undef UPSAMPLE_SCALING_SUPPORTED /* Output rescaling at upsample stage? */ +#define UPSAMPLE_MERGING_SUPPORTED /* Fast path for sloppy upsampling? */ +#define QUANT_1PASS_SUPPORTED /* 1-pass color quantization? */ +#define QUANT_2PASS_SUPPORTED /* 2-pass color quantization? */ + +/* more capability options later, no doubt */ + + +/* + * Ordering of RGB data in scanlines passed to or from the application. + * If your application wants to deal with data in the order B,G,R, just + * change these macros. You can also deal with formats such as R,G,B,X + * (one extra byte per pixel) by changing RGB_PIXELSIZE. Note that changing + * the offsets will also change the order in which colormap data is organized. + * RESTRICTIONS: + * 1. The sample applications cjpeg,djpeg do NOT support modified RGB formats. + * 2. These macros only affect RGB<=>YCbCr color conversion, so they are not + * useful if you are using JPEG color spaces other than YCbCr or grayscale. + * 3. The color quantizer modules will not behave desirably if RGB_PIXELSIZE + * is not 3 (they don't understand about dummy color components!). So you + * can't use color quantization if you change that value. + */ + +#define RGB_RED 0 /* Offset of Red in an RGB scanline element */ +#define RGB_GREEN 1 /* Offset of Green */ +#define RGB_BLUE 2 /* Offset of Blue */ +#define RGB_PIXELSIZE 3 /* JSAMPLEs per RGB scanline element */ + + +/* Definitions for speed-related optimizations. */ + + +/* If your compiler supports inline functions, define INLINE + * as the inline keyword; otherwise define it as empty. + */ + +#ifndef INLINE +#ifdef __GNUC__ /* for instance, GNU C knows about inline */ +#define INLINE __inline__ +#endif +#ifndef INLINE +#define INLINE /* default is to define it as empty */ +#endif +#endif + + +/* On some machines (notably 68000 series) "int" is 32 bits, but multiplying + * two 16-bit shorts is faster than multiplying two ints. Define MULTIPLIER + * as short on such a machine. MULTIPLIER must be at least 16 bits wide. + */ + +#ifndef MULTIPLIER +#define MULTIPLIER int /* type for fastest integer multiply */ +#endif + + +/* FAST_FLOAT should be either float or double, whichever is done faster + * by your compiler. (Note that this type is only used in the floating point + * DCT routines, so it only matters if you've defined DCT_FLOAT_SUPPORTED.) + * Typically, float is faster in ANSI C compilers, while double is faster in + * pre-ANSI compilers (because they insist on converting to double anyway). + * The code below therefore chooses float if we have ANSI-style prototypes. + */ + +#ifndef FAST_FLOAT +#ifdef HAVE_PROTOTYPES +#define FAST_FLOAT float +#else +#define FAST_FLOAT double +#endif +#endif + +#endif /* JPEG_INTERNAL_OPTIONS */ diff --git a/mk4/modimage/jpeg-6b/.cvsignore b/mk4/modimage/jpeg-6b/.cvsignore new file mode 100644 index 0000000..eb0845d --- /dev/null +++ b/mk4/modimage/jpeg-6b/.cvsignore @@ -0,0 +1,9 @@ +config.log +jconfig.h +config.status +Makefile +cjpeg +djpeg +jpegtran +rdjpgcom +wrjpgcom diff --git a/mk4/modimage/jpeg-6b/CVS/Entries b/mk4/modimage/jpeg-6b/CVS/Entries new file mode 100644 index 0000000..5c287a9 --- /dev/null +++ b/mk4/modimage/jpeg-6b/CVS/Entries @@ -0,0 +1,141 @@ +/.cvsignore/1.1/Thu Mar 11 01:11:48 2004//Tmk4_mod6_rc2 +/README/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/ansi2knr.1/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/ansi2knr.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/cderror.h/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/cdjpeg.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/cdjpeg.h/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/change.log/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/cjpeg.1/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/cjpeg.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/ckconfig.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/coderules.doc/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/config.guess/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/config.sub/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/configure/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/djpeg.1/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/djpeg.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/example.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/filelist.doc/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/install-sh/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/install.doc/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jcapimin.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jcapistd.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jccoefct.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jccolor.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jcdctmgr.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jchuff.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jchuff.h/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jcinit.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jcmainct.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jcmarker.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jcmaster.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jcomapi.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jconfig.bcc/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jconfig.cfg/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jconfig.dj/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jconfig.doc/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jconfig.mac/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jconfig.manx/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jconfig.mc6/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jconfig.sas/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jconfig.st/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jconfig.vc/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jconfig.vms/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jconfig.wat/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jcparam.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jcphuff.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jcprepct.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jcsample.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jctrans.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jdapimin.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jdapistd.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jdatadst.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jdatasrc.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jdcoefct.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jdcolor.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jdct.h/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jddctmgr.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jdhuff.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jdhuff.h/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jdinput.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jdmainct.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jdmarker.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jdmaster.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jdmerge.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jdphuff.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jdpostct.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jdsample.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jdtrans.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jerror.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jerror.h/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jfdctflt.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jfdctfst.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jfdctint.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jidctflt.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jidctfst.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jidctint.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jidctred.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jinclude.h/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jmemansi.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jmemdos.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jmemdosa.asm/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jmemmac.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jmemmgr.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jmemname.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jmemnobs.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jmemsys.h/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jmorecfg.h/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jpegint.h/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jpeglib.h/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jpegtran.1/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jpegtran.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jquant1.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jquant2.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jutils.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/jversion.h/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/libjpeg.doc/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/ltconfig/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/ltmain.sh/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/makcjpeg.st/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/makdjpeg.st/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/makeapps.ds/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/makefile.ansi/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/makefile.bcc/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/makefile.cfg/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/makefile.dj/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/makefile.manx/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/makefile.mc6/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/makefile.mms/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/makefile.sas/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/makefile.unix/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/makefile.vc/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/makefile.vms/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/makefile.wat/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/makelib.ds/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/makeproj.mac/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/makljpeg.st/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/maktjpeg.st/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/makvms.opt/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/rdbmp.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/rdcolmap.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/rdgif.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/rdjpgcom.1/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/rdjpgcom.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/rdppm.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/rdrle.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/rdswitch.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/rdtarga.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/structure.doc/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/transupp.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/transupp.h/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/usage.doc/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/wizard.doc/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/wrbmp.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/wrgif.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/wrjpgcom.1/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/wrjpgcom.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/wrppm.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/wrrle.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +/wrtarga.c/1.1.1.1/Wed Oct 29 20:52:41 2003//Tmk4_mod6_rc2 +D diff --git a/mk4/modimage/jpeg-6b/CVS/Repository b/mk4/modimage/jpeg-6b/CVS/Repository new file mode 100644 index 0000000..40b4abf --- /dev/null +++ b/mk4/modimage/jpeg-6b/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/modimage/jpeg-6b diff --git a/mk4/modimage/jpeg-6b/CVS/Root b/mk4/modimage/jpeg-6b/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/modimage/jpeg-6b/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/modimage/jpeg-6b/CVS/Tag b/mk4/modimage/jpeg-6b/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/modimage/jpeg-6b/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/modimage/jpeg-6b/README b/mk4/modimage/jpeg-6b/README new file mode 100644 index 0000000..86cc206 --- /dev/null +++ b/mk4/modimage/jpeg-6b/README @@ -0,0 +1,385 @@ +The Independent JPEG Group's JPEG software +========================================== + +README for release 6b of 27-Mar-1998 +==================================== + +This distribution contains the sixth public release of the Independent JPEG +Group's free JPEG software. You are welcome to redistribute this software and +to use it for any purpose, subject to the conditions under LEGAL ISSUES, below. + +Serious users of this software (particularly those incorporating it into +larger programs) should contact IJG at jpeg-info@uunet.uu.net to be added to +our electronic mailing list. Mailing list members are notified of updates +and have a chance to participate in technical discussions, etc. + +This software is the work of Tom Lane, Philip Gladstone, Jim Boucher, +Lee Crocker, Julian Minguillon, Luis Ortiz, George Phillips, Davide Rossi, +Guido Vollbeding, Ge' Weijers, and other members of the Independent JPEG +Group. + +IJG is not affiliated with the official ISO JPEG standards committee. + + +DOCUMENTATION ROADMAP +===================== + +This file contains the following sections: + +OVERVIEW General description of JPEG and the IJG software. +LEGAL ISSUES Copyright, lack of warranty, terms of distribution. +REFERENCES Where to learn more about JPEG. +ARCHIVE LOCATIONS Where to find newer versions of this software. +RELATED SOFTWARE Other stuff you should get. +FILE FORMAT WARS Software *not* to get. +TO DO Plans for future IJG releases. + +Other documentation files in the distribution are: + +User documentation: + install.doc How to configure and install the IJG software. + usage.doc Usage instructions for cjpeg, djpeg, jpegtran, + rdjpgcom, and wrjpgcom. + *.1 Unix-style man pages for programs (same info as usage.doc). + wizard.doc Advanced usage instructions for JPEG wizards only. + change.log Version-to-version change highlights. +Programmer and internal documentation: + libjpeg.doc How to use the JPEG library in your own programs. + example.c Sample code for calling the JPEG library. + structure.doc Overview of the JPEG library's internal structure. + filelist.doc Road map of IJG files. + coderules.doc Coding style rules --- please read if you contribute code. + +Please read at least the files install.doc and usage.doc. Useful information +can also be found in the JPEG FAQ (Frequently Asked Questions) article. See +ARCHIVE LOCATIONS below to find out where to obtain the FAQ article. + +If you want to understand how the JPEG code works, we suggest reading one or +more of the REFERENCES, then looking at the documentation files (in roughly +the order listed) before diving into the code. + + +OVERVIEW +======== + +This package contains C software to implement JPEG image compression and +decompression. JPEG (pronounced "jay-peg") is a standardized compression +method for full-color and gray-scale images. JPEG is intended for compressing +"real-world" scenes; line drawings, cartoons and other non-realistic images +are not its strong suit. JPEG is lossy, meaning that the output image is not +exactly identical to the input image. Hence you must not use JPEG if you +have to have identical output bits. However, on typical photographic images, +very good compression levels can be obtained with no visible change, and +remarkably high compression levels are possible if you can tolerate a +low-quality image. For more details, see the references, or just experiment +with various compression settings. + +This software implements JPEG baseline, extended-sequential, and progressive +compression processes. Provision is made for supporting all variants of these +processes, although some uncommon parameter settings aren't implemented yet. +For legal reasons, we are not distributing code for the arithmetic-coding +variants of JPEG; see LEGAL ISSUES. We have made no provision for supporting +the hierarchical or lossless processes defined in the standard. + +We provide a set of library routines for reading and writing JPEG image files, +plus two sample applications "cjpeg" and "djpeg", which use the library to +perform conversion between JPEG and some other popular image file formats. +The library is intended to be reused in other applications. + +In order to support file conversion and viewing software, we have included +considerable functionality beyond the bare JPEG coding/decoding capability; +for example, the color quantization modules are not strictly part of JPEG +decoding, but they are essential for output to colormapped file formats or +colormapped displays. These extra functions can be compiled out of the +library if not required for a particular application. We have also included +"jpegtran", a utility for lossless transcoding between different JPEG +processes, and "rdjpgcom" and "wrjpgcom", two simple applications for +inserting and extracting textual comments in JFIF files. + +The emphasis in designing this software has been on achieving portability and +flexibility, while also making it fast enough to be useful. In particular, +the software is not intended to be read as a tutorial on JPEG. (See the +REFERENCES section for introductory material.) Rather, it is intended to +be reliable, portable, industrial-strength code. We do not claim to have +achieved that goal in every aspect of the software, but we strive for it. + +We welcome the use of this software as a component of commercial products. +No royalty is required, but we do ask for an acknowledgement in product +documentation, as described under LEGAL ISSUES. + + +LEGAL ISSUES +============ + +In plain English: + +1. We don't promise that this software works. (But if you find any bugs, + please let us know!) +2. You can use this software for whatever you want. You don't have to pay us. +3. You may not pretend that you wrote this software. If you use it in a + program, you must acknowledge somewhere in your documentation that + you've used the IJG code. + +In legalese: + +The authors make NO WARRANTY or representation, either express or implied, +with respect to this software, its quality, accuracy, merchantability, or +fitness for a particular purpose. This software is provided "AS IS", and you, +its user, assume the entire risk as to its quality and accuracy. + +This software is copyright (C) 1991-1998, Thomas G. Lane. +All Rights Reserved except as specified below. + +Permission is hereby granted to use, copy, modify, and distribute this +software (or portions thereof) for any purpose, without fee, subject to these +conditions: +(1) If any part of the source code for this software is distributed, then this +README file must be included, with this copyright and no-warranty notice +unaltered; and any additions, deletions, or changes to the original files +must be clearly indicated in accompanying documentation. +(2) If only executable code is distributed, then the accompanying +documentation must state that "this software is based in part on the work of +the Independent JPEG Group". +(3) Permission for use of this software is granted only if the user accepts +full responsibility for any undesirable consequences; the authors accept +NO LIABILITY for damages of any kind. + +These conditions apply to any software derived from or based on the IJG code, +not just to the unmodified library. If you use our work, you ought to +acknowledge us. + +Permission is NOT granted for the use of any IJG author's name or company name +in advertising or publicity relating to this software or products derived from +it. This software may be referred to only as "the Independent JPEG Group's +software". + +We specifically permit and encourage the use of this software as the basis of +commercial products, provided that all warranty or liability claims are +assumed by the product vendor. + + +ansi2knr.c is included in this distribution by permission of L. Peter Deutsch, +sole proprietor of its copyright holder, Aladdin Enterprises of Menlo Park, CA. +ansi2knr.c is NOT covered by the above copyright and conditions, but instead +by the usual distribution terms of the Free Software Foundation; principally, +that you must include source code if you redistribute it. (See the file +ansi2knr.c for full details.) However, since ansi2knr.c is not needed as part +of any program generated from the IJG code, this does not limit you more than +the foregoing paragraphs do. + +The Unix configuration script "configure" was produced with GNU Autoconf. +It is copyright by the Free Software Foundation but is freely distributable. +The same holds for its supporting scripts (config.guess, config.sub, +ltconfig, ltmain.sh). Another support script, install-sh, is copyright +by M.I.T. but is also freely distributable. + +It appears that the arithmetic coding option of the JPEG spec is covered by +patents owned by IBM, AT&T, and Mitsubishi. Hence arithmetic coding cannot +legally be used without obtaining one or more licenses. For this reason, +support for arithmetic coding has been removed from the free JPEG software. +(Since arithmetic coding provides only a marginal gain over the unpatented +Huffman mode, it is unlikely that very many implementations will support it.) +So far as we are aware, there are no patent restrictions on the remaining +code. + +The IJG distribution formerly included code to read and write GIF files. +To avoid entanglement with the Unisys LZW patent, GIF reading support has +been removed altogether, and the GIF writer has been simplified to produce +"uncompressed GIFs". This technique does not use the LZW algorithm; the +resulting GIF files are larger than usual, but are readable by all standard +GIF decoders. + +We are required to state that + "The Graphics Interchange Format(c) is the Copyright property of + CompuServe Incorporated. GIF(sm) is a Service Mark property of + CompuServe Incorporated." + + +REFERENCES +========== + +We highly recommend reading one or more of these references before trying to +understand the innards of the JPEG software. + +The best short technical introduction to the JPEG compression algorithm is + Wallace, Gregory K. "The JPEG Still Picture Compression Standard", + Communications of the ACM, April 1991 (vol. 34 no. 4), pp. 30-44. +(Adjacent articles in that issue discuss MPEG motion picture compression, +applications of JPEG, and related topics.) If you don't have the CACM issue +handy, a PostScript file containing a revised version of Wallace's article is +available at ftp://ftp.uu.net/graphics/jpeg/wallace.ps.gz. The file (actually +a preprint for an article that appeared in IEEE Trans. Consumer Electronics) +omits the sample images that appeared in CACM, but it includes corrections +and some added material. Note: the Wallace article is copyright ACM and IEEE, +and it may not be used for commercial purposes. + +A somewhat less technical, more leisurely introduction to JPEG can be found in +"The Data Compression Book" by Mark Nelson and Jean-loup Gailly, published by +M&T Books (New York), 2nd ed. 1996, ISBN 1-55851-434-1. This book provides +good explanations and example C code for a multitude of compression methods +including JPEG. It is an excellent source if you are comfortable reading C +code but don't know much about data compression in general. The book's JPEG +sample code is far from industrial-strength, but when you are ready to look +at a full implementation, you've got one here... + +The best full description of JPEG is the textbook "JPEG Still Image Data +Compression Standard" by William B. Pennebaker and Joan L. Mitchell, published +by Van Nostrand Reinhold, 1993, ISBN 0-442-01272-1. Price US$59.95, 638 pp. +The book includes the complete text of the ISO JPEG standards (DIS 10918-1 +and draft DIS 10918-2). This is by far the most complete exposition of JPEG +in existence, and we highly recommend it. + +The JPEG standard itself is not available electronically; you must order a +paper copy through ISO or ITU. (Unless you feel a need to own a certified +official copy, we recommend buying the Pennebaker and Mitchell book instead; +it's much cheaper and includes a great deal of useful explanatory material.) +In the USA, copies of the standard may be ordered from ANSI Sales at (212) +642-4900, or from Global Engineering Documents at (800) 854-7179. (ANSI +doesn't take credit card orders, but Global does.) It's not cheap: as of +1992, ANSI was charging $95 for Part 1 and $47 for Part 2, plus 7% +shipping/handling. The standard is divided into two parts, Part 1 being the +actual specification, while Part 2 covers compliance testing methods. Part 1 +is titled "Digital Compression and Coding of Continuous-tone Still Images, +Part 1: Requirements and guidelines" and has document numbers ISO/IEC IS +10918-1, ITU-T T.81. Part 2 is titled "Digital Compression and Coding of +Continuous-tone Still Images, Part 2: Compliance testing" and has document +numbers ISO/IEC IS 10918-2, ITU-T T.83. + +Some extensions to the original JPEG standard are defined in JPEG Part 3, +a newer ISO standard numbered ISO/IEC IS 10918-3 and ITU-T T.84. IJG +currently does not support any Part 3 extensions. + +The JPEG standard does not specify all details of an interchangeable file +format. For the omitted details we follow the "JFIF" conventions, revision +1.02. A copy of the JFIF spec is available from: + Literature Department + C-Cube Microsystems, Inc. + 1778 McCarthy Blvd. + Milpitas, CA 95035 + phone (408) 944-6300, fax (408) 944-6314 +A PostScript version of this document is available by FTP at +ftp://ftp.uu.net/graphics/jpeg/jfif.ps.gz. There is also a plain text +version at ftp://ftp.uu.net/graphics/jpeg/jfif.txt.gz, but it is missing +the figures. + +The TIFF 6.0 file format specification can be obtained by FTP from +ftp://ftp.sgi.com/graphics/tiff/TIFF6.ps.gz. The JPEG incorporation scheme +found in the TIFF 6.0 spec of 3-June-92 has a number of serious problems. +IJG does not recommend use of the TIFF 6.0 design (TIFF Compression tag 6). +Instead, we recommend the JPEG design proposed by TIFF Technical Note #2 +(Compression tag 7). Copies of this Note can be obtained from ftp.sgi.com or +from ftp://ftp.uu.net/graphics/jpeg/. It is expected that the next revision +of the TIFF spec will replace the 6.0 JPEG design with the Note's design. +Although IJG's own code does not support TIFF/JPEG, the free libtiff library +uses our library to implement TIFF/JPEG per the Note. libtiff is available +from ftp://ftp.sgi.com/graphics/tiff/. + + +ARCHIVE LOCATIONS +================= + +The "official" archive site for this software is ftp.uu.net (Internet +address 192.48.96.9). The most recent released version can always be found +there in directory graphics/jpeg. This particular version will be archived +as ftp://ftp.uu.net/graphics/jpeg/jpegsrc.v6b.tar.gz. If you don't have +direct Internet access, UUNET's archives are also available via UUCP; contact +help@uunet.uu.net for information on retrieving files that way. + +Numerous Internet sites maintain copies of the UUNET files. However, only +ftp.uu.net is guaranteed to have the latest official version. + +You can also obtain this software in DOS-compatible "zip" archive format from +the SimTel archives (ftp://ftp.simtel.net/pub/simtelnet/msdos/graphics/), or +on CompuServe in the Graphics Support forum (GO CIS:GRAPHSUP), library 12 +"JPEG Tools". Again, these versions may sometimes lag behind the ftp.uu.net +release. + +The JPEG FAQ (Frequently Asked Questions) article is a useful source of +general information about JPEG. It is updated constantly and therefore is +not included in this distribution. The FAQ is posted every two weeks to +Usenet newsgroups comp.graphics.misc, news.answers, and other groups. +It is available on the World Wide Web at http://www.faqs.org/faqs/jpeg-faq/ +and other news.answers archive sites, including the official news.answers +archive at rtfm.mit.edu: ftp://rtfm.mit.edu/pub/usenet/news.answers/jpeg-faq/. +If you don't have Web or FTP access, send e-mail to mail-server@rtfm.mit.edu +with body + send usenet/news.answers/jpeg-faq/part1 + send usenet/news.answers/jpeg-faq/part2 + + +RELATED SOFTWARE +================ + +Numerous viewing and image manipulation programs now support JPEG. (Quite a +few of them use this library to do so.) The JPEG FAQ described above lists +some of the more popular free and shareware viewers, and tells where to +obtain them on Internet. + +If you are on a Unix machine, we highly recommend Jef Poskanzer's free +PBMPLUS software, which provides many useful operations on PPM-format image +files. In particular, it can convert PPM images to and from a wide range of +other formats, thus making cjpeg/djpeg considerably more useful. The latest +version is distributed by the NetPBM group, and is available from numerous +sites, notably ftp://wuarchive.wustl.edu/graphics/graphics/packages/NetPBM/. +Unfortunately PBMPLUS/NETPBM is not nearly as portable as the IJG software is; +you are likely to have difficulty making it work on any non-Unix machine. + +A different free JPEG implementation, written by the PVRG group at Stanford, +is available from ftp://havefun.stanford.edu/pub/jpeg/. This program +is designed for research and experimentation rather than production use; +it is slower, harder to use, and less portable than the IJG code, but it +is easier to read and modify. Also, the PVRG code supports lossless JPEG, +which we do not. (On the other hand, it doesn't do progressive JPEG.) + + +FILE FORMAT WARS +================ + +Some JPEG programs produce files that are not compatible with our library. +The root of the problem is that the ISO JPEG committee failed to specify a +concrete file format. Some vendors "filled in the blanks" on their own, +creating proprietary formats that no one else could read. (For example, none +of the early commercial JPEG implementations for the Macintosh were able to +exchange compressed files.) + +The file format we have adopted is called JFIF (see REFERENCES). This format +has been agreed to by a number of major commercial JPEG vendors, and it has +become the de facto standard. JFIF is a minimal or "low end" representation. +We recommend the use of TIFF/JPEG (TIFF revision 6.0 as modified by TIFF +Technical Note #2) for "high end" applications that need to record a lot of +additional data about an image. TIFF/JPEG is fairly new and not yet widely +supported, unfortunately. + +The upcoming JPEG Part 3 standard defines a file format called SPIFF. +SPIFF is interoperable with JFIF, in the sense that most JFIF decoders should +be able to read the most common variant of SPIFF. SPIFF has some technical +advantages over JFIF, but its major claim to fame is simply that it is an +official standard rather than an informal one. At this point it is unclear +whether SPIFF will supersede JFIF or whether JFIF will remain the de-facto +standard. IJG intends to support SPIFF once the standard is frozen, but we +have not decided whether it should become our default output format or not. +(In any case, our decoder will remain capable of reading JFIF indefinitely.) + +Various proprietary file formats incorporating JPEG compression also exist. +We have little or no sympathy for the existence of these formats. Indeed, +one of the original reasons for developing this free software was to help +force convergence on common, open format standards for JPEG files. Don't +use a proprietary file format! + + +TO DO +===== + +The major thrust for v7 will probably be improvement of visual quality. +The current method for scaling the quantization tables is known not to be +very good at low Q values. We also intend to investigate block boundary +smoothing, "poor man's variable quantization", and other means of improving +quality-vs-file-size performance without sacrificing compatibility. + +In future versions, we are considering supporting some of the upcoming JPEG +Part 3 extensions --- principally, variable quantization and the SPIFF file +format. + +As always, speeding things up is of great interest. + +Please send bug reports, offers of help, etc. to jpeg-info@uunet.uu.net. diff --git a/mk4/modimage/jpeg-6b/ansi2knr.1 b/mk4/modimage/jpeg-6b/ansi2knr.1 new file mode 100644 index 0000000..f9ee5a6 --- /dev/null +++ b/mk4/modimage/jpeg-6b/ansi2knr.1 @@ -0,0 +1,36 @@ +.TH ANSI2KNR 1 "19 Jan 1996" +.SH NAME +ansi2knr \- convert ANSI C to Kernighan & Ritchie C +.SH SYNOPSIS +.I ansi2knr +[--varargs] input_file [output_file] +.SH DESCRIPTION +If no output_file is supplied, output goes to stdout. +.br +There are no error messages. +.sp +.I ansi2knr +recognizes function definitions by seeing a non-keyword identifier at the left +margin, followed by a left parenthesis, with a right parenthesis as the last +character on the line, and with a left brace as the first token on the +following line (ignoring possible intervening comments). It will recognize a +multi-line header provided that no intervening line ends with a left or right +brace or a semicolon. These algorithms ignore whitespace and comments, except +that the function name must be the first thing on the line. +.sp +The following constructs will confuse it: +.br + - Any other construct that starts at the left margin and follows the +above syntax (such as a macro or function call). +.br + - Some macros that tinker with the syntax of the function header. +.sp +The --varargs switch is obsolete, and is recognized only for +backwards compatibility. The present version of +.I ansi2knr +will always attempt to convert a ... argument to va_alist and va_dcl. +.SH AUTHOR +L. Peter Deutsch wrote the original ansi2knr and +continues to maintain the current version; most of the code in the current +version is his work. ansi2knr also includes contributions by Francois +Pinard and Jim Avera . diff --git a/mk4/modimage/jpeg-6b/ansi2knr.c b/mk4/modimage/jpeg-6b/ansi2knr.c new file mode 100644 index 0000000..4e05fc2 --- /dev/null +++ b/mk4/modimage/jpeg-6b/ansi2knr.c @@ -0,0 +1,693 @@ +/* ansi2knr.c */ +/* Convert ANSI C function definitions to K&R ("traditional C") syntax */ + +/* +ansi2knr is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone for the +consequences of using it or for whether it serves any particular purpose or +works at all, unless he says so in writing. Refer to the GNU General Public +License (the "GPL") for full details. + +Everyone is granted permission to copy, modify and redistribute ansi2knr, +but only under the conditions described in the GPL. A copy of this license +is supposed to have been given to you along with ansi2knr so you can know +your rights and responsibilities. It should be in a file named COPYLEFT. +[In the IJG distribution, the GPL appears below, not in a separate file.] +Among other things, the copyright notice and this notice must be preserved +on all copies. + +We explicitly state here what we believe is already implied by the GPL: if +the ansi2knr program is distributed as a separate set of sources and a +separate executable file which are aggregated on a storage medium together +with another program, this in itself does not bring the other program under +the GPL, nor does the mere fact that such a program or the procedures for +constructing it invoke the ansi2knr executable bring any other part of the +program under the GPL. +*/ + +/* +---------- Here is the GNU GPL file COPYLEFT, referred to above ---------- +----- These terms do NOT apply to the JPEG software itself; see README ------ + + GHOSTSCRIPT GENERAL PUBLIC LICENSE + (Clarified 11 Feb 1988) + + Copyright (C) 1988 Richard M. Stallman + Everyone is permitted to copy and distribute verbatim copies of this + license, but changing it is not allowed. You can also use this wording + to make the terms for other programs. + + The license agreements of most software companies keep you at the +mercy of those companies. By contrast, our general public license is +intended to give everyone the right to share Ghostscript. To make sure +that you get the rights we want you to have, we need to make +restrictions that forbid anyone to deny you these rights or to ask you +to surrender the rights. Hence this license agreement. + + Specifically, we want to make sure that you have the right to give +away copies of Ghostscript, that you receive source code or else can get +it if you want it, that you can change Ghostscript or use pieces of it +in new free programs, and that you know you can do these things. + + To make sure that everyone has such rights, we have to forbid you to +deprive anyone else of these rights. For example, if you distribute +copies of Ghostscript, 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 tell them their rights. + + Also, for our own protection, we must make certain that everyone finds +out that there is no warranty for Ghostscript. If Ghostscript is +modified by someone else and passed on, we want its recipients to know +that what they have is not what we distributed, so that any problems +introduced by others will not reflect on our reputation. + + Therefore we (Richard M. Stallman and the Free Software Foundation, +Inc.) make the following terms which say what you must do to be allowed +to distribute or change Ghostscript. + + + COPYING POLICIES + + 1. You may copy and distribute verbatim copies of Ghostscript source +code as you receive it, in any medium, provided that you conspicuously +and appropriately publish on each copy a valid copyright and license +notice "Copyright (C) 1989 Aladdin Enterprises. All rights reserved. +Distributed by Free Software Foundation, Inc." (or with whatever year is +appropriate); keep intact the notices on all files that refer to this +License Agreement and to the absence of any warranty; and give any other +recipients of the Ghostscript program a copy of this License Agreement +along with the program. You may charge a distribution fee for the +physical act of transferring a copy. + + 2. You may modify your copy or copies of Ghostscript or any portion of +it, and copy and distribute such modifications under the terms of +Paragraph 1 above, provided that you also do the following: + + a) cause the modified files to carry prominent notices stating + that you changed the files and the date of any change; and + + b) cause the whole of any work that you distribute or publish, + that in whole or in part contains or is a derivative of Ghostscript + or any part thereof, to be licensed at no charge to all third + parties on terms identical to those contained in this License + Agreement (except that you may choose to grant more extensive + warranty protection to some or all third parties, at your option). + + c) You may charge a distribution fee for the physical act of + transferring a copy, and you may at your option offer warranty + protection in exchange for a fee. + +Mere aggregation of another unrelated program with this program (or its +derivative) on a volume of a storage or distribution medium does not bring +the other program under the scope of these terms. + + 3. You may copy and distribute Ghostscript (or a portion or derivative +of it, under Paragraph 2) in object code or executable form under the +terms of Paragraphs 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 + Paragraphs 1 and 2 above; or, + + b) accompany it with a written offer, valid for at least three + years, to give any third party free (except for a nominal + shipping charge) a complete machine-readable copy of the + corresponding source code, to be distributed under the terms of + Paragraphs 1 and 2 above; or, + + c) accompany it with the information you received as to where the + corresponding source code may be obtained. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form alone.) + +For an executable file, complete source code means all the source code for +all modules it contains; but, as a special exception, it need not include +source code for modules which are standard libraries that accompany the +operating system on which the executable file runs. + + 4. You may not copy, sublicense, distribute or transfer Ghostscript +except as expressly provided under this License Agreement. Any attempt +otherwise to copy, sublicense, distribute or transfer Ghostscript is +void and your rights to use the program under this License agreement +shall be automatically terminated. However, parties who have received +computer software programs from you with this License Agreement will not +have their licenses terminated so long as such parties remain in full +compliance. + + 5. If you wish to incorporate parts of Ghostscript into other free +programs whose distribution conditions are different, write to the Free +Software Foundation at 675 Mass Ave, Cambridge, MA 02139. We have not +yet worked out a simple rule that can be stated here, but we will often +permit this. We 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. + +Your comments and suggestions about our licensing policies and our +software are welcome! Please contact the Free Software Foundation, +Inc., 675 Mass Ave, Cambridge, MA 02139, or call (617) 876-3296. + + NO WARRANTY + + BECAUSE GHOSTSCRIPT IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY +NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT +WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC, RICHARD +M. STALLMAN, ALADDIN ENTERPRISES, L. PETER DEUTSCH, AND/OR OTHER PARTIES +PROVIDE GHOSTSCRIPT "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 GHOSTSCRIPT IS WITH +YOU. SHOULD GHOSTSCRIPT PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL +NECESSARY SERVICING, REPAIR OR CORRECTION. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M. +STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., L. PETER DEUTSCH, ALADDIN +ENTERPRISES, AND/OR ANY OTHER PARTY WHO MAY MODIFY AND REDISTRIBUTE +GHOSTSCRIPT AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING +ANY LOST PROFITS, LOST MONIES, OR OTHER SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE +(INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED +INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR A FAILURE OF THE +PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) GHOSTSCRIPT, EVEN IF YOU +HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES, OR FOR ANY CLAIM +BY ANY OTHER PARTY. + +-------------------- End of file COPYLEFT ------------------------------ +*/ + +/* + * Usage: + ansi2knr input_file [output_file] + * If no output_file is supplied, output goes to stdout. + * There are no error messages. + * + * ansi2knr recognizes function definitions by seeing a non-keyword + * identifier at the left margin, followed by a left parenthesis, + * with a right parenthesis as the last character on the line, + * and with a left brace as the first token on the following line + * (ignoring possible intervening comments). + * It will recognize a multi-line header provided that no intervening + * line ends with a left or right brace or a semicolon. + * These algorithms ignore whitespace and comments, except that + * the function name must be the first thing on the line. + * The following constructs will confuse it: + * - Any other construct that starts at the left margin and + * follows the above syntax (such as a macro or function call). + * - Some macros that tinker with the syntax of the function header. + */ + +/* + * The original and principal author of ansi2knr is L. Peter Deutsch + * . Other authors are noted in the change history + * that follows (in reverse chronological order): + lpd 96-01-21 added code to cope with not HAVE_CONFIG_H and with + compilers that don't understand void, as suggested by + Tom Lane + lpd 96-01-15 changed to require that the first non-comment token + on the line following a function header be a left brace, + to reduce sensitivity to macros, as suggested by Tom Lane + + lpd 95-06-22 removed #ifndefs whose sole purpose was to define + undefined preprocessor symbols as 0; changed all #ifdefs + for configuration symbols to #ifs + lpd 95-04-05 changed copyright notice to make it clear that + including ansi2knr in a program does not bring the entire + program under the GPL + lpd 94-12-18 added conditionals for systems where ctype macros + don't handle 8-bit characters properly, suggested by + Francois Pinard ; + removed --varargs switch (this is now the default) + lpd 94-10-10 removed CONFIG_BROKETS conditional + lpd 94-07-16 added some conditionals to help GNU `configure', + suggested by Francois Pinard ; + properly erase prototype args in function parameters, + contributed by Jim Avera ; + correct error in writeblanks (it shouldn't erase EOLs) + lpd 89-xx-xx original version + */ + +/* Most of the conditionals here are to make ansi2knr work with */ +/* or without the GNU configure machinery. */ + +#if HAVE_CONFIG_H +# include +#endif + +#include +#include + +#if HAVE_CONFIG_H + +/* + For properly autoconfiguring ansi2knr, use AC_CONFIG_HEADER(config.h). + This will define HAVE_CONFIG_H and so, activate the following lines. + */ + +# if STDC_HEADERS || HAVE_STRING_H +# include +# else +# include +# endif + +#else /* not HAVE_CONFIG_H */ + +/* Otherwise do it the hard way */ + +# ifdef BSD +# include +# else +# ifdef VMS + extern int strlen(), strncmp(); +# else +# include +# endif +# endif + +#endif /* not HAVE_CONFIG_H */ + +#if STDC_HEADERS +# include +#else +/* + malloc and free should be declared in stdlib.h, + but if you've got a K&R compiler, they probably aren't. + */ +# ifdef MSDOS +# include +# else +# ifdef VMS + extern char *malloc(); + extern void free(); +# else + extern char *malloc(); + extern int free(); +# endif +# endif + +#endif + +/* + * The ctype macros don't always handle 8-bit characters correctly. + * Compensate for this here. + */ +#ifdef isascii +# undef HAVE_ISASCII /* just in case */ +# define HAVE_ISASCII 1 +#else +#endif +#if STDC_HEADERS || !HAVE_ISASCII +# define is_ascii(c) 1 +#else +# define is_ascii(c) isascii(c) +#endif + +#define is_space(c) (is_ascii(c) && isspace(c)) +#define is_alpha(c) (is_ascii(c) && isalpha(c)) +#define is_alnum(c) (is_ascii(c) && isalnum(c)) + +/* Scanning macros */ +#define isidchar(ch) (is_alnum(ch) || (ch) == '_') +#define isidfirstchar(ch) (is_alpha(ch) || (ch) == '_') + +/* Forward references */ +char *skipspace(); +int writeblanks(); +int test1(); +int convert1(); + +/* The main program */ +int +main(argc, argv) + int argc; + char *argv[]; +{ FILE *in, *out; +#define bufsize 5000 /* arbitrary size */ + char *buf; + char *line; + char *more; + /* + * In previous versions, ansi2knr recognized a --varargs switch. + * If this switch was supplied, ansi2knr would attempt to convert + * a ... argument to va_alist and va_dcl; if this switch was not + * supplied, ansi2knr would simply drop any such arguments. + * Now, ansi2knr always does this conversion, and we only + * check for this switch for backward compatibility. + */ + int convert_varargs = 1; + + if ( argc > 1 && argv[1][0] == '-' ) + { if ( !strcmp(argv[1], "--varargs") ) + { convert_varargs = 1; + argc--; + argv++; + } + else + { fprintf(stderr, "Unrecognized switch: %s\n", argv[1]); + exit(1); + } + } + switch ( argc ) + { + default: + printf("Usage: ansi2knr input_file [output_file]\n"); + exit(0); + case 2: + out = stdout; + break; + case 3: + out = fopen(argv[2], "w"); + if ( out == NULL ) + { fprintf(stderr, "Cannot open output file %s\n", argv[2]); + exit(1); + } + } + in = fopen(argv[1], "r"); + if ( in == NULL ) + { fprintf(stderr, "Cannot open input file %s\n", argv[1]); + exit(1); + } + fprintf(out, "#line 1 \"%s\"\n", argv[1]); + buf = malloc(bufsize); + line = buf; + while ( fgets(line, (unsigned)(buf + bufsize - line), in) != NULL ) + { +test: line += strlen(line); + switch ( test1(buf) ) + { + case 2: /* a function header */ + convert1(buf, out, 1, convert_varargs); + break; + case 1: /* a function */ + /* Check for a { at the start of the next line. */ + more = ++line; +f: if ( line >= buf + (bufsize - 1) ) /* overflow check */ + goto wl; + if ( fgets(line, (unsigned)(buf + bufsize - line), in) == NULL ) + goto wl; + switch ( *skipspace(more, 1) ) + { + case '{': + /* Definitely a function header. */ + convert1(buf, out, 0, convert_varargs); + fputs(more, out); + break; + case 0: + /* The next line was blank or a comment: */ + /* keep scanning for a non-comment. */ + line += strlen(line); + goto f; + default: + /* buf isn't a function header, but */ + /* more might be. */ + fputs(buf, out); + strcpy(buf, more); + line = buf; + goto test; + } + break; + case -1: /* maybe the start of a function */ + if ( line != buf + (bufsize - 1) ) /* overflow check */ + continue; + /* falls through */ + default: /* not a function */ +wl: fputs(buf, out); + break; + } + line = buf; + } + if ( line != buf ) + fputs(buf, out); + free(buf); + fclose(out); + fclose(in); + return 0; +} + +/* Skip over space and comments, in either direction. */ +char * +skipspace(p, dir) + register char *p; + register int dir; /* 1 for forward, -1 for backward */ +{ for ( ; ; ) + { while ( is_space(*p) ) + p += dir; + if ( !(*p == '/' && p[dir] == '*') ) + break; + p += dir; p += dir; + while ( !(*p == '*' && p[dir] == '/') ) + { if ( *p == 0 ) + return p; /* multi-line comment?? */ + p += dir; + } + p += dir; p += dir; + } + return p; +} + +/* + * Write blanks over part of a string. + * Don't overwrite end-of-line characters. + */ +int +writeblanks(start, end) + char *start; + char *end; +{ char *p; + for ( p = start; p < end; p++ ) + if ( *p != '\r' && *p != '\n' ) + *p = ' '; + return 0; +} + +/* + * Test whether the string in buf is a function definition. + * The string may contain and/or end with a newline. + * Return as follows: + * 0 - definitely not a function definition; + * 1 - definitely a function definition; + * 2 - definitely a function prototype (NOT USED); + * -1 - may be the beginning of a function definition, + * append another line and look again. + * The reason we don't attempt to convert function prototypes is that + * Ghostscript's declaration-generating macros look too much like + * prototypes, and confuse the algorithms. + */ +int +test1(buf) + char *buf; +{ register char *p = buf; + char *bend; + char *endfn; + int contin; + + if ( !isidfirstchar(*p) ) + return 0; /* no name at left margin */ + bend = skipspace(buf + strlen(buf) - 1, -1); + switch ( *bend ) + { + case ';': contin = 0 /*2*/; break; + case ')': contin = 1; break; + case '{': return 0; /* not a function */ + case '}': return 0; /* not a function */ + default: contin = -1; + } + while ( isidchar(*p) ) + p++; + endfn = p; + p = skipspace(p, 1); + if ( *p++ != '(' ) + return 0; /* not a function */ + p = skipspace(p, 1); + if ( *p == ')' ) + return 0; /* no parameters */ + /* Check that the apparent function name isn't a keyword. */ + /* We only need to check for keywords that could be followed */ + /* by a left parenthesis (which, unfortunately, is most of them). */ + { static char *words[] = + { "asm", "auto", "case", "char", "const", "double", + "extern", "float", "for", "if", "int", "long", + "register", "return", "short", "signed", "sizeof", + "static", "switch", "typedef", "unsigned", + "void", "volatile", "while", 0 + }; + char **key = words; + char *kp; + int len = endfn - buf; + + while ( (kp = *key) != 0 ) + { if ( strlen(kp) == len && !strncmp(kp, buf, len) ) + return 0; /* name is a keyword */ + key++; + } + } + return contin; +} + +/* Convert a recognized function definition or header to K&R syntax. */ +int +convert1(buf, out, header, convert_varargs) + char *buf; + FILE *out; + int header; /* Boolean */ + int convert_varargs; /* Boolean */ +{ char *endfn; + register char *p; + char **breaks; + unsigned num_breaks = 2; /* for testing */ + char **btop; + char **bp; + char **ap; + char *vararg = 0; + + /* Pre-ANSI implementations don't agree on whether strchr */ + /* is called strchr or index, so we open-code it here. */ + for ( endfn = buf; *(endfn++) != '('; ) + ; +top: p = endfn; + breaks = (char **)malloc(sizeof(char *) * num_breaks * 2); + if ( breaks == 0 ) + { /* Couldn't allocate break table, give up */ + fprintf(stderr, "Unable to allocate break table!\n"); + fputs(buf, out); + return -1; + } + btop = breaks + num_breaks * 2 - 2; + bp = breaks; + /* Parse the argument list */ + do + { int level = 0; + char *lp = NULL; + char *rp; + char *end = NULL; + + if ( bp >= btop ) + { /* Filled up break table. */ + /* Allocate a bigger one and start over. */ + free((char *)breaks); + num_breaks <<= 1; + goto top; + } + *bp++ = p; + /* Find the end of the argument */ + for ( ; end == NULL; p++ ) + { switch(*p) + { + case ',': + if ( !level ) end = p; + break; + case '(': + if ( !level ) lp = p; + level++; + break; + case ')': + if ( --level < 0 ) end = p; + else rp = p; + break; + case '/': + p = skipspace(p, 1) - 1; + break; + default: + ; + } + } + /* Erase any embedded prototype parameters. */ + if ( lp ) + writeblanks(lp + 1, rp); + p--; /* back up over terminator */ + /* Find the name being declared. */ + /* This is complicated because of procedure and */ + /* array modifiers. */ + for ( ; ; ) + { p = skipspace(p - 1, -1); + switch ( *p ) + { + case ']': /* skip array dimension(s) */ + case ')': /* skip procedure args OR name */ + { int level = 1; + while ( level ) + switch ( *--p ) + { + case ']': case ')': level++; break; + case '[': case '(': level--; break; + case '/': p = skipspace(p, -1) + 1; break; + default: ; + } + } + if ( *p == '(' && *skipspace(p + 1, 1) == '*' ) + { /* We found the name being declared */ + while ( !isidfirstchar(*p) ) + p = skipspace(p, 1) + 1; + goto found; + } + break; + default: + goto found; + } + } +found: if ( *p == '.' && p[-1] == '.' && p[-2] == '.' ) + { if ( convert_varargs ) + { *bp++ = "va_alist"; + vararg = p-2; + } + else + { p++; + if ( bp == breaks + 1 ) /* sole argument */ + writeblanks(breaks[0], p); + else + writeblanks(bp[-1] - 1, p); + bp--; + } + } + else + { while ( isidchar(*p) ) p--; + *bp++ = p+1; + } + p = end; + } + while ( *p++ == ',' ); + *bp = p; + /* Make a special check for 'void' arglist */ + if ( bp == breaks+2 ) + { p = skipspace(breaks[0], 1); + if ( !strncmp(p, "void", 4) ) + { p = skipspace(p+4, 1); + if ( p == breaks[2] - 1 ) + { bp = breaks; /* yup, pretend arglist is empty */ + writeblanks(breaks[0], p + 1); + } + } + } + /* Put out the function name and left parenthesis. */ + p = buf; + while ( p != endfn ) putc(*p, out), p++; + /* Put out the declaration. */ + if ( header ) + { fputs(");", out); + for ( p = breaks[0]; *p; p++ ) + if ( *p == '\r' || *p == '\n' ) + putc(*p, out); + } + else + { for ( ap = breaks+1; ap < bp; ap += 2 ) + { p = *ap; + while ( isidchar(*p) ) + putc(*p, out), p++; + if ( ap < bp - 1 ) + fputs(", ", out); + } + fputs(") ", out); + /* Put out the argument declarations */ + for ( ap = breaks+2; ap <= bp; ap += 2 ) + (*ap)[-1] = ';'; + if ( vararg != 0 ) + { *vararg = 0; + fputs(breaks[0], out); /* any prior args */ + fputs("va_dcl", out); /* the final arg */ + fputs(bp[0], out); + } + else + fputs(breaks[0], out); + } + free((char *)breaks); + return 0; +} diff --git a/mk4/modimage/jpeg-6b/cderror.h b/mk4/modimage/jpeg-6b/cderror.h new file mode 100644 index 0000000..70435e1 --- /dev/null +++ b/mk4/modimage/jpeg-6b/cderror.h @@ -0,0 +1,132 @@ +/* + * cderror.h + * + * Copyright (C) 1994-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file defines the error and message codes for the cjpeg/djpeg + * applications. These strings are not needed as part of the JPEG library + * proper. + * Edit this file to add new codes, or to translate the message strings to + * some other language. + */ + +/* + * To define the enum list of message codes, include this file without + * defining macro JMESSAGE. To create a message string table, include it + * again with a suitable JMESSAGE definition (see jerror.c for an example). + */ +#ifndef JMESSAGE +#ifndef CDERROR_H +#define CDERROR_H +/* First time through, define the enum list */ +#define JMAKE_ENUM_LIST +#else +/* Repeated inclusions of this file are no-ops unless JMESSAGE is defined */ +#define JMESSAGE(code,string) +#endif /* CDERROR_H */ +#endif /* JMESSAGE */ + +#ifdef JMAKE_ENUM_LIST + +typedef enum { + +#define JMESSAGE(code,string) code , + +#endif /* JMAKE_ENUM_LIST */ + +JMESSAGE(JMSG_FIRSTADDONCODE=1000, NULL) /* Must be first entry! */ + +#ifdef BMP_SUPPORTED +JMESSAGE(JERR_BMP_BADCMAP, "Unsupported BMP colormap format") +JMESSAGE(JERR_BMP_BADDEPTH, "Only 8- and 24-bit BMP files are supported") +JMESSAGE(JERR_BMP_BADHEADER, "Invalid BMP file: bad header length") +JMESSAGE(JERR_BMP_BADPLANES, "Invalid BMP file: biPlanes not equal to 1") +JMESSAGE(JERR_BMP_COLORSPACE, "BMP output must be grayscale or RGB") +JMESSAGE(JERR_BMP_COMPRESSED, "Sorry, compressed BMPs not yet supported") +JMESSAGE(JERR_BMP_NOT, "Not a BMP file - does not start with BM") +JMESSAGE(JTRC_BMP, "%ux%u 24-bit BMP image") +JMESSAGE(JTRC_BMP_MAPPED, "%ux%u 8-bit colormapped BMP image") +JMESSAGE(JTRC_BMP_OS2, "%ux%u 24-bit OS2 BMP image") +JMESSAGE(JTRC_BMP_OS2_MAPPED, "%ux%u 8-bit colormapped OS2 BMP image") +#endif /* BMP_SUPPORTED */ + +#ifdef GIF_SUPPORTED +JMESSAGE(JERR_GIF_BUG, "GIF output got confused") +JMESSAGE(JERR_GIF_CODESIZE, "Bogus GIF codesize %d") +JMESSAGE(JERR_GIF_COLORSPACE, "GIF output must be grayscale or RGB") +JMESSAGE(JERR_GIF_IMAGENOTFOUND, "Too few images in GIF file") +JMESSAGE(JERR_GIF_NOT, "Not a GIF file") +JMESSAGE(JTRC_GIF, "%ux%ux%d GIF image") +JMESSAGE(JTRC_GIF_BADVERSION, + "Warning: unexpected GIF version number '%c%c%c'") +JMESSAGE(JTRC_GIF_EXTENSION, "Ignoring GIF extension block of type 0x%02x") +JMESSAGE(JTRC_GIF_NONSQUARE, "Caution: nonsquare pixels in input") +JMESSAGE(JWRN_GIF_BADDATA, "Corrupt data in GIF file") +JMESSAGE(JWRN_GIF_CHAR, "Bogus char 0x%02x in GIF file, ignoring") +JMESSAGE(JWRN_GIF_ENDCODE, "Premature end of GIF image") +JMESSAGE(JWRN_GIF_NOMOREDATA, "Ran out of GIF bits") +#endif /* GIF_SUPPORTED */ + +#ifdef PPM_SUPPORTED +JMESSAGE(JERR_PPM_COLORSPACE, "PPM output must be grayscale or RGB") +JMESSAGE(JERR_PPM_NONNUMERIC, "Nonnumeric data in PPM file") +JMESSAGE(JERR_PPM_NOT, "Not a PPM/PGM file") +JMESSAGE(JTRC_PGM, "%ux%u PGM image") +JMESSAGE(JTRC_PGM_TEXT, "%ux%u text PGM image") +JMESSAGE(JTRC_PPM, "%ux%u PPM image") +JMESSAGE(JTRC_PPM_TEXT, "%ux%u text PPM image") +#endif /* PPM_SUPPORTED */ + +#ifdef RLE_SUPPORTED +JMESSAGE(JERR_RLE_BADERROR, "Bogus error code from RLE library") +JMESSAGE(JERR_RLE_COLORSPACE, "RLE output must be grayscale or RGB") +JMESSAGE(JERR_RLE_DIMENSIONS, "Image dimensions (%ux%u) too large for RLE") +JMESSAGE(JERR_RLE_EMPTY, "Empty RLE file") +JMESSAGE(JERR_RLE_EOF, "Premature EOF in RLE header") +JMESSAGE(JERR_RLE_MEM, "Insufficient memory for RLE header") +JMESSAGE(JERR_RLE_NOT, "Not an RLE file") +JMESSAGE(JERR_RLE_TOOMANYCHANNELS, "Cannot handle %d output channels for RLE") +JMESSAGE(JERR_RLE_UNSUPPORTED, "Cannot handle this RLE setup") +JMESSAGE(JTRC_RLE, "%ux%u full-color RLE file") +JMESSAGE(JTRC_RLE_FULLMAP, "%ux%u full-color RLE file with map of length %d") +JMESSAGE(JTRC_RLE_GRAY, "%ux%u grayscale RLE file") +JMESSAGE(JTRC_RLE_MAPGRAY, "%ux%u grayscale RLE file with map of length %d") +JMESSAGE(JTRC_RLE_MAPPED, "%ux%u colormapped RLE file with map of length %d") +#endif /* RLE_SUPPORTED */ + +#ifdef TARGA_SUPPORTED +JMESSAGE(JERR_TGA_BADCMAP, "Unsupported Targa colormap format") +JMESSAGE(JERR_TGA_BADPARMS, "Invalid or unsupported Targa file") +JMESSAGE(JERR_TGA_COLORSPACE, "Targa output must be grayscale or RGB") +JMESSAGE(JTRC_TGA, "%ux%u RGB Targa image") +JMESSAGE(JTRC_TGA_GRAY, "%ux%u grayscale Targa image") +JMESSAGE(JTRC_TGA_MAPPED, "%ux%u colormapped Targa image") +#else +JMESSAGE(JERR_TGA_NOTCOMP, "Targa support was not compiled") +#endif /* TARGA_SUPPORTED */ + +JMESSAGE(JERR_BAD_CMAP_FILE, + "Color map file is invalid or of unsupported format") +JMESSAGE(JERR_TOO_MANY_COLORS, + "Output file format cannot handle %d colormap entries") +JMESSAGE(JERR_UNGETC_FAILED, "ungetc failed") +#ifdef TARGA_SUPPORTED +JMESSAGE(JERR_UNKNOWN_FORMAT, + "Unrecognized input file format --- perhaps you need -targa") +#else +JMESSAGE(JERR_UNKNOWN_FORMAT, "Unrecognized input file format") +#endif +JMESSAGE(JERR_UNSUPPORTED_FORMAT, "Unsupported output file format") + +#ifdef JMAKE_ENUM_LIST + + JMSG_LASTADDONCODE +} ADDON_MESSAGE_CODE; + +#undef JMAKE_ENUM_LIST +#endif /* JMAKE_ENUM_LIST */ + +/* Zap JMESSAGE macro so that future re-inclusions do nothing by default */ +#undef JMESSAGE diff --git a/mk4/modimage/jpeg-6b/cdjpeg.c b/mk4/modimage/jpeg-6b/cdjpeg.c new file mode 100644 index 0000000..b6250ff --- /dev/null +++ b/mk4/modimage/jpeg-6b/cdjpeg.c @@ -0,0 +1,181 @@ +/* + * cdjpeg.c + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains common support routines used by the IJG application + * programs (cjpeg, djpeg, jpegtran). + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ +#include /* to declare isupper(), tolower() */ +#ifdef NEED_SIGNAL_CATCHER +#include /* to declare signal() */ +#endif +#ifdef USE_SETMODE +#include /* to declare setmode()'s parameter macros */ +/* If you have setmode() but not , just delete this line: */ +#include /* to declare setmode() */ +#endif + + +/* + * Signal catcher to ensure that temporary files are removed before aborting. + * NB: for Amiga Manx C this is actually a global routine named _abort(); + * we put "#define signal_catcher _abort" in jconfig.h. Talk about bogus... + */ + +#ifdef NEED_SIGNAL_CATCHER + +static j_common_ptr sig_cinfo; + +void /* must be global for Manx C */ +signal_catcher (int signum) +{ + if (sig_cinfo != NULL) { + if (sig_cinfo->err != NULL) /* turn off trace output */ + sig_cinfo->err->trace_level = 0; + jpeg_destroy(sig_cinfo); /* clean up memory allocation & temp files */ + } + exit(EXIT_FAILURE); +} + + +GLOBAL(void) +enable_signal_catcher (j_common_ptr cinfo) +{ + sig_cinfo = cinfo; +#ifdef SIGINT /* not all systems have SIGINT */ + signal(SIGINT, signal_catcher); +#endif +#ifdef SIGTERM /* not all systems have SIGTERM */ + signal(SIGTERM, signal_catcher); +#endif +} + +#endif + + +/* + * Optional progress monitor: display a percent-done figure on stderr. + */ + +#ifdef PROGRESS_REPORT + +METHODDEF(void) +progress_monitor (j_common_ptr cinfo) +{ + cd_progress_ptr prog = (cd_progress_ptr) cinfo->progress; + int total_passes = prog->pub.total_passes + prog->total_extra_passes; + int percent_done = (int) (prog->pub.pass_counter*100L/prog->pub.pass_limit); + + if (percent_done != prog->percent_done) { + prog->percent_done = percent_done; + if (total_passes > 1) { + fprintf(stderr, "\rPass %d/%d: %3d%% ", + prog->pub.completed_passes + prog->completed_extra_passes + 1, + total_passes, percent_done); + } else { + fprintf(stderr, "\r %3d%% ", percent_done); + } + fflush(stderr); + } +} + + +GLOBAL(void) +start_progress_monitor (j_common_ptr cinfo, cd_progress_ptr progress) +{ + /* Enable progress display, unless trace output is on */ + if (cinfo->err->trace_level == 0) { + progress->pub.progress_monitor = progress_monitor; + progress->completed_extra_passes = 0; + progress->total_extra_passes = 0; + progress->percent_done = -1; + cinfo->progress = &progress->pub; + } +} + + +GLOBAL(void) +end_progress_monitor (j_common_ptr cinfo) +{ + /* Clear away progress display */ + if (cinfo->err->trace_level == 0) { + fprintf(stderr, "\r \r"); + fflush(stderr); + } +} + +#endif + + +/* + * Case-insensitive matching of possibly-abbreviated keyword switches. + * keyword is the constant keyword (must be lower case already), + * minchars is length of minimum legal abbreviation. + */ + +GLOBAL(boolean) +keymatch (char * arg, const char * keyword, int minchars) +{ + register int ca, ck; + register int nmatched = 0; + + while ((ca = *arg++) != '\0') { + if ((ck = *keyword++) == '\0') + return FALSE; /* arg longer than keyword, no good */ + if (isupper(ca)) /* force arg to lcase (assume ck is already) */ + ca = tolower(ca); + if (ca != ck) + return FALSE; /* no good */ + nmatched++; /* count matched characters */ + } + /* reached end of argument; fail if it's too short for unique abbrev */ + if (nmatched < minchars) + return FALSE; + return TRUE; /* A-OK */ +} + + +/* + * Routines to establish binary I/O mode for stdin and stdout. + * Non-Unix systems often require some hacking to get out of text mode. + */ + +GLOBAL(FILE *) +read_stdin (void) +{ + FILE * input_file = stdin; + +#ifdef USE_SETMODE /* need to hack file mode? */ + setmode(fileno(stdin), O_BINARY); +#endif +#ifdef USE_FDOPEN /* need to re-open in binary mode? */ + if ((input_file = fdopen(fileno(stdin), READ_BINARY)) == NULL) { + fprintf(stderr, "Cannot reopen stdin\n"); + exit(EXIT_FAILURE); + } +#endif + return input_file; +} + + +GLOBAL(FILE *) +write_stdout (void) +{ + FILE * output_file = stdout; + +#ifdef USE_SETMODE /* need to hack file mode? */ + setmode(fileno(stdout), O_BINARY); +#endif +#ifdef USE_FDOPEN /* need to re-open in binary mode? */ + if ((output_file = fdopen(fileno(stdout), WRITE_BINARY)) == NULL) { + fprintf(stderr, "Cannot reopen stdout\n"); + exit(EXIT_FAILURE); + } +#endif + return output_file; +} diff --git a/mk4/modimage/jpeg-6b/cdjpeg.h b/mk4/modimage/jpeg-6b/cdjpeg.h new file mode 100644 index 0000000..2b387b6 --- /dev/null +++ b/mk4/modimage/jpeg-6b/cdjpeg.h @@ -0,0 +1,184 @@ +/* + * cdjpeg.h + * + * Copyright (C) 1994-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains common declarations for the sample applications + * cjpeg and djpeg. It is NOT used by the core JPEG library. + */ + +#define JPEG_CJPEG_DJPEG /* define proper options in jconfig.h */ +#define JPEG_INTERNAL_OPTIONS /* cjpeg.c,djpeg.c need to see xxx_SUPPORTED */ +#include "jinclude.h" +#include "jpeglib.h" +#include "jerror.h" /* get library error codes too */ +#include "cderror.h" /* get application-specific error codes */ + + +/* + * Object interface for cjpeg's source file decoding modules + */ + +typedef struct cjpeg_source_struct * cjpeg_source_ptr; + +struct cjpeg_source_struct { + JMETHOD(void, start_input, (j_compress_ptr cinfo, + cjpeg_source_ptr sinfo)); + JMETHOD(JDIMENSION, get_pixel_rows, (j_compress_ptr cinfo, + cjpeg_source_ptr sinfo)); + JMETHOD(void, finish_input, (j_compress_ptr cinfo, + cjpeg_source_ptr sinfo)); + + FILE *input_file; + + JSAMPARRAY buffer; + JDIMENSION buffer_height; +}; + + +/* + * Object interface for djpeg's output file encoding modules + */ + +typedef struct djpeg_dest_struct * djpeg_dest_ptr; + +struct djpeg_dest_struct { + /* start_output is called after jpeg_start_decompress finishes. + * The color map will be ready at this time, if one is needed. + */ + JMETHOD(void, start_output, (j_decompress_ptr cinfo, + djpeg_dest_ptr dinfo)); + /* Emit the specified number of pixel rows from the buffer. */ + JMETHOD(void, put_pixel_rows, (j_decompress_ptr cinfo, + djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied)); + /* Finish up at the end of the image. */ + JMETHOD(void, finish_output, (j_decompress_ptr cinfo, + djpeg_dest_ptr dinfo)); + + /* Target file spec; filled in by djpeg.c after object is created. */ + FILE * output_file; + + /* Output pixel-row buffer. Created by module init or start_output. + * Width is cinfo->output_width * cinfo->output_components; + * height is buffer_height. + */ + JSAMPARRAY buffer; + JDIMENSION buffer_height; +}; + + +/* + * cjpeg/djpeg may need to perform extra passes to convert to or from + * the source/destination file format. The JPEG library does not know + * about these passes, but we'd like them to be counted by the progress + * monitor. We use an expanded progress monitor object to hold the + * additional pass count. + */ + +struct cdjpeg_progress_mgr { + struct jpeg_progress_mgr pub; /* fields known to JPEG library */ + int completed_extra_passes; /* extra passes completed */ + int total_extra_passes; /* total extra */ + /* last printed percentage stored here to avoid multiple printouts */ + int percent_done; +}; + +typedef struct cdjpeg_progress_mgr * cd_progress_ptr; + + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jinit_read_bmp jIRdBMP +#define jinit_write_bmp jIWrBMP +#define jinit_read_gif jIRdGIF +#define jinit_write_gif jIWrGIF +#define jinit_read_ppm jIRdPPM +#define jinit_write_ppm jIWrPPM +#define jinit_read_rle jIRdRLE +#define jinit_write_rle jIWrRLE +#define jinit_read_targa jIRdTarga +#define jinit_write_targa jIWrTarga +#define read_quant_tables RdQTables +#define read_scan_script RdScnScript +#define set_quant_slots SetQSlots +#define set_sample_factors SetSFacts +#define read_color_map RdCMap +#define enable_signal_catcher EnSigCatcher +#define start_progress_monitor StProgMon +#define end_progress_monitor EnProgMon +#define read_stdin RdStdin +#define write_stdout WrStdout +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + +/* Module selection routines for I/O modules. */ + +EXTERN(cjpeg_source_ptr) jinit_read_bmp JPP((j_compress_ptr cinfo)); +EXTERN(djpeg_dest_ptr) jinit_write_bmp JPP((j_decompress_ptr cinfo, + boolean is_os2)); +EXTERN(cjpeg_source_ptr) jinit_read_gif JPP((j_compress_ptr cinfo)); +EXTERN(djpeg_dest_ptr) jinit_write_gif JPP((j_decompress_ptr cinfo)); +EXTERN(cjpeg_source_ptr) jinit_read_ppm JPP((j_compress_ptr cinfo)); +EXTERN(djpeg_dest_ptr) jinit_write_ppm JPP((j_decompress_ptr cinfo)); +EXTERN(cjpeg_source_ptr) jinit_read_rle JPP((j_compress_ptr cinfo)); +EXTERN(djpeg_dest_ptr) jinit_write_rle JPP((j_decompress_ptr cinfo)); +EXTERN(cjpeg_source_ptr) jinit_read_targa JPP((j_compress_ptr cinfo)); +EXTERN(djpeg_dest_ptr) jinit_write_targa JPP((j_decompress_ptr cinfo)); + +/* cjpeg support routines (in rdswitch.c) */ + +EXTERN(boolean) read_quant_tables JPP((j_compress_ptr cinfo, char * filename, + int scale_factor, boolean force_baseline)); +EXTERN(boolean) read_scan_script JPP((j_compress_ptr cinfo, char * filename)); +EXTERN(boolean) set_quant_slots JPP((j_compress_ptr cinfo, char *arg)); +EXTERN(boolean) set_sample_factors JPP((j_compress_ptr cinfo, char *arg)); + +/* djpeg support routines (in rdcolmap.c) */ + +EXTERN(void) read_color_map JPP((j_decompress_ptr cinfo, FILE * infile)); + +/* common support routines (in cdjpeg.c) */ + +EXTERN(void) enable_signal_catcher JPP((j_common_ptr cinfo)); +EXTERN(void) start_progress_monitor JPP((j_common_ptr cinfo, + cd_progress_ptr progress)); +EXTERN(void) end_progress_monitor JPP((j_common_ptr cinfo)); +EXTERN(boolean) keymatch JPP((char * arg, const char * keyword, int minchars)); +EXTERN(FILE *) read_stdin JPP((void)); +EXTERN(FILE *) write_stdout JPP((void)); + +/* miscellaneous useful macros */ + +#ifdef DONT_USE_B_MODE /* define mode parameters for fopen() */ +#define READ_BINARY "r" +#define WRITE_BINARY "w" +#else +#ifdef VMS /* VMS is very nonstandard */ +#define READ_BINARY "rb", "ctx=stm" +#define WRITE_BINARY "wb", "ctx=stm" +#else /* standard ANSI-compliant case */ +#define READ_BINARY "rb" +#define WRITE_BINARY "wb" +#endif +#endif + +#ifndef EXIT_FAILURE /* define exit() codes if not provided */ +#define EXIT_FAILURE 1 +#endif +#ifndef EXIT_SUCCESS +#ifdef VMS +#define EXIT_SUCCESS 1 /* VMS is very nonstandard */ +#else +#define EXIT_SUCCESS 0 +#endif +#endif +#ifndef EXIT_WARNING +#ifdef VMS +#define EXIT_WARNING 1 /* VMS is very nonstandard */ +#else +#define EXIT_WARNING 2 +#endif +#endif diff --git a/mk4/modimage/jpeg-6b/change.log b/mk4/modimage/jpeg-6b/change.log new file mode 100644 index 0000000..74102c0 --- /dev/null +++ b/mk4/modimage/jpeg-6b/change.log @@ -0,0 +1,217 @@ +CHANGE LOG for Independent JPEG Group's JPEG software + + +Version 6b 27-Mar-1998 +----------------------- + +jpegtran has new features for lossless image transformations (rotation +and flipping) as well as "lossless" reduction to grayscale. + +jpegtran now copies comments by default; it has a -copy switch to enable +copying all APPn blocks as well, or to suppress comments. (Formerly it +always suppressed comments and APPn blocks.) jpegtran now also preserves +JFIF version and resolution information. + +New decompressor library feature: COM and APPn markers found in the input +file can be saved in memory for later use by the application. (Before, +you had to code this up yourself with a custom marker processor.) + +There is an unused field "void * client_data" now in compress and decompress +parameter structs; this may be useful in some applications. + +JFIF version number information is now saved by the decoder and accepted by +the encoder. jpegtran uses this to copy the source file's version number, +to ensure "jpegtran -copy all" won't create bogus files that contain JFXX +extensions but claim to be version 1.01. Applications that generate their +own JFXX extension markers also (finally) have a supported way to cause the +encoder to emit JFIF version number 1.02. + +djpeg's trace mode reports JFIF 1.02 thumbnail images as such, rather +than as unknown APP0 markers. + +In -verbose mode, djpeg and rdjpgcom will try to print the contents of +APP12 markers as text. Some digital cameras store useful text information +in APP12 markers. + +Handling of truncated data streams is more robust: blocks beyond the one in +which the error occurs will be output as uniform gray, or left unchanged +if decoding a progressive JPEG. The appearance no longer depends on the +Huffman tables being used. + +Huffman tables are checked for validity much more carefully than before. + +To avoid the Unisys LZW patent, djpeg's GIF output capability has been +changed to produce "uncompressed GIFs", and cjpeg's GIF input capability +has been removed altogether. We're not happy about it either, but there +seems to be no good alternative. + +The configure script now supports building libjpeg as a shared library +on many flavors of Unix (all the ones that GNU libtool knows how to +build shared libraries for). Use "./configure --enable-shared" to +try this out. + +New jconfig file and makefiles for Microsoft Visual C++ and Developer Studio. +Also, a jconfig file and a build script for Metrowerks CodeWarrior +on Apple Macintosh. makefile.dj has been updated for DJGPP v2, and there +are miscellaneous other minor improvements in the makefiles. + +jmemmac.c now knows how to create temporary files following Mac System 7 +conventions. + +djpeg's -map switch is now able to read raw-format PPM files reliably. + +cjpeg -progressive -restart no longer generates any unnecessary DRI markers. + +Multiple calls to jpeg_simple_progression for a single JPEG object +no longer leak memory. + + +Version 6a 7-Feb-96 +-------------------- + +Library initialization sequence modified to detect version mismatches +and struct field packing mismatches between library and calling application. +This change requires applications to be recompiled, but does not require +any application source code change. + +All routine declarations changed to the style "GLOBAL(type) name ...", +that is, GLOBAL, LOCAL, METHODDEF, EXTERN are now macros taking the +routine's return type as an argument. This makes it possible to add +Microsoft-style linkage keywords to all the routines by changing just +these macros. Note that any application code that was using these macros +will have to be changed. + +DCT coefficient quantization tables are now stored in normal array order +rather than zigzag order. Application code that calls jpeg_add_quant_table, +or otherwise manipulates quantization tables directly, will need to be +changed. If you need to make such code work with either older or newer +versions of the library, a test like "#if JPEG_LIB_VERSION >= 61" is +recommended. + +djpeg's trace capability now dumps DQT tables in natural order, not zigzag +order. This allows the trace output to be made into a "-qtables" file +more easily. + +New system-dependent memory manager module for use on Apple Macintosh. + +Fix bug in cjpeg's -smooth option: last one or two scanlines would be +duplicates of the prior line unless the image height mod 16 was 1 or 2. + +Repair minor problems in VMS, BCC, MC6 makefiles. + +New configure script based on latest GNU Autoconf. + +Correct the list of include files needed by MetroWerks C for ccommand(). + +Numerous small documentation updates. + + +Version 6 2-Aug-95 +------------------- + +Progressive JPEG support: library can read and write full progressive JPEG +files. A "buffered image" mode supports incremental decoding for on-the-fly +display of progressive images. Simply recompiling an existing IJG-v5-based +decoder with v6 should allow it to read progressive files, though of course +without any special progressive display. + +New "jpegtran" application performs lossless transcoding between different +JPEG formats; primarily, it can be used to convert baseline to progressive +JPEG and vice versa. In support of jpegtran, the library now allows lossless +reading and writing of JPEG files as DCT coefficient arrays. This ability +may be of use in other applications. + +Notes for programmers: +* We changed jpeg_start_decompress() to be able to suspend; this makes all +decoding modes available to suspending-input applications. However, +existing applications that use suspending input will need to be changed +to check the return value from jpeg_start_decompress(). You don't need to +do anything if you don't use a suspending data source. +* We changed the interface to the virtual array routines: access_virt_array +routines now take a count of the number of rows to access this time. The +last parameter to request_virt_array routines is now interpreted as the +maximum number of rows that may be accessed at once, but not necessarily +the height of every access. + + +Version 5b 15-Mar-95 +--------------------- + +Correct bugs with grayscale images having v_samp_factor > 1. + +jpeg_write_raw_data() now supports output suspension. + +Correct bugs in "configure" script for case of compiling in +a directory other than the one containing the source files. + +Repair bug in jquant1.c: sometimes didn't use as many colors as it could. + +Borland C makefile and jconfig file work under either MS-DOS or OS/2. + +Miscellaneous improvements to documentation. + + +Version 5a 7-Dec-94 +-------------------- + +Changed color conversion roundoff behavior so that grayscale values are +represented exactly. (This causes test image files to change.) + +Make ordered dither use 16x16 instead of 4x4 pattern for a small quality +improvement. + +New configure script based on latest GNU Autoconf. +Fix configure script to handle CFLAGS correctly. +Rename *.auto files to *.cfg, so that configure script still works if +file names have been truncated for DOS. + +Fix bug in rdbmp.c: didn't allow for extra data between header and image. + +Modify rdppm.c/wrppm.c to handle 2-byte raw PPM/PGM formats for 12-bit data. + +Fix several bugs in rdrle.c. + +NEED_SHORT_EXTERNAL_NAMES option was broken. + +Revise jerror.h/jerror.c for more flexibility in message table. + +Repair oversight in jmemname.c NO_MKTEMP case: file could be there +but unreadable. + + +Version 5 24-Sep-94 +-------------------- + +Version 5 represents a nearly complete redesign and rewrite of the IJG +software. Major user-visible changes include: + * Automatic configuration simplifies installation for most Unix systems. + * A range of speed vs. image quality tradeoffs are supported. + This includes resizing of an image during decompression: scaling down + by a factor of 1/2, 1/4, or 1/8 is handled very efficiently. + * New programs rdjpgcom and wrjpgcom allow insertion and extraction + of text comments in a JPEG file. + +The application programmer's interface to the library has changed completely. +Notable improvements include: + * We have eliminated the use of callback routines for handling the + uncompressed image data. The application now sees the library as a + set of routines that it calls to read or write image data on a + scanline-by-scanline basis. + * The application image data is represented in a conventional interleaved- + pixel format, rather than as a separate array for each color channel. + This can save a copying step in many programs. + * The handling of compressed data has been cleaned up: the application can + supply routines to source or sink the compressed data. It is possible to + suspend processing on source/sink buffer overrun, although this is not + supported in all operating modes. + * All static state has been eliminated from the library, so that multiple + instances of compression or decompression can be active concurrently. + * JPEG abbreviated datastream formats are supported, ie, quantization and + Huffman tables can be stored separately from the image data. + * And not only that, but the documentation of the library has improved + considerably! + + +The last widely used release before the version 5 rewrite was version 4A of +18-Feb-93. Change logs before that point have been discarded, since they +are not of much interest after the rewrite. diff --git a/mk4/modimage/jpeg-6b/cjpeg.1 b/mk4/modimage/jpeg-6b/cjpeg.1 new file mode 100644 index 0000000..d175a96 --- /dev/null +++ b/mk4/modimage/jpeg-6b/cjpeg.1 @@ -0,0 +1,292 @@ +.TH CJPEG 1 "20 March 1998" +.SH NAME +cjpeg \- compress an image file to a JPEG file +.SH SYNOPSIS +.B cjpeg +[ +.I options +] +[ +.I filename +] +.LP +.SH DESCRIPTION +.LP +.B cjpeg +compresses the named image file, or the standard input if no file is +named, and produces a JPEG/JFIF file on the standard output. +The currently supported input file formats are: PPM (PBMPLUS color +format), PGM (PBMPLUS gray-scale format), BMP, Targa, and RLE (Utah Raster +Toolkit format). (RLE is supported only if the URT library is available.) +.SH OPTIONS +All switch names may be abbreviated; for example, +.B \-grayscale +may be written +.B \-gray +or +.BR \-gr . +Most of the "basic" switches can be abbreviated to as little as one letter. +Upper and lower case are equivalent (thus +.B \-BMP +is the same as +.BR \-bmp ). +British spellings are also accepted (e.g., +.BR \-greyscale ), +though for brevity these are not mentioned below. +.PP +The basic switches are: +.TP +.BI \-quality " N" +Scale quantization tables to adjust image quality. Quality is 0 (worst) to +100 (best); default is 75. (See below for more info.) +.TP +.B \-grayscale +Create monochrome JPEG file from color input. Be sure to use this switch when +compressing a grayscale BMP file, because +.B cjpeg +isn't bright enough to notice whether a BMP file uses only shades of gray. +By saying +.BR \-grayscale , +you'll get a smaller JPEG file that takes less time to process. +.TP +.B \-optimize +Perform optimization of entropy encoding parameters. Without this, default +encoding parameters are used. +.B \-optimize +usually makes the JPEG file a little smaller, but +.B cjpeg +runs somewhat slower and needs much more memory. Image quality and speed of +decompression are unaffected by +.BR \-optimize . +.TP +.B \-progressive +Create progressive JPEG file (see below). +.TP +.B \-targa +Input file is Targa format. Targa files that contain an "identification" +field will not be automatically recognized by +.BR cjpeg ; +for such files you must specify +.B \-targa +to make +.B cjpeg +treat the input as Targa format. +For most Targa files, you won't need this switch. +.PP +The +.B \-quality +switch lets you trade off compressed file size against quality of the +reconstructed image: the higher the quality setting, the larger the JPEG file, +and the closer the output image will be to the original input. Normally you +want to use the lowest quality setting (smallest file) that decompresses into +something visually indistinguishable from the original image. For this +purpose the quality setting should be between 50 and 95; the default of 75 is +often about right. If you see defects at +.B \-quality +75, then go up 5 or 10 counts at a time until you are happy with the output +image. (The optimal setting will vary from one image to another.) +.PP +.B \-quality +100 will generate a quantization table of all 1's, minimizing loss in the +quantization step (but there is still information loss in subsampling, as well +as roundoff error). This setting is mainly of interest for experimental +purposes. Quality values above about 95 are +.B not +recommended for normal use; the compressed file size goes up dramatically for +hardly any gain in output image quality. +.PP +In the other direction, quality values below 50 will produce very small files +of low image quality. Settings around 5 to 10 might be useful in preparing an +index of a large image library, for example. Try +.B \-quality +2 (or so) for some amusing Cubist effects. (Note: quality +values below about 25 generate 2-byte quantization tables, which are +considered optional in the JPEG standard. +.B cjpeg +emits a warning message when you give such a quality value, because some +other JPEG programs may be unable to decode the resulting file. Use +.B \-baseline +if you need to ensure compatibility at low quality values.) +.PP +The +.B \-progressive +switch creates a "progressive JPEG" file. In this type of JPEG file, the data +is stored in multiple scans of increasing quality. If the file is being +transmitted over a slow communications link, the decoder can use the first +scan to display a low-quality image very quickly, and can then improve the +display with each subsequent scan. The final image is exactly equivalent to a +standard JPEG file of the same quality setting, and the total file size is +about the same --- often a little smaller. +.B Caution: +progressive JPEG is not yet widely implemented, so many decoders will be +unable to view a progressive JPEG file at all. +.PP +Switches for advanced users: +.TP +.B \-dct int +Use integer DCT method (default). +.TP +.B \-dct fast +Use fast integer DCT (less accurate). +.TP +.B \-dct float +Use floating-point DCT method. +The float method is very slightly more accurate than the int method, but is +much slower unless your machine has very fast floating-point hardware. Also +note that results of the floating-point method may vary slightly across +machines, while the integer methods should give the same results everywhere. +The fast integer method is much less accurate than the other two. +.TP +.BI \-restart " N" +Emit a JPEG restart marker every N MCU rows, or every N MCU blocks if "B" is +attached to the number. +.B \-restart 0 +(the default) means no restart markers. +.TP +.BI \-smooth " N" +Smooth the input image to eliminate dithering noise. N, ranging from 1 to +100, indicates the strength of smoothing. 0 (the default) means no smoothing. +.TP +.BI \-maxmemory " N" +Set limit for amount of memory to use in processing large images. Value is +in thousands of bytes, or millions of bytes if "M" is attached to the +number. For example, +.B \-max 4m +selects 4000000 bytes. If more space is needed, temporary files will be used. +.TP +.BI \-outfile " name" +Send output image to the named file, not to standard output. +.TP +.B \-verbose +Enable debug printout. More +.BR \-v 's +give more output. Also, version information is printed at startup. +.TP +.B \-debug +Same as +.BR \-verbose . +.PP +The +.B \-restart +option inserts extra markers that allow a JPEG decoder to resynchronize after +a transmission error. Without restart markers, any damage to a compressed +file will usually ruin the image from the point of the error to the end of the +image; with restart markers, the damage is usually confined to the portion of +the image up to the next restart marker. Of course, the restart markers +occupy extra space. We recommend +.B \-restart 1 +for images that will be transmitted across unreliable networks such as Usenet. +.PP +The +.B \-smooth +option filters the input to eliminate fine-scale noise. This is often useful +when converting dithered images to JPEG: a moderate smoothing factor of 10 to +50 gets rid of dithering patterns in the input file, resulting in a smaller +JPEG file and a better-looking image. Too large a smoothing factor will +visibly blur the image, however. +.PP +Switches for wizards: +.TP +.B \-baseline +Force baseline-compatible quantization tables to be generated. This clamps +quantization values to 8 bits even at low quality settings. (This switch is +poorly named, since it does not ensure that the output is actually baseline +JPEG. For example, you can use +.B \-baseline +and +.B \-progressive +together.) +.TP +.BI \-qtables " file" +Use the quantization tables given in the specified text file. +.TP +.BI \-qslots " N[,...]" +Select which quantization table to use for each color component. +.TP +.BI \-sample " HxV[,...]" +Set JPEG sampling factors for each color component. +.TP +.BI \-scans " file" +Use the scan script given in the specified text file. +.PP +The "wizard" switches are intended for experimentation with JPEG. If you +don't know what you are doing, \fBdon't use them\fR. These switches are +documented further in the file wizard.doc. +.SH EXAMPLES +.LP +This example compresses the PPM file foo.ppm with a quality factor of +60 and saves the output as foo.jpg: +.IP +.B cjpeg \-quality +.I 60 foo.ppm +.B > +.I foo.jpg +.SH HINTS +Color GIF files are not the ideal input for JPEG; JPEG is really intended for +compressing full-color (24-bit) images. In particular, don't try to convert +cartoons, line drawings, and other images that have only a few distinct +colors. GIF works great on these, JPEG does not. If you want to convert a +GIF to JPEG, you should experiment with +.BR cjpeg 's +.B \-quality +and +.B \-smooth +options to get a satisfactory conversion. +.B \-smooth 10 +or so is often helpful. +.PP +Avoid running an image through a series of JPEG compression/decompression +cycles. Image quality loss will accumulate; after ten or so cycles the image +may be noticeably worse than it was after one cycle. It's best to use a +lossless format while manipulating an image, then convert to JPEG format when +you are ready to file the image away. +.PP +The +.B \-optimize +option to +.B cjpeg +is worth using when you are making a "final" version for posting or archiving. +It's also a win when you are using low quality settings to make very small +JPEG files; the percentage improvement is often a lot more than it is on +larger files. (At present, +.B \-optimize +mode is always selected when generating progressive JPEG files.) +.SH ENVIRONMENT +.TP +.B JPEGMEM +If this environment variable is set, its value is the default memory limit. +The value is specified as described for the +.B \-maxmemory +switch. +.B JPEGMEM +overrides the default value specified when the program was compiled, and +itself is overridden by an explicit +.BR \-maxmemory . +.SH SEE ALSO +.BR djpeg (1), +.BR jpegtran (1), +.BR rdjpgcom (1), +.BR wrjpgcom (1) +.br +.BR ppm (5), +.BR pgm (5) +.br +Wallace, Gregory K. "The JPEG Still Picture Compression Standard", +Communications of the ACM, April 1991 (vol. 34, no. 4), pp. 30-44. +.SH AUTHOR +Independent JPEG Group +.SH BUGS +Arithmetic coding is not supported for legal reasons. +.PP +GIF input files are no longer supported, to avoid the Unisys LZW patent. +Use a Unisys-licensed program if you need to read a GIF file. (Conversion +of GIF files to JPEG is usually a bad idea anyway.) +.PP +Not all variants of BMP and Targa file formats are supported. +.PP +The +.B \-targa +switch is not a bug, it's a feature. (It would be a bug if the Targa format +designers had not been clueless.) +.PP +Still not as fast as we'd like. diff --git a/mk4/modimage/jpeg-6b/cjpeg.c b/mk4/modimage/jpeg-6b/cjpeg.c new file mode 100644 index 0000000..f2a929f --- /dev/null +++ b/mk4/modimage/jpeg-6b/cjpeg.c @@ -0,0 +1,606 @@ +/* + * cjpeg.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a command-line user interface for the JPEG compressor. + * It should work on any system with Unix- or MS-DOS-style command lines. + * + * Two different command line styles are permitted, depending on the + * compile-time switch TWO_FILE_COMMANDLINE: + * cjpeg [options] inputfile outputfile + * cjpeg [options] [inputfile] + * In the second style, output is always to standard output, which you'd + * normally redirect to a file or pipe to some other program. Input is + * either from a named file or from standard input (typically redirected). + * The second style is convenient on Unix but is unhelpful on systems that + * don't support pipes. Also, you MUST use the first style if your system + * doesn't do binary I/O to stdin/stdout. + * To simplify script writing, the "-outfile" switch is provided. The syntax + * cjpeg [options] -outfile outputfile inputfile + * works regardless of which command line style is used. + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ +#include "jversion.h" /* for version message */ + +#ifdef USE_CCOMMAND /* command-line reader for Macintosh */ +#ifdef __MWERKS__ +#include /* Metrowerks needs this */ +#include /* ... and this */ +#endif +#ifdef THINK_C +#include /* Think declares it here */ +#endif +#endif + + +/* Create the add-on message string table. */ + +#define JMESSAGE(code,string) string , + +static const char * const cdjpeg_message_table[] = { +#include "cderror.h" + NULL +}; + + +/* + * This routine determines what format the input file is, + * and selects the appropriate input-reading module. + * + * To determine which family of input formats the file belongs to, + * we may look only at the first byte of the file, since C does not + * guarantee that more than one character can be pushed back with ungetc. + * Looking at additional bytes would require one of these approaches: + * 1) assume we can fseek() the input file (fails for piped input); + * 2) assume we can push back more than one character (works in + * some C implementations, but unportable); + * 3) provide our own buffering (breaks input readers that want to use + * stdio directly, such as the RLE library); + * or 4) don't put back the data, and modify the input_init methods to assume + * they start reading after the start of file (also breaks RLE library). + * #1 is attractive for MS-DOS but is untenable on Unix. + * + * The most portable solution for file types that can't be identified by their + * first byte is to make the user tell us what they are. This is also the + * only approach for "raw" file types that contain only arbitrary values. + * We presently apply this method for Targa files. Most of the time Targa + * files start with 0x00, so we recognize that case. Potentially, however, + * a Targa file could start with any byte value (byte 0 is the length of the + * seldom-used ID field), so we provide a switch to force Targa input mode. + */ + +static boolean is_targa; /* records user -targa switch */ + + +LOCAL(cjpeg_source_ptr) +select_file_type (j_compress_ptr cinfo, FILE * infile) +{ + int c; + + if (is_targa) { +#ifdef TARGA_SUPPORTED + return jinit_read_targa(cinfo); +#else + ERREXIT(cinfo, JERR_TGA_NOTCOMP); +#endif + } + + if ((c = getc(infile)) == EOF) + ERREXIT(cinfo, JERR_INPUT_EMPTY); + if (ungetc(c, infile) == EOF) + ERREXIT(cinfo, JERR_UNGETC_FAILED); + + switch (c) { +#ifdef BMP_SUPPORTED + case 'B': + return jinit_read_bmp(cinfo); +#endif +#ifdef GIF_SUPPORTED + case 'G': + return jinit_read_gif(cinfo); +#endif +#ifdef PPM_SUPPORTED + case 'P': + return jinit_read_ppm(cinfo); +#endif +#ifdef RLE_SUPPORTED + case 'R': + return jinit_read_rle(cinfo); +#endif +#ifdef TARGA_SUPPORTED + case 0x00: + return jinit_read_targa(cinfo); +#endif + default: + ERREXIT(cinfo, JERR_UNKNOWN_FORMAT); + break; + } + + return NULL; /* suppress compiler warnings */ +} + + +/* + * Argument-parsing code. + * The switch parser is designed to be useful with DOS-style command line + * syntax, ie, intermixed switches and file names, where only the switches + * to the left of a given file name affect processing of that file. + * The main program in this file doesn't actually use this capability... + */ + + +static const char * progname; /* program name for error messages */ +static char * outfilename; /* for -outfile switch */ + + +LOCAL(void) +usage (void) +/* complain about bad command line */ +{ + fprintf(stderr, "usage: %s [switches] ", progname); +#ifdef TWO_FILE_COMMANDLINE + fprintf(stderr, "inputfile outputfile\n"); +#else + fprintf(stderr, "[inputfile]\n"); +#endif + + fprintf(stderr, "Switches (names may be abbreviated):\n"); + fprintf(stderr, " -quality N Compression quality (0..100; 5-95 is useful range)\n"); + fprintf(stderr, " -grayscale Create monochrome JPEG file\n"); +#ifdef ENTROPY_OPT_SUPPORTED + fprintf(stderr, " -optimize Optimize Huffman table (smaller file, but slow compression)\n"); +#endif +#ifdef C_PROGRESSIVE_SUPPORTED + fprintf(stderr, " -progressive Create progressive JPEG file\n"); +#endif +#ifdef TARGA_SUPPORTED + fprintf(stderr, " -targa Input file is Targa format (usually not needed)\n"); +#endif + fprintf(stderr, "Switches for advanced users:\n"); +#ifdef DCT_ISLOW_SUPPORTED + fprintf(stderr, " -dct int Use integer DCT method%s\n", + (JDCT_DEFAULT == JDCT_ISLOW ? " (default)" : "")); +#endif +#ifdef DCT_IFAST_SUPPORTED + fprintf(stderr, " -dct fast Use fast integer DCT (less accurate)%s\n", + (JDCT_DEFAULT == JDCT_IFAST ? " (default)" : "")); +#endif +#ifdef DCT_FLOAT_SUPPORTED + fprintf(stderr, " -dct float Use floating-point DCT method%s\n", + (JDCT_DEFAULT == JDCT_FLOAT ? " (default)" : "")); +#endif + fprintf(stderr, " -restart N Set restart interval in rows, or in blocks with B\n"); +#ifdef INPUT_SMOOTHING_SUPPORTED + fprintf(stderr, " -smooth N Smooth dithered input (N=1..100 is strength)\n"); +#endif + fprintf(stderr, " -maxmemory N Maximum memory to use (in kbytes)\n"); + fprintf(stderr, " -outfile name Specify name for output file\n"); + fprintf(stderr, " -verbose or -debug Emit debug output\n"); + fprintf(stderr, "Switches for wizards:\n"); +#ifdef C_ARITH_CODING_SUPPORTED + fprintf(stderr, " -arithmetic Use arithmetic coding\n"); +#endif + fprintf(stderr, " -baseline Force baseline quantization tables\n"); + fprintf(stderr, " -qtables file Use quantization tables given in file\n"); + fprintf(stderr, " -qslots N[,...] Set component quantization tables\n"); + fprintf(stderr, " -sample HxV[,...] Set component sampling factors\n"); +#ifdef C_MULTISCAN_FILES_SUPPORTED + fprintf(stderr, " -scans file Create multi-scan JPEG per script file\n"); +#endif + exit(EXIT_FAILURE); +} + + +LOCAL(int) +parse_switches (j_compress_ptr cinfo, int argc, char **argv, + int last_file_arg_seen, boolean for_real) +/* Parse optional switches. + * Returns argv[] index of first file-name argument (== argc if none). + * Any file names with indexes <= last_file_arg_seen are ignored; + * they have presumably been processed in a previous iteration. + * (Pass 0 for last_file_arg_seen on the first or only iteration.) + * for_real is FALSE on the first (dummy) pass; we may skip any expensive + * processing. + */ +{ + int argn; + char * arg; + int quality; /* -quality parameter */ + int q_scale_factor; /* scaling percentage for -qtables */ + boolean force_baseline; + boolean simple_progressive; + char * qtablefile = NULL; /* saves -qtables filename if any */ + char * qslotsarg = NULL; /* saves -qslots parm if any */ + char * samplearg = NULL; /* saves -sample parm if any */ + char * scansarg = NULL; /* saves -scans parm if any */ + + /* Set up default JPEG parameters. */ + /* Note that default -quality level need not, and does not, + * match the default scaling for an explicit -qtables argument. + */ + quality = 75; /* default -quality value */ + q_scale_factor = 100; /* default to no scaling for -qtables */ + force_baseline = FALSE; /* by default, allow 16-bit quantizers */ + simple_progressive = FALSE; + is_targa = FALSE; + outfilename = NULL; + cinfo->err->trace_level = 0; + + /* Scan command line options, adjust parameters */ + + for (argn = 1; argn < argc; argn++) { + arg = argv[argn]; + if (*arg != '-') { + /* Not a switch, must be a file name argument */ + if (argn <= last_file_arg_seen) { + outfilename = NULL; /* -outfile applies to just one input file */ + continue; /* ignore this name if previously processed */ + } + break; /* else done parsing switches */ + } + arg++; /* advance past switch marker character */ + + if (keymatch(arg, "arithmetic", 1)) { + /* Use arithmetic coding. */ +#ifdef C_ARITH_CODING_SUPPORTED + cinfo->arith_code = TRUE; +#else + fprintf(stderr, "%s: sorry, arithmetic coding not supported\n", + progname); + exit(EXIT_FAILURE); +#endif + + } else if (keymatch(arg, "baseline", 1)) { + /* Force baseline-compatible output (8-bit quantizer values). */ + force_baseline = TRUE; + + } else if (keymatch(arg, "dct", 2)) { + /* Select DCT algorithm. */ + if (++argn >= argc) /* advance to next argument */ + usage(); + if (keymatch(argv[argn], "int", 1)) { + cinfo->dct_method = JDCT_ISLOW; + } else if (keymatch(argv[argn], "fast", 2)) { + cinfo->dct_method = JDCT_IFAST; + } else if (keymatch(argv[argn], "float", 2)) { + cinfo->dct_method = JDCT_FLOAT; + } else + usage(); + + } else if (keymatch(arg, "debug", 1) || keymatch(arg, "verbose", 1)) { + /* Enable debug printouts. */ + /* On first -d, print version identification */ + static boolean printed_version = FALSE; + + if (! printed_version) { + fprintf(stderr, "Independent JPEG Group's CJPEG, version %s\n%s\n", + JVERSION, JCOPYRIGHT); + printed_version = TRUE; + } + cinfo->err->trace_level++; + + } else if (keymatch(arg, "grayscale", 2) || keymatch(arg, "greyscale",2)) { + /* Force a monochrome JPEG file to be generated. */ + jpeg_set_colorspace(cinfo, JCS_GRAYSCALE); + + } else if (keymatch(arg, "maxmemory", 3)) { + /* Maximum memory in Kb (or Mb with 'm'). */ + long lval; + char ch = 'x'; + + if (++argn >= argc) /* advance to next argument */ + usage(); + if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1) + usage(); + if (ch == 'm' || ch == 'M') + lval *= 1000L; + cinfo->mem->max_memory_to_use = lval * 1000L; + + } else if (keymatch(arg, "optimize", 1) || keymatch(arg, "optimise", 1)) { + /* Enable entropy parm optimization. */ +#ifdef ENTROPY_OPT_SUPPORTED + cinfo->optimize_coding = TRUE; +#else + fprintf(stderr, "%s: sorry, entropy optimization was not compiled\n", + progname); + exit(EXIT_FAILURE); +#endif + + } else if (keymatch(arg, "outfile", 4)) { + /* Set output file name. */ + if (++argn >= argc) /* advance to next argument */ + usage(); + outfilename = argv[argn]; /* save it away for later use */ + + } else if (keymatch(arg, "progressive", 1)) { + /* Select simple progressive mode. */ +#ifdef C_PROGRESSIVE_SUPPORTED + simple_progressive = TRUE; + /* We must postpone execution until num_components is known. */ +#else + fprintf(stderr, "%s: sorry, progressive output was not compiled\n", + progname); + exit(EXIT_FAILURE); +#endif + + } else if (keymatch(arg, "quality", 1)) { + /* Quality factor (quantization table scaling factor). */ + if (++argn >= argc) /* advance to next argument */ + usage(); + if (sscanf(argv[argn], "%d", &quality) != 1) + usage(); + /* Change scale factor in case -qtables is present. */ + q_scale_factor = jpeg_quality_scaling(quality); + + } else if (keymatch(arg, "qslots", 2)) { + /* Quantization table slot numbers. */ + if (++argn >= argc) /* advance to next argument */ + usage(); + qslotsarg = argv[argn]; + /* Must delay setting qslots until after we have processed any + * colorspace-determining switches, since jpeg_set_colorspace sets + * default quant table numbers. + */ + + } else if (keymatch(arg, "qtables", 2)) { + /* Quantization tables fetched from file. */ + if (++argn >= argc) /* advance to next argument */ + usage(); + qtablefile = argv[argn]; + /* We postpone actually reading the file in case -quality comes later. */ + + } else if (keymatch(arg, "restart", 1)) { + /* Restart interval in MCU rows (or in MCUs with 'b'). */ + long lval; + char ch = 'x'; + + if (++argn >= argc) /* advance to next argument */ + usage(); + if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1) + usage(); + if (lval < 0 || lval > 65535L) + usage(); + if (ch == 'b' || ch == 'B') { + cinfo->restart_interval = (unsigned int) lval; + cinfo->restart_in_rows = 0; /* else prior '-restart n' overrides me */ + } else { + cinfo->restart_in_rows = (int) lval; + /* restart_interval will be computed during startup */ + } + + } else if (keymatch(arg, "sample", 2)) { + /* Set sampling factors. */ + if (++argn >= argc) /* advance to next argument */ + usage(); + samplearg = argv[argn]; + /* Must delay setting sample factors until after we have processed any + * colorspace-determining switches, since jpeg_set_colorspace sets + * default sampling factors. + */ + + } else if (keymatch(arg, "scans", 2)) { + /* Set scan script. */ +#ifdef C_MULTISCAN_FILES_SUPPORTED + if (++argn >= argc) /* advance to next argument */ + usage(); + scansarg = argv[argn]; + /* We must postpone reading the file in case -progressive appears. */ +#else + fprintf(stderr, "%s: sorry, multi-scan output was not compiled\n", + progname); + exit(EXIT_FAILURE); +#endif + + } else if (keymatch(arg, "smooth", 2)) { + /* Set input smoothing factor. */ + int val; + + if (++argn >= argc) /* advance to next argument */ + usage(); + if (sscanf(argv[argn], "%d", &val) != 1) + usage(); + if (val < 0 || val > 100) + usage(); + cinfo->smoothing_factor = val; + + } else if (keymatch(arg, "targa", 1)) { + /* Input file is Targa format. */ + is_targa = TRUE; + + } else { + usage(); /* bogus switch */ + } + } + + /* Post-switch-scanning cleanup */ + + if (for_real) { + + /* Set quantization tables for selected quality. */ + /* Some or all may be overridden if -qtables is present. */ + jpeg_set_quality(cinfo, quality, force_baseline); + + if (qtablefile != NULL) /* process -qtables if it was present */ + if (! read_quant_tables(cinfo, qtablefile, + q_scale_factor, force_baseline)) + usage(); + + if (qslotsarg != NULL) /* process -qslots if it was present */ + if (! set_quant_slots(cinfo, qslotsarg)) + usage(); + + if (samplearg != NULL) /* process -sample if it was present */ + if (! set_sample_factors(cinfo, samplearg)) + usage(); + +#ifdef C_PROGRESSIVE_SUPPORTED + if (simple_progressive) /* process -progressive; -scans can override */ + jpeg_simple_progression(cinfo); +#endif + +#ifdef C_MULTISCAN_FILES_SUPPORTED + if (scansarg != NULL) /* process -scans if it was present */ + if (! read_scan_script(cinfo, scansarg)) + usage(); +#endif + } + + return argn; /* return index of next arg (file name) */ +} + + +/* + * The main program. + */ + +int +main (int argc, char **argv) +{ + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; +#ifdef PROGRESS_REPORT + struct cdjpeg_progress_mgr progress; +#endif + int file_index; + cjpeg_source_ptr src_mgr; + FILE * input_file; + FILE * output_file; + JDIMENSION num_scanlines; + + /* On Mac, fetch a command line. */ +#ifdef USE_CCOMMAND + argc = ccommand(&argv); +#endif + + progname = argv[0]; + if (progname == NULL || progname[0] == 0) + progname = "cjpeg"; /* in case C library doesn't provide it */ + + /* Initialize the JPEG compression object with default error handling. */ + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_compress(&cinfo); + /* Add some application-specific error messages (from cderror.h) */ + jerr.addon_message_table = cdjpeg_message_table; + jerr.first_addon_message = JMSG_FIRSTADDONCODE; + jerr.last_addon_message = JMSG_LASTADDONCODE; + + /* Now safe to enable signal catcher. */ +#ifdef NEED_SIGNAL_CATCHER + enable_signal_catcher((j_common_ptr) &cinfo); +#endif + + /* Initialize JPEG parameters. + * Much of this may be overridden later. + * In particular, we don't yet know the input file's color space, + * but we need to provide some value for jpeg_set_defaults() to work. + */ + + cinfo.in_color_space = JCS_RGB; /* arbitrary guess */ + jpeg_set_defaults(&cinfo); + + /* Scan command line to find file names. + * It is convenient to use just one switch-parsing routine, but the switch + * values read here are ignored; we will rescan the switches after opening + * the input file. + */ + + file_index = parse_switches(&cinfo, argc, argv, 0, FALSE); + +#ifdef TWO_FILE_COMMANDLINE + /* Must have either -outfile switch or explicit output file name */ + if (outfilename == NULL) { + if (file_index != argc-2) { + fprintf(stderr, "%s: must name one input and one output file\n", + progname); + usage(); + } + outfilename = argv[file_index+1]; + } else { + if (file_index != argc-1) { + fprintf(stderr, "%s: must name one input and one output file\n", + progname); + usage(); + } + } +#else + /* Unix style: expect zero or one file name */ + if (file_index < argc-1) { + fprintf(stderr, "%s: only one input file\n", progname); + usage(); + } +#endif /* TWO_FILE_COMMANDLINE */ + + /* Open the input file. */ + if (file_index < argc) { + if ((input_file = fopen(argv[file_index], READ_BINARY)) == NULL) { + fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index]); + exit(EXIT_FAILURE); + } + } else { + /* default input file is stdin */ + input_file = read_stdin(); + } + + /* Open the output file. */ + if (outfilename != NULL) { + if ((output_file = fopen(outfilename, WRITE_BINARY)) == NULL) { + fprintf(stderr, "%s: can't open %s\n", progname, outfilename); + exit(EXIT_FAILURE); + } + } else { + /* default output file is stdout */ + output_file = write_stdout(); + } + +#ifdef PROGRESS_REPORT + start_progress_monitor((j_common_ptr) &cinfo, &progress); +#endif + + /* Figure out the input file format, and set up to read it. */ + src_mgr = select_file_type(&cinfo, input_file); + src_mgr->input_file = input_file; + + /* Read the input file header to obtain file size & colorspace. */ + (*src_mgr->start_input) (&cinfo, src_mgr); + + /* Now that we know input colorspace, fix colorspace-dependent defaults */ + jpeg_default_colorspace(&cinfo); + + /* Adjust default compression parameters by re-parsing the options */ + file_index = parse_switches(&cinfo, argc, argv, 0, TRUE); + + /* Specify data destination for compression */ + jpeg_stdio_dest(&cinfo, output_file); + + /* Start compressor */ + jpeg_start_compress(&cinfo, TRUE); + + /* Process data */ + while (cinfo.next_scanline < cinfo.image_height) { + num_scanlines = (*src_mgr->get_pixel_rows) (&cinfo, src_mgr); + (void) jpeg_write_scanlines(&cinfo, src_mgr->buffer, num_scanlines); + } + + /* Finish compression and release memory */ + (*src_mgr->finish_input) (&cinfo, src_mgr); + jpeg_finish_compress(&cinfo); + jpeg_destroy_compress(&cinfo); + + /* Close files, if we opened them */ + if (input_file != stdin) + fclose(input_file); + if (output_file != stdout) + fclose(output_file); + +#ifdef PROGRESS_REPORT + end_progress_monitor((j_common_ptr) &cinfo); +#endif + + /* All done. */ + exit(jerr.num_warnings ? EXIT_WARNING : EXIT_SUCCESS); + return 0; /* suppress no-return-value warnings */ +} diff --git a/mk4/modimage/jpeg-6b/ckconfig.c b/mk4/modimage/jpeg-6b/ckconfig.c new file mode 100644 index 0000000..34baf79 --- /dev/null +++ b/mk4/modimage/jpeg-6b/ckconfig.c @@ -0,0 +1,402 @@ +/* + * ckconfig.c + * + * Copyright (C) 1991-1994, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + */ + +/* + * This program is intended to help you determine how to configure the JPEG + * software for installation on a particular system. The idea is to try to + * compile and execute this program. If your compiler fails to compile the + * program, make changes as indicated in the comments below. Once you can + * compile the program, run it, and it will produce a "jconfig.h" file for + * your system. + * + * As a general rule, each time you try to compile this program, + * pay attention only to the *first* error message you get from the compiler. + * Many C compilers will issue lots of spurious error messages once they + * have gotten confused. Go to the line indicated in the first error message, + * and read the comments preceding that line to see what to change. + * + * Almost all of the edits you may need to make to this program consist of + * changing a line that reads "#define SOME_SYMBOL" to "#undef SOME_SYMBOL", + * or vice versa. This is called defining or undefining that symbol. + */ + + +/* First we must see if your system has the include files we need. + * We start out with the assumption that your system has all the ANSI-standard + * include files. If you get any error trying to include one of these files, + * undefine the corresponding HAVE_xxx symbol. + */ + +#define HAVE_STDDEF_H /* replace 'define' by 'undef' if error here */ +#ifdef HAVE_STDDEF_H /* next line will be skipped if you undef... */ +#include +#endif + +#define HAVE_STDLIB_H /* same thing for stdlib.h */ +#ifdef HAVE_STDLIB_H +#include +#endif + +#include /* If you ain't got this, you ain't got C. */ + +/* We have to see if your string functions are defined by + * strings.h (old BSD convention) or string.h (everybody else). + * We try the non-BSD convention first; define NEED_BSD_STRINGS + * if the compiler says it can't find string.h. + */ + +#undef NEED_BSD_STRINGS + +#ifdef NEED_BSD_STRINGS +#include +#else +#include +#endif + +/* On some systems (especially older Unix machines), type size_t is + * defined only in the include file . If you get a failure + * on the size_t test below, try defining NEED_SYS_TYPES_H. + */ + +#undef NEED_SYS_TYPES_H /* start by assuming we don't need it */ +#ifdef NEED_SYS_TYPES_H +#include +#endif + + +/* Usually type size_t is defined in one of the include files we've included + * above. If not, you'll get an error on the "typedef size_t my_size_t;" line. + * In that case, first try defining NEED_SYS_TYPES_H just above. + * If that doesn't work, you'll have to search through your system library + * to figure out which include file defines "size_t". Look for a line that + * says "typedef something-or-other size_t;". Then, change the line below + * that says "#include " to instead include the file + * you found size_t in, and define NEED_SPECIAL_INCLUDE. If you can't find + * type size_t anywhere, try replacing "#include " with + * "typedef unsigned int size_t;". + */ + +#undef NEED_SPECIAL_INCLUDE /* assume we DON'T need it, for starters */ + +#ifdef NEED_SPECIAL_INCLUDE +#include +#endif + +typedef size_t my_size_t; /* The payoff: do we have size_t now? */ + + +/* The next question is whether your compiler supports ANSI-style function + * prototypes. You need to know this in order to choose between using + * makefile.ansi and using makefile.unix. + * The #define line below is set to assume you have ANSI function prototypes. + * If you get an error in this group of lines, undefine HAVE_PROTOTYPES. + */ + +#define HAVE_PROTOTYPES + +#ifdef HAVE_PROTOTYPES +int testfunction (int arg1, int * arg2); /* check prototypes */ + +struct methods_struct { /* check method-pointer declarations */ + int (*error_exit) (char *msgtext); + int (*trace_message) (char *msgtext); + int (*another_method) (void); +}; + +int testfunction (int arg1, int * arg2) /* check definitions */ +{ + return arg2[arg1]; +} + +int test2function (void) /* check void arg list */ +{ + return 0; +} +#endif + + +/* Now we want to find out if your compiler knows what "unsigned char" means. + * If you get an error on the "unsigned char un_char;" line, + * then undefine HAVE_UNSIGNED_CHAR. + */ + +#define HAVE_UNSIGNED_CHAR + +#ifdef HAVE_UNSIGNED_CHAR +unsigned char un_char; +#endif + + +/* Now we want to find out if your compiler knows what "unsigned short" means. + * If you get an error on the "unsigned short un_short;" line, + * then undefine HAVE_UNSIGNED_SHORT. + */ + +#define HAVE_UNSIGNED_SHORT + +#ifdef HAVE_UNSIGNED_SHORT +unsigned short un_short; +#endif + + +/* Now we want to find out if your compiler understands type "void". + * If you get an error anywhere in here, undefine HAVE_VOID. + */ + +#define HAVE_VOID + +#ifdef HAVE_VOID +/* Caution: a C++ compiler will insist on complete prototypes */ +typedef void * void_ptr; /* check void * */ +#ifdef HAVE_PROTOTYPES /* check ptr to function returning void */ +typedef void (*void_func) (int a, int b); +#else +typedef void (*void_func) (); +#endif + +#ifdef HAVE_PROTOTYPES /* check void function result */ +void test3function (void_ptr arg1, void_func arg2) +#else +void test3function (arg1, arg2) + void_ptr arg1; + void_func arg2; +#endif +{ + char * locptr = (char *) arg1; /* check casting to and from void * */ + arg1 = (void *) locptr; + (*arg2) (1, 2); /* check call of fcn returning void */ +} +#endif + + +/* Now we want to find out if your compiler knows what "const" means. + * If you get an error here, undefine HAVE_CONST. + */ + +#define HAVE_CONST + +#ifdef HAVE_CONST +static const int carray[3] = {1, 2, 3}; + +#ifdef HAVE_PROTOTYPES +int test4function (const int arg1) +#else +int test4function (arg1) + const int arg1; +#endif +{ + return carray[arg1]; +} +#endif + + +/* If you get an error or warning about this structure definition, + * define INCOMPLETE_TYPES_BROKEN. + */ + +#undef INCOMPLETE_TYPES_BROKEN + +#ifndef INCOMPLETE_TYPES_BROKEN +typedef struct undefined_structure * undef_struct_ptr; +#endif + + +/* If you get an error about duplicate names, + * define NEED_SHORT_EXTERNAL_NAMES. + */ + +#undef NEED_SHORT_EXTERNAL_NAMES + +#ifndef NEED_SHORT_EXTERNAL_NAMES + +int possibly_duplicate_function () +{ + return 0; +} + +int possibly_dupli_function () +{ + return 1; +} + +#endif + + + +/************************************************************************ + * OK, that's it. You should not have to change anything beyond this + * point in order to compile and execute this program. (You might get + * some warnings, but you can ignore them.) + * When you run the program, it will make a couple more tests that it + * can do automatically, and then it will create jconfig.h and print out + * any additional suggestions it has. + ************************************************************************ + */ + + +#ifdef HAVE_PROTOTYPES +int is_char_signed (int arg) +#else +int is_char_signed (arg) + int arg; +#endif +{ + if (arg == 189) { /* expected result for unsigned char */ + return 0; /* type char is unsigned */ + } + else if (arg != -67) { /* expected result for signed char */ + printf("Hmm, it seems 'char' is not eight bits wide on your machine.\n"); + printf("I fear the JPEG software will not work at all.\n\n"); + } + return 1; /* assume char is signed otherwise */ +} + + +#ifdef HAVE_PROTOTYPES +int is_shifting_signed (long arg) +#else +int is_shifting_signed (arg) + long arg; +#endif +/* See whether right-shift on a long is signed or not. */ +{ + long res = arg >> 4; + + if (res == -0x7F7E80CL) { /* expected result for signed shift */ + return 1; /* right shift is signed */ + } + /* see if unsigned-shift hack will fix it. */ + /* we can't just test exact value since it depends on width of long... */ + res |= (~0L) << (32-4); + if (res == -0x7F7E80CL) { /* expected result now? */ + return 0; /* right shift is unsigned */ + } + printf("Right shift isn't acting as I expect it to.\n"); + printf("I fear the JPEG software will not work at all.\n\n"); + return 0; /* try it with unsigned anyway */ +} + + +#ifdef HAVE_PROTOTYPES +int main (int argc, char ** argv) +#else +int main (argc, argv) + int argc; + char ** argv; +#endif +{ + char signed_char_check = (char) (-67); + FILE *outfile; + + /* Attempt to write jconfig.h */ + if ((outfile = fopen("jconfig.h", "w")) == NULL) { + printf("Failed to write jconfig.h\n"); + return 1; + } + + /* Write out all the info */ + fprintf(outfile, "/* jconfig.h --- generated by ckconfig.c */\n"); + fprintf(outfile, "/* see jconfig.doc for explanations */\n\n"); +#ifdef HAVE_PROTOTYPES + fprintf(outfile, "#define HAVE_PROTOTYPES\n"); +#else + fprintf(outfile, "#undef HAVE_PROTOTYPES\n"); +#endif +#ifdef HAVE_UNSIGNED_CHAR + fprintf(outfile, "#define HAVE_UNSIGNED_CHAR\n"); +#else + fprintf(outfile, "#undef HAVE_UNSIGNED_CHAR\n"); +#endif +#ifdef HAVE_UNSIGNED_SHORT + fprintf(outfile, "#define HAVE_UNSIGNED_SHORT\n"); +#else + fprintf(outfile, "#undef HAVE_UNSIGNED_SHORT\n"); +#endif +#ifdef HAVE_VOID + fprintf(outfile, "/* #define void char */\n"); +#else + fprintf(outfile, "#define void char\n"); +#endif +#ifdef HAVE_CONST + fprintf(outfile, "/* #define const */\n"); +#else + fprintf(outfile, "#define const\n"); +#endif + if (is_char_signed((int) signed_char_check)) + fprintf(outfile, "#undef CHAR_IS_UNSIGNED\n"); + else + fprintf(outfile, "#define CHAR_IS_UNSIGNED\n"); +#ifdef HAVE_STDDEF_H + fprintf(outfile, "#define HAVE_STDDEF_H\n"); +#else + fprintf(outfile, "#undef HAVE_STDDEF_H\n"); +#endif +#ifdef HAVE_STDLIB_H + fprintf(outfile, "#define HAVE_STDLIB_H\n"); +#else + fprintf(outfile, "#undef HAVE_STDLIB_H\n"); +#endif +#ifdef NEED_BSD_STRINGS + fprintf(outfile, "#define NEED_BSD_STRINGS\n"); +#else + fprintf(outfile, "#undef NEED_BSD_STRINGS\n"); +#endif +#ifdef NEED_SYS_TYPES_H + fprintf(outfile, "#define NEED_SYS_TYPES_H\n"); +#else + fprintf(outfile, "#undef NEED_SYS_TYPES_H\n"); +#endif + fprintf(outfile, "#undef NEED_FAR_POINTERS\n"); +#ifdef NEED_SHORT_EXTERNAL_NAMES + fprintf(outfile, "#define NEED_SHORT_EXTERNAL_NAMES\n"); +#else + fprintf(outfile, "#undef NEED_SHORT_EXTERNAL_NAMES\n"); +#endif +#ifdef INCOMPLETE_TYPES_BROKEN + fprintf(outfile, "#define INCOMPLETE_TYPES_BROKEN\n"); +#else + fprintf(outfile, "#undef INCOMPLETE_TYPES_BROKEN\n"); +#endif + fprintf(outfile, "\n#ifdef JPEG_INTERNALS\n\n"); + if (is_shifting_signed(-0x7F7E80B1L)) + fprintf(outfile, "#undef RIGHT_SHIFT_IS_UNSIGNED\n"); + else + fprintf(outfile, "#define RIGHT_SHIFT_IS_UNSIGNED\n"); + fprintf(outfile, "\n#endif /* JPEG_INTERNALS */\n"); + fprintf(outfile, "\n#ifdef JPEG_CJPEG_DJPEG\n\n"); + fprintf(outfile, "#define BMP_SUPPORTED /* BMP image file format */\n"); + fprintf(outfile, "#define GIF_SUPPORTED /* GIF image file format */\n"); + fprintf(outfile, "#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */\n"); + fprintf(outfile, "#undef RLE_SUPPORTED /* Utah RLE image file format */\n"); + fprintf(outfile, "#define TARGA_SUPPORTED /* Targa image file format */\n\n"); + fprintf(outfile, "#undef TWO_FILE_COMMANDLINE /* You may need this on non-Unix systems */\n"); + fprintf(outfile, "#undef NEED_SIGNAL_CATCHER /* Define this if you use jmemname.c */\n"); + fprintf(outfile, "#undef DONT_USE_B_MODE\n"); + fprintf(outfile, "/* #define PROGRESS_REPORT */ /* optional */\n"); + fprintf(outfile, "\n#endif /* JPEG_CJPEG_DJPEG */\n"); + + /* Close the jconfig.h file */ + fclose(outfile); + + /* User report */ + printf("Configuration check for Independent JPEG Group's software done.\n"); + printf("\nI have written the jconfig.h file for you.\n\n"); +#ifdef HAVE_PROTOTYPES + printf("You should use makefile.ansi as the starting point for your Makefile.\n"); +#else + printf("You should use makefile.unix as the starting point for your Makefile.\n"); +#endif + +#ifdef NEED_SPECIAL_INCLUDE + printf("\nYou'll need to change jconfig.h to include the system include file\n"); + printf("that you found type size_t in, or add a direct definition of type\n"); + printf("size_t if that's what you used. Just add it to the end.\n"); +#endif + + return 0; +} diff --git a/mk4/modimage/jpeg-6b/coderules.doc b/mk4/modimage/jpeg-6b/coderules.doc new file mode 100644 index 0000000..0ab5d9b --- /dev/null +++ b/mk4/modimage/jpeg-6b/coderules.doc @@ -0,0 +1,118 @@ +IJG JPEG LIBRARY: CODING RULES + +Copyright (C) 1991-1996, Thomas G. Lane. +This file is part of the Independent JPEG Group's software. +For conditions of distribution and use, see the accompanying README file. + + +Since numerous people will be contributing code and bug fixes, it's important +to establish a common coding style. The goal of using similar coding styles +is much more important than the details of just what that style is. + +In general we follow the recommendations of "Recommended C Style and Coding +Standards" revision 6.1 (Cannon et al. as modified by Spencer, Keppel and +Brader). This document is available in the IJG FTP archive (see +jpeg/doc/cstyle.ms.tbl.Z, or cstyle.txt.Z for those without nroff/tbl). + +Block comments should be laid out thusly: + +/* + * Block comments in this style. + */ + +We indent statements in K&R style, e.g., + if (test) { + then-part; + } else { + else-part; + } +with two spaces per indentation level. (This indentation convention is +handled automatically by GNU Emacs and many other text editors.) + +Multi-word names should be written in lower case with underscores, e.g., +multi_word_name (not multiWordName). Preprocessor symbols and enum constants +are similar but upper case (MULTI_WORD_NAME). Names should be unique within +the first fifteen characters. (On some older systems, global names must be +unique within six characters. We accommodate this without cluttering the +source code by using macros to substitute shorter names.) + +We use function prototypes everywhere; we rely on automatic source code +transformation to feed prototype-less C compilers. Transformation is done +by the simple and portable tool 'ansi2knr.c' (courtesy of Ghostscript). +ansi2knr is not very bright, so it imposes a format requirement on function +declarations: the function name MUST BEGIN IN COLUMN 1. Thus all functions +should be written in the following style: + +LOCAL(int *) +function_name (int a, char *b) +{ + code... +} + +Note that each function definition must begin with GLOBAL(type), LOCAL(type), +or METHODDEF(type). These macros expand to "static type" or just "type" as +appropriate. They provide a readable indication of the routine's usage and +can readily be changed for special needs. (For instance, special linkage +keywords can be inserted for use in Windows DLLs.) + +ansi2knr does not transform method declarations (function pointers in +structs). We handle these with a macro JMETHOD, defined as + #ifdef HAVE_PROTOTYPES + #define JMETHOD(type,methodname,arglist) type (*methodname) arglist + #else + #define JMETHOD(type,methodname,arglist) type (*methodname) () + #endif +which is used like this: + struct function_pointers { + JMETHOD(void, init_entropy_encoder, (int somearg, jparms *jp)); + JMETHOD(void, term_entropy_encoder, (void)); + }; +Note the set of parentheses surrounding the parameter list. + +A similar solution is used for forward and external function declarations +(see the EXTERN and JPP macros). + +If the code is to work on non-ANSI compilers, we cannot rely on a prototype +declaration to coerce actual parameters into the right types. Therefore, use +explicit casts on actual parameters whenever the actual parameter type is not +identical to the formal parameter. Beware of implicit conversions to "int". + +It seems there are some non-ANSI compilers in which the sizeof() operator +is defined to return int, yet size_t is defined as long. Needless to say, +this is brain-damaged. Always use the SIZEOF() macro in place of sizeof(), +so that the result is guaranteed to be of type size_t. + + +The JPEG library is intended to be used within larger programs. Furthermore, +we want it to be reentrant so that it can be used by applications that process +multiple images concurrently. The following rules support these requirements: + +1. Avoid direct use of file I/O, "malloc", error report printouts, etc; +pass these through the common routines provided. + +2. Minimize global namespace pollution. Functions should be declared static +wherever possible. (Note that our method-based calling conventions help this +a lot: in many modules only the initialization function will ever need to be +called directly, so only that function need be externally visible.) All +global function names should begin with "jpeg_", and should have an +abbreviated name (unique in the first six characters) substituted by macro +when NEED_SHORT_EXTERNAL_NAMES is set. + +3. Don't use global variables; anything that must be used in another module +should be in the common data structures. + +4. Don't use static variables except for read-only constant tables. Variables +that should be private to a module can be placed into private structures (see +the system architecture document, structure.doc). + +5. Source file names should begin with "j" for files that are part of the +library proper; source files that are not part of the library, such as cjpeg.c +and djpeg.c, do not begin with "j". Keep source file names to eight +characters (plus ".c" or ".h", etc) to make life easy for MS-DOSers. Keep +compression and decompression code in separate source files --- some +applications may want only one half of the library. + +Note: these rules (particularly #4) are not followed religiously in the +modules that are used in cjpeg/djpeg but are not part of the JPEG library +proper. Those modules are not really intended to be used in other +applications. diff --git a/mk4/modimage/jpeg-6b/config.guess b/mk4/modimage/jpeg-6b/config.guess new file mode 100644 index 0000000..413ed41 --- /dev/null +++ b/mk4/modimage/jpeg-6b/config.guess @@ -0,0 +1,883 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 93, 94, 95, 96, 1997 Free Software Foundation, Inc. +# +# 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. + +# Written by Per Bothner . +# The master version of this file is at the FSF in /home/gd/gnu/lib. +# +# 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 system type (host/target name). +# +# Only a few systems have been added to this list; please add others +# (but try to keep the structure clean). +# + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 8/24/94.) +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 + +trap 'rm -f dummy.c dummy.o dummy; exit 1' 1 2 15 + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + alpha:OSF1:*:*) + if test $UNAME_RELEASE = "V4.0"; then + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + fi + # 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. + cat <dummy.s + .globl main + .ent main +main: + .frame \$30,0,\$26,0 + .prologue 0 + .long 0x47e03d80 # implver $0 + lda \$2,259 + .long 0x47e20c21 # amask $2,$1 + srl \$1,8,\$2 + sll \$2,2,\$2 + sll \$0,3,\$0 + addl \$1,\$0,\$0 + addl \$2,\$0,\$0 + ret \$31,(\$26),1 + .end main +EOF + ${CC-cc} dummy.s -o dummy 2>/dev/null + if test "$?" = 0 ; then + ./dummy + case "$?" in + 7) + UNAME_MACHINE="alpha" + ;; + 15) + UNAME_MACHINE="alphaev5" + ;; + 14) + UNAME_MACHINE="alphaev56" + ;; + 10) + UNAME_MACHINE="alphapca56" + ;; + 16) + UNAME_MACHINE="alphaev6" + ;; + esac + fi + rm -f dummy.s dummy + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr [[A-Z]] [[a-z]]` + exit 0 ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit 0 ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-cbm-sysv4 + exit 0;; + amiga:NetBSD:*:*) + echo m68k-cbm-netbsd${UNAME_RELEASE} + exit 0 ;; + amiga:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + arc64:OpenBSD:*:*) + echo mips64el-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + arc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + hkmips:OpenBSD:*:*) + echo mips-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + pmax:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sgi:OpenBSD:*:*) + echo mips-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + wgrisc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit 0;; + arm32:NetBSD:*:*) + echo arm-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + exit 0 ;; + SR2?01:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit 0;; + Pyramid*:OSx*:*:*|MIS*: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 ;; + 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=`(head -1 /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 ;; + atari*:NetBSD:*:*) + echo m68k-atari-netbsd${UNAME_RELEASE} + exit 0 ;; + atari*:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sun3*:NetBSD:*:*) + echo m68k-sun-netbsd${UNAME_RELEASE} + exit 0 ;; + sun3*:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mac68k:NetBSD:*:*) + echo m68k-apple-netbsd${UNAME_RELEASE} + exit 0 ;; + mac68k:OpenBSD:*:*) + echo m68k-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 ;; + 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:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit 0 ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + sed 's/^ //' << EOF >dummy.c + int main (argc, argv) int argc; char **argv; { + #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-cc} dummy.c -o dummy \ + && ./dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \ + && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + echo mips-mips-riscos${UNAME_RELEASE} + 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 -o $UNAME_PROCESSOR = mc88110 ] ; then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx \ + -o ${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 ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + sed 's/^ //' << EOF >dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + ${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + 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:*:4) + if /usr/sbin/lsattr -EHl proc0 | 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=4.${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 NetBSD 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/[3478]??:HP-UX:*:*) + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/7?? | 9000/8?[1679] ) HP_ARCH=hppa1.1 ;; + 9000/8?? ) HP_ARCH=hppa1.0 ;; + esac + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit 0 ;; + 3050*:HI-UX:*:*) + sed 's/^ //' << EOF >dummy.c + #include + 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-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + 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 ;; + 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*X-MP:*:*:*) + echo xmp-cray-unicos + exit 0 ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} + 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/ + exit 0 ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} + exit 0 ;; + CRAY-2:*:*:*) + echo cray2-cray-unicos + exit 0 ;; + F300:UNIX_System_V:*:*) + FUJITSU_SYS=`uname -p | tr [A-Z] [a-z] | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "f300-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit 0 ;; + F301:UNIX_System_V:*:*) + echo f301-fujitsu-uxpv`echo $UNAME_RELEASE | sed 's/ .*//'` + exit 0 ;; + hp3[0-9][05]:NetBSD:*:*) + echo m68k-hp-netbsd${UNAME_RELEASE} + exit 0 ;; + hp300:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + i?86:BSD/386:*:* | *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit 0 ;; + *:FreeBSD:*:*) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit 0 ;; + *:NetBSD:*:*) + echo ${UNAME_MACHINE}-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + exit 0 ;; + *:OpenBSD:*:*) + echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + exit 0 ;; + i*:CYGWIN*:*) + echo i386-pc-cygwin32 + exit 0 ;; + i*:MINGW*:*) + echo i386-pc-mingw32 + exit 0 ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin32 + exit 0 ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + *:GNU:*:*) + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit 0 ;; + *:Linux:*:*) + # The BFD linker knows what the default object file format is, so + # first see if it will tell us. + ld_help_string=`ld --help 2>&1` + ld_supported_emulations=`echo $ld_help_string \ + | sed -ne '/supported emulations:/!d + s/[ ][ ]*/ /g + s/.*supported emulations: *// + s/ .*// + p'` + case "$ld_supported_emulations" in + i?86linux) echo "${UNAME_MACHINE}-pc-linux-gnuaout" ; exit 0 ;; + i?86coff) echo "${UNAME_MACHINE}-pc-linux-gnucoff" ; exit 0 ;; + sparclinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;; + m68klinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;; + elf32ppc) echo "powerpc-unknown-linux-gnu" ; exit 0 ;; + esac + + if test "${UNAME_MACHINE}" = "alpha" ; then + sed 's/^ //' <dummy.s + .globl main + .ent main + main: + .frame \$30,0,\$26,0 + .prologue 0 + .long 0x47e03d80 # implver $0 + lda \$2,259 + .long 0x47e20c21 # amask $2,$1 + srl \$1,8,\$2 + sll \$2,2,\$2 + sll \$0,3,\$0 + addl \$1,\$0,\$0 + addl \$2,\$0,\$0 + ret \$31,(\$26),1 + .end main +EOF + LIBC="" + ${CC-cc} dummy.s -o dummy 2>/dev/null + if test "$?" = 0 ; then + ./dummy + case "$?" in + 7) + UNAME_MACHINE="alpha" + ;; + 15) + UNAME_MACHINE="alphaev5" + ;; + 14) + UNAME_MACHINE="alphaev56" + ;; + 10) + UNAME_MACHINE="alphapca56" + ;; + 16) + UNAME_MACHINE="alphaev6" + ;; + esac + + objdump --private-headers dummy | \ + grep ld.so.1 > /dev/null + if test "$?" = 0 ; then + LIBC="libc1" + fi + fi + rm -f dummy.s dummy + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} ; exit 0 + elif test "${UNAME_MACHINE}" = "mips" ; then + cat >dummy.c </dev/null && ./dummy "${UNAME_MACHINE}" && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + else + # Either a pre-BFD a.out linker (linux-gnuoldld) + # or one that does not give us useful --help. + # GCC wants to distinguish between linux-gnuoldld and linux-gnuaout. + # If ld does not provide *any* "supported emulations:" + # that means it is gnuoldld. + echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations:" + test $? != 0 && echo "${UNAME_MACHINE}-pc-linux-gnuoldld" && exit 0 + + case "${UNAME_MACHINE}" in + i?86) + VENDOR=pc; + ;; + *) + VENDOR=unknown; + ;; + esac + # Determine whether the default compiler is a.out or elf + cat >dummy.c < +main(argc, argv) + int argc; + char *argv[]; +{ +#ifdef __ELF__ +# ifdef __GLIBC__ +# if __GLIBC__ >= 2 + printf ("%s-${VENDOR}-linux-gnu\n", argv[1]); +# else + printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]); +# endif +# else + printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]); +# endif +#else + printf ("%s-${VENDOR}-linux-gnuaout\n", argv[1]); +#endif + return 0; +} +EOF + ${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy "${UNAME_MACHINE}" && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + fi ;; +# 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. + i?86:DYNIX/ptx:4*:*) + 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:*:4.*:* | i?86:SYSTEM_V:4.*:*) + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_RELEASE} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE} + fi + exit 0 ;; + i?86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')` + (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit 0 ;; + pc:*:*:*) + # 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 ;; + M68*:*:R3V[567]*:*) + test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; + 3[34]??:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*: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.*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit 0 ;; + i?86:LynxOS:2.*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + rs6000:LynxOS:2.*:* | PowerPC:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + 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:CPunix:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit 0 ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # 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 ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit 0 ;; + news*:NEWS-OS:*:6*) + echo mips-sony-newsos6 + exit 0 ;; + R3000:*System_V*:*:* | R4000:UNIX_SYSV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + 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 + +cat >dummy.c < +# include +#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 + 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`; + printf ("%s-next-nextstep%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) + printf ("vax-dec-bsd\n"); exit (0); +#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-cc} dummy.c -o dummy 2>/dev/null && ./dummy && rm dummy.c dummy && exit 0 +rm -f dummy.c dummy + +# 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 + +#echo '(Unable to guess system type)' 1>&2 + +exit 1 diff --git a/mk4/modimage/jpeg-6b/config.sub b/mk4/modimage/jpeg-6b/config.sub new file mode 100644 index 0000000..213a6d4 --- /dev/null +++ b/mk4/modimage/jpeg-6b/config.sub @@ -0,0 +1,954 @@ +#! /bin/sh +# Configuration validation subroutine script, version 1.1. +# Copyright (C) 1991, 92, 93, 94, 95, 96, 1997 Free Software Foundation, Inc. +# 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. + +# 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. + +if [ x$1 = x ] +then + echo Configuration name missing. 1>&2 + echo "Usage: $0 CPU-MFR-OPSYS" 1>&2 + echo "or $0 ALIAS" 1>&2 + echo where ALIAS is a recognized configuration type. 1>&2 + exit 1 +fi + +# First pass through any local machine types. +case $1 in + *local*) + echo $1 + exit 0 + ;; + *) + ;; +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 + linux-gnu*) + 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) + os= + 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/'` + ;; + -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 + ;; +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. + tahoe | i860 | m32r | m68k | m68000 | m88k | ns32k | arc | arm \ + | arme[lb] | pyramid | mn10200 | mn10300 \ + | tron | a29k | 580 | i960 | h8300 | hppa | hppa1.0 | hppa1.1 \ + | alpha | alphaev5 | alphaev56 | we32k | ns16k | clipper \ + | i370 | sh | powerpc | powerpcle | 1750a | dsp16xx | pdp11 \ + | mips64 | mipsel | mips64el | mips64orion | mips64orionel \ + | mipstx39 | mipstx39el \ + | sparc | sparclet | sparclite | sparc64 | v850) + basic_machine=$basic_machine-unknown + ;; + # 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[3456]86) + 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. + vax-* | tahoe-* | i[3456]86-* | i860-* | m32r-* | m68k-* | m68000-* \ + | m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | arm-* | c[123]* \ + | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \ + | power-* | none-* | 580-* | cray2-* | h8300-* | i960-* \ + | xmp-* | ymp-* | hppa-* | hppa1.0-* | hppa1.1-* \ + | alpha-* | alphaev5-* | alphaev56-* | we32k-* | cydra-* \ + | ns16k-* | pn-* | np1-* | xps100-* | clipper-* | orion-* \ + | sparclite-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \ + | sparc64-* | mips64-* | mipsel-* \ + | mips64el-* | mips64orion-* | mips64orionel-* \ + | mipstx39-* | mipstx39el-* \ + | f301-*) + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-cbm + ;; + amigaos | amigados) + basic_machine=m68k-cbm + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-cbm + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + 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 | ymp) + basic_machine=ymp-cray + os=-unicos + ;; + cray2) + basic_machine=cray2-cray + os=-unicos + ;; + [ctj]90-cray) + basic_machine=c90-cray + os=-unicos + ;; + crds | unos) + basic_machine=m68k-crds + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + 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 + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-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 + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k7[0-9][0-9] | hp7[0-9][0-9] | hp9k8[0-9]7 | hp8[0-9]7) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + os=-mvs + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i[3456]86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i[3456]86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i[3456]86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i[3456]86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + 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 + ;; + miniframe) + basic_machine=m68000-convergent + ;; + mipsel*-linux*) + basic_machine=mipsel-unknown + os=-linux-gnu + ;; + mips*-linux*) + basic_machine=mips-unknown + os=-linux-gnu + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + 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 + ;; + 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 + ;; + np1) + basic_machine=np1-gould + ;; + 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) + basic_machine=i586-intel + ;; + pentiumpro | p6) + basic_machine=i686-intel + ;; + pentium-* | p5-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + k5) + # We don't have specific support for AMD's K5 yet, so just call it a Pentium + basic_machine=i586-amd + ;; + nexen) + # We don't have specific support for Nexgen yet, so just call it a Pentium + basic_machine=i586-nexgen + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=rs6000-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/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + 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 + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + 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 + ;; + xmp) + basic_machine=xmp-cray + os=-unicos + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + 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. + mips) + if [ x$os = x-linux-gnu ]; then + basic_machine=mips-unknown + else + basic_machine=mips-mips + fi + ;; + romp) + basic_machine=romp-ibm + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sparc) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + *) + 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. + -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* | -netbsd* | -openbsd* | -freebsd* | -riscix* \ + | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -cygwin32* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -uxpv*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -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|'` + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -ctix* | -uts*) + os=-sysv + ;; + -ns2 ) + os=-nextstep2 + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -xenix) + os=-xenix + ;; + -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*-semi) + os=-aout + ;; + 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 + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-ibm) + os=-aix + ;; + *-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 + ;; + f301-fujitsu) + os=-uxpv + ;; + *) + 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 + ;; + -hpux*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -vxsim* | -vxworks*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os diff --git a/mk4/modimage/jpeg-6b/configure b/mk4/modimage/jpeg-6b/configure new file mode 100644 index 0000000..35c9db5 --- /dev/null +++ b/mk4/modimage/jpeg-6b/configure @@ -0,0 +1,2011 @@ +#! /bin/sh + +# Guess values for system-dependent variables and create Makefiles. +# Generated automatically using autoconf version 2.12 +# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + +# Defaults: +ac_help= +ac_default_prefix=/usr/local +# Any additions from configure.in: +ac_help="$ac_help + --enable-shared build shared library using GNU libtool" +ac_help="$ac_help + --enable-static build static library using GNU libtool" +ac_help="$ac_help + --enable-maxmem[=N] enable use of temp files, set max mem usage to N MB" +ac_help="$ac_help +" + +# Initialize some variables set by options. +# The variables have the same names as the options, with +# dashes changed to underlines. +build=NONE +cache_file=./config.cache +exec_prefix=NONE +host=NONE +no_create= +nonopt=NONE +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +target=NONE +verbose= +x_includes=NONE +x_libraries=NONE +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' + +# Initialize some other variables. +subdirs= +MFLAGS= MAKEFLAGS= +# Maximum number of lines to put in a shell here document. +ac_max_here_lines=12 + +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 + + case "$ac_option" in + -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) ac_optarg= ;; + esac + + # 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 ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build="$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" ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir="$ac_optarg" ;; + + -disable-* | --disable-*) + ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + eval "enable_${ac_feature}=no" ;; + + -enable-* | --enable-*) + ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) 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) + # 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 << EOF +Usage: configure [options] [host] +Options: [defaults in brackets after descriptions] +Configuration: + --cache-file=FILE cache test results in FILE + --help print this message + --no-create do not create output files + --quiet, --silent do not print \`checking...' messages + --version print the version of autoconf that created configure +Directory and file names: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [same as prefix] + --bindir=DIR user executables in DIR [EPREFIX/bin] + --sbindir=DIR system admin executables in DIR [EPREFIX/sbin] + --libexecdir=DIR program executables in DIR [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data in DIR + [PREFIX/share] + --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data in DIR + [PREFIX/com] + --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var] + --libdir=DIR object code libraries in DIR [EPREFIX/lib] + --includedir=DIR C header files in DIR [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include] + --infodir=DIR info documentation in DIR [PREFIX/info] + --mandir=DIR man documentation in DIR [PREFIX/man] + --srcdir=DIR find the sources in DIR [configure dir or ..] + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM + run sed PROGRAM on installed program names +EOF + cat << EOF +Host type: + --build=BUILD configure for building on BUILD [BUILD=HOST] + --host=HOST configure for HOST [guessed] + --target=TARGET configure for TARGET [TARGET=HOST] +Features and packages: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --x-includes=DIR X include files are in DIR + --x-libraries=DIR X library files are in DIR +EOF + if test -n "$ac_help"; then + echo "--enable and --with options recognized:$ac_help" + fi + exit 0 ;; + + -host | --host | --hos | --ho) + ac_prev=host ;; + -host=* | --host=* | --hos=* | --ho=*) + host="$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) + 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 ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target="$ac_optarg" ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers) + echo "configure generated by autoconf version 2.12" + exit 0 ;; + + -with-* | --with-*) + ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "with_${ac_package}='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`echo $ac_option|sed -e 's/-*without-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + 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 "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } + ;; + + *=*) + varname=`echo "$ac_option"|sed -e 's/=.*//'` + # Reject names that aren't valid shell variable names. + if test -n "`echo $varname| sed 's/[a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $varname: invalid shell variable name" 1>&2; exit 1; } + fi + val="`echo "$ac_option"|sed 's/[^=]*=//'`" + test -n "$verbose" && echo " setting shell variable $varname to $val" + eval "$varname='$val'" + eval "export $varname" ;; + + *) + if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then + echo "configure: warning: $ac_option: invalid host type" 1>&2 + fi + if test "x$nonopt" != xNONE; then + { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } + fi + nonopt="$ac_option" + ;; + + esac +done + +if test -n "$ac_prev"; then + { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } +fi + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +# File descriptor usage: +# 0 standard input +# 1 file creation +# 2 errors and warnings +# 3 some systems may open it to /dev/tty +# 4 used on the Kubota Titan +# 6 checking for... messages and results +# 5 compiler messages saved in config.log +if test "$silent" = yes; then + exec 6>/dev/null +else + exec 6>&1 +fi +exec 5>./config.log + +echo "\ +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. +" 1>&5 + +# Strip out --no-create and --no-recursion so they do not pile up. +# Also quote any args containing shell metacharacters. +ac_configure_args= +for ac_arg +do + case "$ac_arg" in + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) ;; + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) + ac_configure_args="$ac_configure_args '$ac_arg'" ;; + *) ac_configure_args="$ac_configure_args $ac_arg" ;; + esac +done + +# NLS nuisances. +# Only set these to C if already set. These must not be set unconditionally +# because not all systems understand e.g. LANG=C (notably SCO). +# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'! +# Non-C LC_CTYPE values break the ctype check. +if test "${LANG+set}" = set; then LANG=C; export LANG; fi +if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi +if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi +if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi + +# 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 + +# A filename unique to this package, relative to the directory that +# configure is in, which we can look for to find out if srcdir is correct. +ac_unique_file=jcmaster.c + +# 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_prog=$0 + ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` + test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. + 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 "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } + else + { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } + fi +fi +srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` + +# 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 "loading site script $ac_site_file" + . "$ac_site_file" + fi +done + + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then + # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. + if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then + ac_n= ac_c=' +' ac_t=' ' + else + ac_n=-n ac_c= ac_t= + fi +else + ac_n= ac_c='\c' ac_t= +fi + + + +# Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:538: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="gcc" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +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 $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:567: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + ac_prog_rejected=no + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + break + fi + done + IFS="$ac_save_ifs" +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 $# -gt 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 + set dummy "$ac_dir/$ac_word" "$@" + shift + ac_cv_prog_CC="$@" + fi +fi +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; } +fi + +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 +echo "configure:615: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then + ac_cv_prog_cc_works=yes + # If we can't run a trivial program, we are probably using a cross compiler. + if (./conftest; exit) 2>/dev/null; then + ac_cv_prog_cc_cross=no + else + ac_cv_prog_cc_cross=yes + fi +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + ac_cv_prog_cc_works=no +fi +rm -fr conftest* + +echo "$ac_t""$ac_cv_prog_cc_works" 1>&6 +if test $ac_cv_prog_cc_works = no; then + { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } +fi +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 +echo "configure:649: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 +cross_compiling=$ac_cv_prog_cc_cross + +echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 +echo "configure:654: checking whether we are using GNU C" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.c <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + ac_cv_prog_gcc=yes +else + ac_cv_prog_gcc=no +fi +fi + +echo "$ac_t""$ac_cv_prog_gcc" 1>&6 + +if test $ac_cv_prog_gcc = yes; then + GCC=yes + test "${CFLAGS+set}" = set || CFLAGS="-O2" +else + GCC= + test "${CFLAGS+set}" = set || CFLAGS="-O" +fi + +echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 +echo "configure:681: checking how to run the C preprocessor" >&5 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then +if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # This must be in double quotes, not single quotes, because CPP may get + # substituted into the Makefile and "${CC-cc}" will confuse make. + CPP="${CC-cc} -E" + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:702: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -E -traditional-cpp" + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:719: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP=/lib/cpp +fi +rm -f conftest* +fi +rm -f conftest* + ac_cv_prog_CPP="$CPP" +fi + CPP="$ac_cv_prog_CPP" +else + ac_cv_prog_CPP="$CPP" +fi +echo "$ac_t""$CPP" 1>&6 + +echo $ac_n "checking for function prototypes""... $ac_c" 1>&6 +echo "configure:742: checking for function prototypes" >&5 +if eval "test \"`echo '$''{'ijg_cv_have_prototypes'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ijg_cv_have_prototypes=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ijg_cv_have_prototypes=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ijg_cv_have_prototypes" 1>&6 +if test $ijg_cv_have_prototypes = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_PROTOTYPES +EOF + +else + echo Your compiler does not seem to know about function prototypes. + echo Perhaps it needs a special switch to enable ANSI C mode. + echo If so, we recommend running configure like this: + echo " ./configure CC='cc -switch'" + echo where -switch is the proper switch. +fi +ac_safe=`echo "stddef.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for stddef.h""... $ac_c" 1>&6 +echo "configure:792: checking for stddef.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:802: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define HAVE_STDDEF_H +EOF + +else + echo "$ac_t""no" 1>&6 +fi + +ac_safe=`echo "stdlib.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for stdlib.h""... $ac_c" 1>&6 +echo "configure:828: checking for stdlib.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:838: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define HAVE_STDLIB_H +EOF + +else + echo "$ac_t""no" 1>&6 +fi + +ac_safe=`echo "string.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for string.h""... $ac_c" 1>&6 +echo "configure:864: checking for string.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:874: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + : +else + echo "$ac_t""no" 1>&6 +cat >> confdefs.h <<\EOF +#define NEED_BSD_STRINGS +EOF + +fi + +echo $ac_n "checking for size_t""... $ac_c" 1>&6 +echo "configure:900: checking for size_t" >&5 +cat > conftest.$ac_ext < +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#include +#ifdef NEED_BSD_STRINGS +#include +#else +#include +#endif +typedef size_t my_size_t; + +int main() { + my_size_t foovar; +; return 0; } +EOF +if { (eval echo configure:923: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ijg_size_t_ok=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ijg_size_t_ok="not ANSI, perhaps it is in sys/types.h" +fi +rm -f conftest* +echo "$ac_t""$ijg_size_t_ok" 1>&6 +if test "$ijg_size_t_ok" != yes; then +ac_safe=`echo "sys/types.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for sys/types.h""... $ac_c" 1>&6 +echo "configure:937: checking for sys/types.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:947: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define NEED_SYS_TYPES_H +EOF + +cat > conftest.$ac_ext < +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "size_t" >/dev/null 2>&1; then + rm -rf conftest* + ijg_size_t_ok="size_t is in sys/types.h" +else + rm -rf conftest* + ijg_size_t_ok=no +fi +rm -f conftest* + +else + echo "$ac_t""no" 1>&6 +ijg_size_t_ok=no +fi + +echo "$ac_t""$ijg_size_t_ok" 1>&6 +if test "$ijg_size_t_ok" = no; then + echo Type size_t is not defined in any of the usual places. + echo Try putting '"typedef unsigned int size_t;"' in jconfig.h. +fi +fi +echo $ac_n "checking for type unsigned char""... $ac_c" 1>&6 +echo "configure:994: checking for type unsigned char" >&5 +cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + echo "$ac_t""yes" 1>&6 +cat >> confdefs.h <<\EOF +#define HAVE_UNSIGNED_CHAR +EOF + +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + echo "$ac_t""no" 1>&6 +fi +rm -f conftest* +echo $ac_n "checking for type unsigned short""... $ac_c" 1>&6 +echo "configure:1018: checking for type unsigned short" >&5 +cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + echo "$ac_t""yes" 1>&6 +cat >> confdefs.h <<\EOF +#define HAVE_UNSIGNED_SHORT +EOF + +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + echo "$ac_t""no" 1>&6 +fi +rm -f conftest* +echo $ac_n "checking for type void""... $ac_c" 1>&6 +echo "configure:1042: checking for type void" >&5 +cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + echo "$ac_t""yes" 1>&6 +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + echo "$ac_t""no" 1>&6 +cat >> confdefs.h <<\EOF +#define void char +EOF + +fi +rm -f conftest* + +echo $ac_n "checking for working const""... $ac_c" 1>&6 +echo "configure:1088: checking for working const" >&5 +if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <j = 5; +} +{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; +} + +; return 0; } +EOF +if { (eval echo configure:1142: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_c_const=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_c_const=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_c_const" 1>&6 +if test $ac_cv_c_const = no; then + cat >> confdefs.h <<\EOF +#define const +EOF + +fi + +echo $ac_n "checking for inline""... $ac_c" 1>&6 +echo "configure:1163: checking for inline" >&5 +ijg_cv_inline="" +cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ijg_cv_inline="__inline__" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ijg_cv_inline="__inline" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ijg_cv_inline="inline" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -f conftest* +fi +rm -f conftest* +fi +rm -f conftest* +echo "$ac_t""$ijg_cv_inline" 1>&6 +cat >> confdefs.h <&6 +echo "configure:1224: checking for broken incomplete types" >&5 +cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + echo "$ac_t""ok" 1>&6 +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + echo "$ac_t""broken" 1>&6 +cat >> confdefs.h <<\EOF +#define INCOMPLETE_TYPES_BROKEN +EOF + +fi +rm -f conftest* +echo $ac_n "checking for short external names""... $ac_c" 1>&6 +echo "configure:1248: checking for short external names" >&5 +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + echo "$ac_t""ok" 1>&6 +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + echo "$ac_t""short" 1>&6 +cat >> confdefs.h <<\EOF +#define NEED_SHORT_EXTERNAL_NAMES +EOF + +fi +rm -f conftest* +echo $ac_n "checking to see if char is signed""... $ac_c" 1>&6 +echo "configure:1275: checking to see if char is signed" >&5 +if test "$cross_compiling" = yes; then + echo Assuming that char is signed on target machine. +echo If it is unsigned, this will be a little bit inefficient. + +else + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + echo "$ac_t""no" 1>&6 +cat >> confdefs.h <<\EOF +#define CHAR_IS_UNSIGNED +EOF + +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + echo "$ac_t""yes" 1>&6 +fi +rm -fr conftest* +fi + +echo $ac_n "checking to see if right shift is signed""... $ac_c" 1>&6 +echo "configure:1323: checking to see if right shift is signed" >&5 +if test "$cross_compiling" = yes; then + echo "$ac_t""Assuming that right shift is signed on target machine." 1>&6 +else + cat > conftest.$ac_ext <> 4; + + if (res == -0x7F7E80CL) { /* expected result for signed shift */ + return 1; /* right shift is signed */ + } + /* see if unsigned-shift hack will fix it. */ + /* we can't just test exact value since it depends on width of long... */ + res |= (~0L) << (32-4); + if (res == -0x7F7E80CL) { /* expected result now? */ + return 0; /* right shift is unsigned */ + } + printf("Right shift isn't acting as I expect it to.\n"); + printf("I fear the JPEG software will not work at all.\n\n"); + return 0; /* try it with unsigned anyway */ +} +main() { + exit(is_shifting_signed(-0x7F7E80B1L)); +} +EOF +if { (eval echo configure:1358: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + echo "$ac_t""no" 1>&6 +cat >> confdefs.h <<\EOF +#define RIGHT_SHIFT_IS_UNSIGNED +EOF + +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + echo "$ac_t""yes" 1>&6 +fi +rm -fr conftest* +fi + +echo $ac_n "checking to see if fopen accepts b spec""... $ac_c" 1>&6 +echo "configure:1375: checking to see if fopen accepts b spec" >&5 +if test "$cross_compiling" = yes; then + echo "$ac_t""Assuming that it does." 1>&6 +else + cat > conftest.$ac_ext < +main() { + if (fopen("conftestdata", "wb") != NULL) + exit(0); + exit(1); +} +EOF +if { (eval echo configure:1390: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + echo "$ac_t""yes" 1>&6 +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + echo "$ac_t""no" 1>&6 +cat >> confdefs.h <<\EOF +#define DONT_USE_B_MODE +EOF + +fi +rm -fr conftest* +fi + +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 + fi +done +if test -z "$ac_aux_dir"; then + { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; } +fi +ac_config_guess=$ac_aux_dir/config.guess +ac_config_sub=$ac_aux_dir/config.sub +ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 +echo "configure:1436: checking for a BSD compatible install" >&5 +if test -z "$INSTALL"; then +if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + # Account for people who put trailing slashes in PATH elements. + case "$ac_dir/" in + /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + for ac_prog in ginstall installbsd scoinst install; do + if test -f $ac_dir/$ac_prog; then + if test $ac_prog = install && + grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + # OSF/1 installbsd also uses dspmsg, but is usable. + : + else + ac_cv_path_install="$ac_dir/$ac_prog -c" + break 2 + fi + fi + done + ;; + esac + done + IFS="$ac_save_IFS" + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL="$ac_cv_path_install" + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL="$ac_install_sh" + fi +fi +echo "$ac_t""$INSTALL" 1>&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +# Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1488: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_RANLIB="ranlib" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":" +fi +fi +RANLIB="$ac_cv_prog_RANLIB" +if test -n "$RANLIB"; then + echo "$ac_t""$RANLIB" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + +# Decide whether to use libtool, +# and if so whether to build shared, static, or both flavors of library. +LTSHARED="no" +# Check whether --enable-shared or --disable-shared was given. +if test "${enable_shared+set}" = set; then + enableval="$enable_shared" + LTSHARED="$enableval" +fi + +LTSTATIC="no" +# Check whether --enable-static or --disable-static was given. +if test "${enable_static+set}" = set; then + enableval="$enable_static" + LTSTATIC="$enableval" +fi + +if test "x$LTSHARED" != xno -o "x$LTSTATIC" != xno; then + USELIBTOOL="yes" + LIBTOOL="./libtool" + O="lo" + A="la" + LN='$(LIBTOOL) --mode=link $(CC)' + INSTALL_LIB='$(LIBTOOL) --mode=install ${INSTALL}' + INSTALL_PROGRAM="\$(LIBTOOL) --mode=install $INSTALL_PROGRAM" +else + USELIBTOOL="no" + LIBTOOL="" + O="o" + A="a" + LN='$(CC)' + INSTALL_LIB="$INSTALL_DATA" +fi + + + + + + +# Configure libtool if needed. +if test $USELIBTOOL = yes; then + disable_shared= + disable_static= + if test "x$LTSHARED" = xno; then + disable_shared="--disable-shared" + fi + if test "x$LTSTATIC" = xno; then + disable_static="--disable-static" + fi + $srcdir/ltconfig $disable_shared $disable_static $srcdir/ltmain.sh +fi + +# Select memory manager depending on user input. +# If no "-enable-maxmem", use jmemnobs +MEMORYMGR='jmemnobs.$(O)' +MAXMEM="no" +# Check whether --enable-maxmem or --disable-maxmem was given. +if test "${enable_maxmem+set}" = set; then + enableval="$enable_maxmem" + MAXMEM="$enableval" +fi + +# support --with-maxmem for backwards compatibility with IJG V5. +# Check whether --with-maxmem or --without-maxmem was given. +if test "${with_maxmem+set}" = set; then + withval="$with_maxmem" + MAXMEM="$withval" +fi + +if test "x$MAXMEM" = xyes; then + MAXMEM=1 +fi +if test "x$MAXMEM" != xno; then + if test -n "`echo $MAXMEM | sed 's/[0-9]//g'`"; then + { echo "configure: error: non-numeric argument to --enable-maxmem" 1>&2; exit 1; } + fi + DEFAULTMAXMEM=`expr $MAXMEM \* 1048576` +cat >> confdefs.h <&6 +echo "configure:1596: checking for 'tmpfile()'" >&5 +cat > conftest.$ac_ext < +int main() { + FILE * tfile = tmpfile(); +; return 0; } +EOF +if { (eval echo configure:1605: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + echo "$ac_t""yes" 1>&6 +MEMORYMGR='jmemansi.$(O)' +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + echo "$ac_t""no" 1>&6 +MEMORYMGR='jmemname.$(O)' +cat >> confdefs.h <<\EOF +#define NEED_SIGNAL_CATCHER +EOF + +echo $ac_n "checking for 'mktemp()'""... $ac_c" 1>&6 +echo "configure:1620: checking for 'mktemp()'" >&5 +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + echo "$ac_t""yes" 1>&6 +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + echo "$ac_t""no" 1>&6 +cat >> confdefs.h <<\EOF +#define NO_MKTEMP +EOF + +fi +rm -f conftest* +fi +rm -f conftest* +fi + + +# Extract the library version ID from jpeglib.h. +echo $ac_n "checking libjpeg version number""... $ac_c" 1>&6 +echo "configure:1650: checking libjpeg version number" >&5 +JPEG_LIB_VERSION=`sed -e '/^#define JPEG_LIB_VERSION/!d' -e 's/^[^0-9]*\([0-9][0-9]*\).*$/\1/' $srcdir/jpeglib.h` +echo "$ac_t""$JPEG_LIB_VERSION" 1>&6 + + +# Prepare to massage makefile.cfg correctly. +if test $ijg_cv_have_prototypes = yes; then + A2K_DEPS="" + COM_A2K="# " +else + A2K_DEPS="ansi2knr" + COM_A2K="" +fi + + +# ansi2knr needs -DBSD if string.h is missing +if test $ac_cv_header_string_h = no; then + ANSI2KNRFLAGS="-DBSD" +else + ANSI2KNRFLAGS="" +fi + +# Substitutions to enable or disable libtool-related stuff +if test $USELIBTOOL = yes -a $ijg_cv_have_prototypes = yes; then + COM_LT="" +else + COM_LT="# " +fi + +if test "x$LTSHARED" != xno; then + FORCE_INSTALL_LIB="install-lib" +else + FORCE_INSTALL_LIB="" +fi + +# Set up -I directives +if test "x$srcdir" = x.; then + INCLUDEFLAGS='-I$(srcdir)' +else + INCLUDEFLAGS='-I. -I$(srcdir)' +fi + +trap '' 1 2 15 + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Any assignment to VPATH causes Sun make to only execute +# the first set of double-colon rules, so remove it if not needed. +# If there is a colon in the path, we need to keep it. +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' +fi + +trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 + +DEFS=-DHAVE_CONFIG_H + +# Without the "./", some shells look in PATH for config.status. +: ${CONFIG_STATUS=./config.status} + +echo creating $CONFIG_STATUS +rm -f $CONFIG_STATUS +cat > $CONFIG_STATUS </dev/null | sed 1q`: +# +# $0 $ac_configure_args +# +# Compiler output produced by configure, useful for debugging +# configure, is in ./config.log if it exists. + +ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" +for ac_option +do + case "\$ac_option" in + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" + exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; + -version | --version | --versio | --versi | --vers | --ver | --ve | --v) + echo "$CONFIG_STATUS generated by autoconf version 2.12" + exit 0 ;; + -help | --help | --hel | --he | --h) + echo "\$ac_cs_usage"; exit 0 ;; + *) echo "\$ac_cs_usage"; exit 1 ;; + esac +done + +ac_given_srcdir=$srcdir +ac_given_INSTALL="$INSTALL" + +trap 'rm -fr `echo "Makefile:makefile.cfg jconfig.h:jconfig.cfg" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 +EOF +cat >> $CONFIG_STATUS < conftest.subs <<\\CEOF +$ac_vpsub +$extrasub +s%@CFLAGS@%$CFLAGS%g +s%@CPPFLAGS@%$CPPFLAGS%g +s%@CXXFLAGS@%$CXXFLAGS%g +s%@DEFS@%$DEFS%g +s%@LDFLAGS@%$LDFLAGS%g +s%@LIBS@%$LIBS%g +s%@exec_prefix@%$exec_prefix%g +s%@prefix@%$prefix%g +s%@program_transform_name@%$program_transform_name%g +s%@bindir@%$bindir%g +s%@sbindir@%$sbindir%g +s%@libexecdir@%$libexecdir%g +s%@datadir@%$datadir%g +s%@sysconfdir@%$sysconfdir%g +s%@sharedstatedir@%$sharedstatedir%g +s%@localstatedir@%$localstatedir%g +s%@libdir@%$libdir%g +s%@includedir@%$includedir%g +s%@oldincludedir@%$oldincludedir%g +s%@infodir@%$infodir%g +s%@mandir@%$mandir%g +s%@CC@%$CC%g +s%@CPP@%$CPP%g +s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g +s%@INSTALL_DATA@%$INSTALL_DATA%g +s%@RANLIB@%$RANLIB%g +s%@LIBTOOL@%$LIBTOOL%g +s%@O@%$O%g +s%@A@%$A%g +s%@LN@%$LN%g +s%@INSTALL_LIB@%$INSTALL_LIB%g +s%@MEMORYMGR@%$MEMORYMGR%g +s%@JPEG_LIB_VERSION@%$JPEG_LIB_VERSION%g +s%@A2K_DEPS@%$A2K_DEPS%g +s%@COM_A2K@%$COM_A2K%g +s%@ANSI2KNRFLAGS@%$ANSI2KNRFLAGS%g +s%@COM_LT@%$COM_LT%g +s%@FORCE_INSTALL_LIB@%$FORCE_INSTALL_LIB%g +s%@INCLUDEFLAGS@%$INCLUDEFLAGS%g + +CEOF +EOF + +cat >> $CONFIG_STATUS <<\EOF + +# 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_cmds=90 # Maximum number of lines to put in a sed script. +ac_file=1 # Number of current file. +ac_beg=1 # First line for current file. +ac_end=$ac_max_sed_cmds # 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" conftest.subs > conftest.s$ac_file + else + sed "${ac_end}q" conftest.subs > conftest.s$ac_file + fi + if test ! -s conftest.s$ac_file; then + ac_more_lines=false + rm -f conftest.s$ac_file + else + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f conftest.s$ac_file" + else + ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file" + fi + ac_file=`expr $ac_file + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_cmds` + fi +done +if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat +fi +EOF + +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories. + + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" + # A "../" for each directory in $ac_dir_suffix. + ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` + else + ac_dir_suffix= ac_dots= + fi + + case "$ac_given_srcdir" in + .) srcdir=. + if test -z "$ac_dots"; then top_srcdir=. + else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; + /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; + *) # Relative path. + srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" + top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + + case "$ac_given_INSTALL" in + [/$]*) INSTALL="$ac_given_INSTALL" ;; + *) INSTALL="$ac_dots$ac_given_INSTALL" ;; + esac + + echo creating "$ac_file" + rm -f "$ac_file" + configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." + case "$ac_file" in + *Makefile*) ac_comsub="1i\\ +# $configure_input" ;; + *) ac_comsub= ;; + esac + + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + sed -e "$ac_comsub +s%@configure_input@%$configure_input%g +s%@srcdir@%$srcdir%g +s%@top_srcdir@%$top_srcdir%g +s%@INSTALL@%$INSTALL%g +" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file +fi; done +rm -f conftest.s* + +# 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='\3' +ac_dD='%g' +# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE". +ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='\([ ]\)%\1#\2define\3' +ac_uC=' ' +ac_uD='\4%g' +# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_eB='$%\1#\2define\3' +ac_eC=' ' +ac_eD='%g' + +if test "${CONFIG_HEADERS+set}" != set; then +EOF +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +fi +for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + echo creating $ac_file + + rm -f conftest.frag conftest.in conftest.out + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + cat $ac_file_inputs > conftest.in + +EOF + +# Transform confdefs.h into a sed script conftest.vals that substitutes +# the proper values into config.h.in to produce config.h. 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.vals +cat > conftest.hdr <<\EOF +s/[\\&%]/\\&/g +s%[\\$`]%\\&%g +s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp +s%ac_d%ac_u%gp +s%ac_u%ac_e%gp +EOF +sed -n -f conftest.hdr confdefs.h > conftest.vals +rm -f conftest.hdr + +# 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.vals <<\EOF +EOF + +# Break up conftest.vals because some shells have a limit on +# the size of here documents, and old seds have small limits too. + +rm -f conftest.tail +while : +do + ac_lines=`grep -c . conftest.vals` + # grep -c gives empty output for an empty file on some AIX systems. + if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi + # Write a limited-size here document to conftest.frag. + echo ' cat > conftest.frag <> $CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS + echo 'CEOF + sed -f conftest.frag conftest.in > conftest.out + rm -f conftest.in + mv conftest.out conftest.in +' >> $CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail + rm -f conftest.vals + mv conftest.tail conftest.vals +done +rm -f conftest.vals + +cat >> $CONFIG_STATUS <<\EOF + rm -f conftest.frag conftest.h + echo "/* $ac_file. Generated automatically by configure. */" > conftest.h + cat conftest.in >> conftest.h + rm -f conftest.in + if cmp -s $ac_file conftest.h 2>/dev/null; then + echo "$ac_file is unchanged" + rm -f conftest.h + else + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + fi + rm -f $ac_file + mv conftest.h $ac_file + fi +fi; done + +EOF +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF + +exit 0 +EOF +chmod +x $CONFIG_STATUS +rm -fr confdefs* $ac_clean_files +test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 + diff --git a/mk4/modimage/jpeg-6b/djpeg.1 b/mk4/modimage/jpeg-6b/djpeg.1 new file mode 100644 index 0000000..11beb6a --- /dev/null +++ b/mk4/modimage/jpeg-6b/djpeg.1 @@ -0,0 +1,253 @@ +.TH DJPEG 1 "22 August 1997" +.SH NAME +djpeg \- decompress a JPEG file to an image file +.SH SYNOPSIS +.B djpeg +[ +.I options +] +[ +.I filename +] +.LP +.SH DESCRIPTION +.LP +.B djpeg +decompresses the named JPEG file, or the standard input if no file is named, +and produces an image file on the standard output. PBMPLUS (PPM/PGM), BMP, +GIF, Targa, or RLE (Utah Raster Toolkit) output format can be selected. +(RLE is supported only if the URT library is available.) +.SH OPTIONS +All switch names may be abbreviated; for example, +.B \-grayscale +may be written +.B \-gray +or +.BR \-gr . +Most of the "basic" switches can be abbreviated to as little as one letter. +Upper and lower case are equivalent (thus +.B \-BMP +is the same as +.BR \-bmp ). +British spellings are also accepted (e.g., +.BR \-greyscale ), +though for brevity these are not mentioned below. +.PP +The basic switches are: +.TP +.BI \-colors " N" +Reduce image to at most N colors. This reduces the number of colors used in +the output image, so that it can be displayed on a colormapped display or +stored in a colormapped file format. For example, if you have an 8-bit +display, you'd need to reduce to 256 or fewer colors. +.TP +.BI \-quantize " N" +Same as +.BR \-colors . +.B \-colors +is the recommended name, +.B \-quantize +is provided only for backwards compatibility. +.TP +.B \-fast +Select recommended processing options for fast, low quality output. (The +default options are chosen for highest quality output.) Currently, this is +equivalent to \fB\-dct fast \-nosmooth \-onepass \-dither ordered\fR. +.TP +.B \-grayscale +Force gray-scale output even if JPEG file is color. Useful for viewing on +monochrome displays; also, +.B djpeg +runs noticeably faster in this mode. +.TP +.BI \-scale " M/N" +Scale the output image by a factor M/N. Currently the scale factor must be +1/1, 1/2, 1/4, or 1/8. Scaling is handy if the image is larger than your +screen; also, +.B djpeg +runs much faster when scaling down the output. +.TP +.B \-bmp +Select BMP output format (Windows flavor). 8-bit colormapped format is +emitted if +.B \-colors +or +.B \-grayscale +is specified, or if the JPEG file is gray-scale; otherwise, 24-bit full-color +format is emitted. +.TP +.B \-gif +Select GIF output format. Since GIF does not support more than 256 colors, +.B \-colors 256 +is assumed (unless you specify a smaller number of colors). +.TP +.B \-os2 +Select BMP output format (OS/2 1.x flavor). 8-bit colormapped format is +emitted if +.B \-colors +or +.B \-grayscale +is specified, or if the JPEG file is gray-scale; otherwise, 24-bit full-color +format is emitted. +.TP +.B \-pnm +Select PBMPLUS (PPM/PGM) output format (this is the default format). +PGM is emitted if the JPEG file is gray-scale or if +.B \-grayscale +is specified; otherwise PPM is emitted. +.TP +.B \-rle +Select RLE output format. (Requires URT library.) +.TP +.B \-targa +Select Targa output format. Gray-scale format is emitted if the JPEG file is +gray-scale or if +.B \-grayscale +is specified; otherwise, colormapped format is emitted if +.B \-colors +is specified; otherwise, 24-bit full-color format is emitted. +.PP +Switches for advanced users: +.TP +.B \-dct int +Use integer DCT method (default). +.TP +.B \-dct fast +Use fast integer DCT (less accurate). +.TP +.B \-dct float +Use floating-point DCT method. +The float method is very slightly more accurate than the int method, but is +much slower unless your machine has very fast floating-point hardware. Also +note that results of the floating-point method may vary slightly across +machines, while the integer methods should give the same results everywhere. +The fast integer method is much less accurate than the other two. +.TP +.B \-dither fs +Use Floyd-Steinberg dithering in color quantization. +.TP +.B \-dither ordered +Use ordered dithering in color quantization. +.TP +.B \-dither none +Do not use dithering in color quantization. +By default, Floyd-Steinberg dithering is applied when quantizing colors; this +is slow but usually produces the best results. Ordered dither is a compromise +between speed and quality; no dithering is fast but usually looks awful. Note +that these switches have no effect unless color quantization is being done. +Ordered dither is only available in +.B \-onepass +mode. +.TP +.BI \-map " file" +Quantize to the colors used in the specified image file. This is useful for +producing multiple files with identical color maps, or for forcing a +predefined set of colors to be used. The +.I file +must be a GIF or PPM file. This option overrides +.B \-colors +and +.BR \-onepass . +.TP +.B \-nosmooth +Use a faster, lower-quality upsampling routine. +.TP +.B \-onepass +Use one-pass instead of two-pass color quantization. The one-pass method is +faster and needs less memory, but it produces a lower-quality image. +.B \-onepass +is ignored unless you also say +.B \-colors +.IR N . +Also, the one-pass method is always used for gray-scale output (the two-pass +method is no improvement then). +.TP +.BI \-maxmemory " N" +Set limit for amount of memory to use in processing large images. Value is +in thousands of bytes, or millions of bytes if "M" is attached to the +number. For example, +.B \-max 4m +selects 4000000 bytes. If more space is needed, temporary files will be used. +.TP +.BI \-outfile " name" +Send output image to the named file, not to standard output. +.TP +.B \-verbose +Enable debug printout. More +.BR \-v 's +give more output. Also, version information is printed at startup. +.TP +.B \-debug +Same as +.BR \-verbose . +.SH EXAMPLES +.LP +This example decompresses the JPEG file foo.jpg, quantizes it to +256 colors, and saves the output in 8-bit BMP format in foo.bmp: +.IP +.B djpeg \-colors 256 \-bmp +.I foo.jpg +.B > +.I foo.bmp +.SH HINTS +To get a quick preview of an image, use the +.B \-grayscale +and/or +.B \-scale +switches. +.B \-grayscale \-scale 1/8 +is the fastest case. +.PP +Several options are available that trade off image quality to gain speed. +.B \-fast +turns on the recommended settings. +.PP +.B \-dct fast +and/or +.B \-nosmooth +gain speed at a small sacrifice in quality. +When producing a color-quantized image, +.B \-onepass \-dither ordered +is fast but much lower quality than the default behavior. +.B \-dither none +may give acceptable results in two-pass mode, but is seldom tolerable in +one-pass mode. +.PP +If you are fortunate enough to have very fast floating point hardware, +\fB\-dct float\fR may be even faster than \fB\-dct fast\fR. But on most +machines \fB\-dct float\fR is slower than \fB\-dct int\fR; in this case it is +not worth using, because its theoretical accuracy advantage is too small to be +significant in practice. +.SH ENVIRONMENT +.TP +.B JPEGMEM +If this environment variable is set, its value is the default memory limit. +The value is specified as described for the +.B \-maxmemory +switch. +.B JPEGMEM +overrides the default value specified when the program was compiled, and +itself is overridden by an explicit +.BR \-maxmemory . +.SH SEE ALSO +.BR cjpeg (1), +.BR jpegtran (1), +.BR rdjpgcom (1), +.BR wrjpgcom (1) +.br +.BR ppm (5), +.BR pgm (5) +.br +Wallace, Gregory K. "The JPEG Still Picture Compression Standard", +Communications of the ACM, April 1991 (vol. 34, no. 4), pp. 30-44. +.SH AUTHOR +Independent JPEG Group +.SH BUGS +Arithmetic coding is not supported for legal reasons. +.PP +To avoid the Unisys LZW patent, +.B djpeg +produces uncompressed GIF files. These are larger than they should be, but +are readable by standard GIF decoders. +.PP +Still not as fast as we'd like. diff --git a/mk4/modimage/jpeg-6b/djpeg.c b/mk4/modimage/jpeg-6b/djpeg.c new file mode 100644 index 0000000..e099e90 --- /dev/null +++ b/mk4/modimage/jpeg-6b/djpeg.c @@ -0,0 +1,616 @@ +/* + * djpeg.c + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a command-line user interface for the JPEG decompressor. + * It should work on any system with Unix- or MS-DOS-style command lines. + * + * Two different command line styles are permitted, depending on the + * compile-time switch TWO_FILE_COMMANDLINE: + * djpeg [options] inputfile outputfile + * djpeg [options] [inputfile] + * In the second style, output is always to standard output, which you'd + * normally redirect to a file or pipe to some other program. Input is + * either from a named file or from standard input (typically redirected). + * The second style is convenient on Unix but is unhelpful on systems that + * don't support pipes. Also, you MUST use the first style if your system + * doesn't do binary I/O to stdin/stdout. + * To simplify script writing, the "-outfile" switch is provided. The syntax + * djpeg [options] -outfile outputfile inputfile + * works regardless of which command line style is used. + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ +#include "jversion.h" /* for version message */ + +#include /* to declare isprint() */ + +#ifdef USE_CCOMMAND /* command-line reader for Macintosh */ +#ifdef __MWERKS__ +#include /* Metrowerks needs this */ +#include /* ... and this */ +#endif +#ifdef THINK_C +#include /* Think declares it here */ +#endif +#endif + + +/* Create the add-on message string table. */ + +#define JMESSAGE(code,string) string , + +static const char * const cdjpeg_message_table[] = { +#include "cderror.h" + NULL +}; + + +/* + * This list defines the known output image formats + * (not all of which need be supported by a given version). + * You can change the default output format by defining DEFAULT_FMT; + * indeed, you had better do so if you undefine PPM_SUPPORTED. + */ + +typedef enum { + FMT_BMP, /* BMP format (Windows flavor) */ + FMT_GIF, /* GIF format */ + FMT_OS2, /* BMP format (OS/2 flavor) */ + FMT_PPM, /* PPM/PGM (PBMPLUS formats) */ + FMT_RLE, /* RLE format */ + FMT_TARGA, /* Targa format */ + FMT_TIFF /* TIFF format */ +} IMAGE_FORMATS; + +#ifndef DEFAULT_FMT /* so can override from CFLAGS in Makefile */ +#define DEFAULT_FMT FMT_PPM +#endif + +static IMAGE_FORMATS requested_fmt; + + +/* + * Argument-parsing code. + * The switch parser is designed to be useful with DOS-style command line + * syntax, ie, intermixed switches and file names, where only the switches + * to the left of a given file name affect processing of that file. + * The main program in this file doesn't actually use this capability... + */ + + +static const char * progname; /* program name for error messages */ +static char * outfilename; /* for -outfile switch */ + + +LOCAL(void) +usage (void) +/* complain about bad command line */ +{ + fprintf(stderr, "usage: %s [switches] ", progname); +#ifdef TWO_FILE_COMMANDLINE + fprintf(stderr, "inputfile outputfile\n"); +#else + fprintf(stderr, "[inputfile]\n"); +#endif + + fprintf(stderr, "Switches (names may be abbreviated):\n"); + fprintf(stderr, " -colors N Reduce image to no more than N colors\n"); + fprintf(stderr, " -fast Fast, low-quality processing\n"); + fprintf(stderr, " -grayscale Force grayscale output\n"); +#ifdef IDCT_SCALING_SUPPORTED + fprintf(stderr, " -scale M/N Scale output image by fraction M/N, eg, 1/8\n"); +#endif +#ifdef BMP_SUPPORTED + fprintf(stderr, " -bmp Select BMP output format (Windows style)%s\n", + (DEFAULT_FMT == FMT_BMP ? " (default)" : "")); +#endif +#ifdef GIF_SUPPORTED + fprintf(stderr, " -gif Select GIF output format%s\n", + (DEFAULT_FMT == FMT_GIF ? " (default)" : "")); +#endif +#ifdef BMP_SUPPORTED + fprintf(stderr, " -os2 Select BMP output format (OS/2 style)%s\n", + (DEFAULT_FMT == FMT_OS2 ? " (default)" : "")); +#endif +#ifdef PPM_SUPPORTED + fprintf(stderr, " -pnm Select PBMPLUS (PPM/PGM) output format%s\n", + (DEFAULT_FMT == FMT_PPM ? " (default)" : "")); +#endif +#ifdef RLE_SUPPORTED + fprintf(stderr, " -rle Select Utah RLE output format%s\n", + (DEFAULT_FMT == FMT_RLE ? " (default)" : "")); +#endif +#ifdef TARGA_SUPPORTED + fprintf(stderr, " -targa Select Targa output format%s\n", + (DEFAULT_FMT == FMT_TARGA ? " (default)" : "")); +#endif + fprintf(stderr, "Switches for advanced users:\n"); +#ifdef DCT_ISLOW_SUPPORTED + fprintf(stderr, " -dct int Use integer DCT method%s\n", + (JDCT_DEFAULT == JDCT_ISLOW ? " (default)" : "")); +#endif +#ifdef DCT_IFAST_SUPPORTED + fprintf(stderr, " -dct fast Use fast integer DCT (less accurate)%s\n", + (JDCT_DEFAULT == JDCT_IFAST ? " (default)" : "")); +#endif +#ifdef DCT_FLOAT_SUPPORTED + fprintf(stderr, " -dct float Use floating-point DCT method%s\n", + (JDCT_DEFAULT == JDCT_FLOAT ? " (default)" : "")); +#endif + fprintf(stderr, " -dither fs Use F-S dithering (default)\n"); + fprintf(stderr, " -dither none Don't use dithering in quantization\n"); + fprintf(stderr, " -dither ordered Use ordered dither (medium speed, quality)\n"); +#ifdef QUANT_2PASS_SUPPORTED + fprintf(stderr, " -map FILE Map to colors used in named image file\n"); +#endif + fprintf(stderr, " -nosmooth Don't use high-quality upsampling\n"); +#ifdef QUANT_1PASS_SUPPORTED + fprintf(stderr, " -onepass Use 1-pass quantization (fast, low quality)\n"); +#endif + fprintf(stderr, " -maxmemory N Maximum memory to use (in kbytes)\n"); + fprintf(stderr, " -outfile name Specify name for output file\n"); + fprintf(stderr, " -verbose or -debug Emit debug output\n"); + exit(EXIT_FAILURE); +} + + +LOCAL(int) +parse_switches (j_decompress_ptr cinfo, int argc, char **argv, + int last_file_arg_seen, boolean for_real) +/* Parse optional switches. + * Returns argv[] index of first file-name argument (== argc if none). + * Any file names with indexes <= last_file_arg_seen are ignored; + * they have presumably been processed in a previous iteration. + * (Pass 0 for last_file_arg_seen on the first or only iteration.) + * for_real is FALSE on the first (dummy) pass; we may skip any expensive + * processing. + */ +{ + int argn; + char * arg; + + /* Set up default JPEG parameters. */ + requested_fmt = DEFAULT_FMT; /* set default output file format */ + outfilename = NULL; + cinfo->err->trace_level = 0; + + /* Scan command line options, adjust parameters */ + + for (argn = 1; argn < argc; argn++) { + arg = argv[argn]; + if (*arg != '-') { + /* Not a switch, must be a file name argument */ + if (argn <= last_file_arg_seen) { + outfilename = NULL; /* -outfile applies to just one input file */ + continue; /* ignore this name if previously processed */ + } + break; /* else done parsing switches */ + } + arg++; /* advance past switch marker character */ + + if (keymatch(arg, "bmp", 1)) { + /* BMP output format. */ + requested_fmt = FMT_BMP; + + } else if (keymatch(arg, "colors", 1) || keymatch(arg, "colours", 1) || + keymatch(arg, "quantize", 1) || keymatch(arg, "quantise", 1)) { + /* Do color quantization. */ + int val; + + if (++argn >= argc) /* advance to next argument */ + usage(); + if (sscanf(argv[argn], "%d", &val) != 1) + usage(); + cinfo->desired_number_of_colors = val; + cinfo->quantize_colors = TRUE; + + } else if (keymatch(arg, "dct", 2)) { + /* Select IDCT algorithm. */ + if (++argn >= argc) /* advance to next argument */ + usage(); + if (keymatch(argv[argn], "int", 1)) { + cinfo->dct_method = JDCT_ISLOW; + } else if (keymatch(argv[argn], "fast", 2)) { + cinfo->dct_method = JDCT_IFAST; + } else if (keymatch(argv[argn], "float", 2)) { + cinfo->dct_method = JDCT_FLOAT; + } else + usage(); + + } else if (keymatch(arg, "dither", 2)) { + /* Select dithering algorithm. */ + if (++argn >= argc) /* advance to next argument */ + usage(); + if (keymatch(argv[argn], "fs", 2)) { + cinfo->dither_mode = JDITHER_FS; + } else if (keymatch(argv[argn], "none", 2)) { + cinfo->dither_mode = JDITHER_NONE; + } else if (keymatch(argv[argn], "ordered", 2)) { + cinfo->dither_mode = JDITHER_ORDERED; + } else + usage(); + + } else if (keymatch(arg, "debug", 1) || keymatch(arg, "verbose", 1)) { + /* Enable debug printouts. */ + /* On first -d, print version identification */ + static boolean printed_version = FALSE; + + if (! printed_version) { + fprintf(stderr, "Independent JPEG Group's DJPEG, version %s\n%s\n", + JVERSION, JCOPYRIGHT); + printed_version = TRUE; + } + cinfo->err->trace_level++; + + } else if (keymatch(arg, "fast", 1)) { + /* Select recommended processing options for quick-and-dirty output. */ + cinfo->two_pass_quantize = FALSE; + cinfo->dither_mode = JDITHER_ORDERED; + if (! cinfo->quantize_colors) /* don't override an earlier -colors */ + cinfo->desired_number_of_colors = 216; + cinfo->dct_method = JDCT_FASTEST; + cinfo->do_fancy_upsampling = FALSE; + + } else if (keymatch(arg, "gif", 1)) { + /* GIF output format. */ + requested_fmt = FMT_GIF; + + } else if (keymatch(arg, "grayscale", 2) || keymatch(arg, "greyscale",2)) { + /* Force monochrome output. */ + cinfo->out_color_space = JCS_GRAYSCALE; + + } else if (keymatch(arg, "map", 3)) { + /* Quantize to a color map taken from an input file. */ + if (++argn >= argc) /* advance to next argument */ + usage(); + if (for_real) { /* too expensive to do twice! */ +#ifdef QUANT_2PASS_SUPPORTED /* otherwise can't quantize to supplied map */ + FILE * mapfile; + + if ((mapfile = fopen(argv[argn], READ_BINARY)) == NULL) { + fprintf(stderr, "%s: can't open %s\n", progname, argv[argn]); + exit(EXIT_FAILURE); + } + read_color_map(cinfo, mapfile); + fclose(mapfile); + cinfo->quantize_colors = TRUE; +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } + + } else if (keymatch(arg, "maxmemory", 3)) { + /* Maximum memory in Kb (or Mb with 'm'). */ + long lval; + char ch = 'x'; + + if (++argn >= argc) /* advance to next argument */ + usage(); + if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1) + usage(); + if (ch == 'm' || ch == 'M') + lval *= 1000L; + cinfo->mem->max_memory_to_use = lval * 1000L; + + } else if (keymatch(arg, "nosmooth", 3)) { + /* Suppress fancy upsampling */ + cinfo->do_fancy_upsampling = FALSE; + + } else if (keymatch(arg, "onepass", 3)) { + /* Use fast one-pass quantization. */ + cinfo->two_pass_quantize = FALSE; + + } else if (keymatch(arg, "os2", 3)) { + /* BMP output format (OS/2 flavor). */ + requested_fmt = FMT_OS2; + + } else if (keymatch(arg, "outfile", 4)) { + /* Set output file name. */ + if (++argn >= argc) /* advance to next argument */ + usage(); + outfilename = argv[argn]; /* save it away for later use */ + + } else if (keymatch(arg, "pnm", 1) || keymatch(arg, "ppm", 1)) { + /* PPM/PGM output format. */ + requested_fmt = FMT_PPM; + + } else if (keymatch(arg, "rle", 1)) { + /* RLE output format. */ + requested_fmt = FMT_RLE; + + } else if (keymatch(arg, "scale", 1)) { + /* Scale the output image by a fraction M/N. */ + if (++argn >= argc) /* advance to next argument */ + usage(); + if (sscanf(argv[argn], "%d/%d", + &cinfo->scale_num, &cinfo->scale_denom) != 2) + usage(); + + } else if (keymatch(arg, "targa", 1)) { + /* Targa output format. */ + requested_fmt = FMT_TARGA; + + } else { + usage(); /* bogus switch */ + } + } + + return argn; /* return index of next arg (file name) */ +} + + +/* + * Marker processor for COM and interesting APPn markers. + * This replaces the library's built-in processor, which just skips the marker. + * We want to print out the marker as text, to the extent possible. + * Note this code relies on a non-suspending data source. + */ + +LOCAL(unsigned int) +jpeg_getc (j_decompress_ptr cinfo) +/* Read next byte */ +{ + struct jpeg_source_mgr * datasrc = cinfo->src; + + if (datasrc->bytes_in_buffer == 0) { + if (! (*datasrc->fill_input_buffer) (cinfo)) + ERREXIT(cinfo, JERR_CANT_SUSPEND); + } + datasrc->bytes_in_buffer--; + return GETJOCTET(*datasrc->next_input_byte++); +} + + +METHODDEF(boolean) +print_text_marker (j_decompress_ptr cinfo) +{ + boolean traceit = (cinfo->err->trace_level >= 1); + INT32 length; + unsigned int ch; + unsigned int lastch = 0; + + length = jpeg_getc(cinfo) << 8; + length += jpeg_getc(cinfo); + length -= 2; /* discount the length word itself */ + + if (traceit) { + if (cinfo->unread_marker == JPEG_COM) + fprintf(stderr, "Comment, length %ld:\n", (long) length); + else /* assume it is an APPn otherwise */ + fprintf(stderr, "APP%d, length %ld:\n", + cinfo->unread_marker - JPEG_APP0, (long) length); + } + + while (--length >= 0) { + ch = jpeg_getc(cinfo); + if (traceit) { + /* Emit the character in a readable form. + * Nonprintables are converted to \nnn form, + * while \ is converted to \\. + * Newlines in CR, CR/LF, or LF form will be printed as one newline. + */ + if (ch == '\r') { + fprintf(stderr, "\n"); + } else if (ch == '\n') { + if (lastch != '\r') + fprintf(stderr, "\n"); + } else if (ch == '\\') { + fprintf(stderr, "\\\\"); + } else if (isprint(ch)) { + putc(ch, stderr); + } else { + fprintf(stderr, "\\%03o", ch); + } + lastch = ch; + } + } + + if (traceit) + fprintf(stderr, "\n"); + + return TRUE; +} + + +/* + * The main program. + */ + +int +main (int argc, char **argv) +{ + struct jpeg_decompress_struct cinfo; + struct jpeg_error_mgr jerr; +#ifdef PROGRESS_REPORT + struct cdjpeg_progress_mgr progress; +#endif + int file_index; + djpeg_dest_ptr dest_mgr = NULL; + FILE * input_file; + FILE * output_file; + JDIMENSION num_scanlines; + + /* On Mac, fetch a command line. */ +#ifdef USE_CCOMMAND + argc = ccommand(&argv); +#endif + + progname = argv[0]; + if (progname == NULL || progname[0] == 0) + progname = "djpeg"; /* in case C library doesn't provide it */ + + /* Initialize the JPEG decompression object with default error handling. */ + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_decompress(&cinfo); + /* Add some application-specific error messages (from cderror.h) */ + jerr.addon_message_table = cdjpeg_message_table; + jerr.first_addon_message = JMSG_FIRSTADDONCODE; + jerr.last_addon_message = JMSG_LASTADDONCODE; + + /* Insert custom marker processor for COM and APP12. + * APP12 is used by some digital camera makers for textual info, + * so we provide the ability to display it as text. + * If you like, additional APPn marker types can be selected for display, + * but don't try to override APP0 or APP14 this way (see libjpeg.doc). + */ + jpeg_set_marker_processor(&cinfo, JPEG_COM, print_text_marker); + jpeg_set_marker_processor(&cinfo, JPEG_APP0+12, print_text_marker); + + /* Now safe to enable signal catcher. */ +#ifdef NEED_SIGNAL_CATCHER + enable_signal_catcher((j_common_ptr) &cinfo); +#endif + + /* Scan command line to find file names. */ + /* It is convenient to use just one switch-parsing routine, but the switch + * values read here are ignored; we will rescan the switches after opening + * the input file. + * (Exception: tracing level set here controls verbosity for COM markers + * found during jpeg_read_header...) + */ + + file_index = parse_switches(&cinfo, argc, argv, 0, FALSE); + +#ifdef TWO_FILE_COMMANDLINE + /* Must have either -outfile switch or explicit output file name */ + if (outfilename == NULL) { + if (file_index != argc-2) { + fprintf(stderr, "%s: must name one input and one output file\n", + progname); + usage(); + } + outfilename = argv[file_index+1]; + } else { + if (file_index != argc-1) { + fprintf(stderr, "%s: must name one input and one output file\n", + progname); + usage(); + } + } +#else + /* Unix style: expect zero or one file name */ + if (file_index < argc-1) { + fprintf(stderr, "%s: only one input file\n", progname); + usage(); + } +#endif /* TWO_FILE_COMMANDLINE */ + + /* Open the input file. */ + if (file_index < argc) { + if ((input_file = fopen(argv[file_index], READ_BINARY)) == NULL) { + fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index]); + exit(EXIT_FAILURE); + } + } else { + /* default input file is stdin */ + input_file = read_stdin(); + } + + /* Open the output file. */ + if (outfilename != NULL) { + if ((output_file = fopen(outfilename, WRITE_BINARY)) == NULL) { + fprintf(stderr, "%s: can't open %s\n", progname, outfilename); + exit(EXIT_FAILURE); + } + } else { + /* default output file is stdout */ + output_file = write_stdout(); + } + +#ifdef PROGRESS_REPORT + start_progress_monitor((j_common_ptr) &cinfo, &progress); +#endif + + /* Specify data source for decompression */ + jpeg_stdio_src(&cinfo, input_file); + + /* Read file header, set default decompression parameters */ + (void) jpeg_read_header(&cinfo, TRUE); + + /* Adjust default decompression parameters by re-parsing the options */ + file_index = parse_switches(&cinfo, argc, argv, 0, TRUE); + + /* Initialize the output module now to let it override any crucial + * option settings (for instance, GIF wants to force color quantization). + */ + switch (requested_fmt) { +#ifdef BMP_SUPPORTED + case FMT_BMP: + dest_mgr = jinit_write_bmp(&cinfo, FALSE); + break; + case FMT_OS2: + dest_mgr = jinit_write_bmp(&cinfo, TRUE); + break; +#endif +#ifdef GIF_SUPPORTED + case FMT_GIF: + dest_mgr = jinit_write_gif(&cinfo); + break; +#endif +#ifdef PPM_SUPPORTED + case FMT_PPM: + dest_mgr = jinit_write_ppm(&cinfo); + break; +#endif +#ifdef RLE_SUPPORTED + case FMT_RLE: + dest_mgr = jinit_write_rle(&cinfo); + break; +#endif +#ifdef TARGA_SUPPORTED + case FMT_TARGA: + dest_mgr = jinit_write_targa(&cinfo); + break; +#endif + default: + ERREXIT(&cinfo, JERR_UNSUPPORTED_FORMAT); + break; + } + dest_mgr->output_file = output_file; + + /* Start decompressor */ + (void) jpeg_start_decompress(&cinfo); + + /* Write output file header */ + (*dest_mgr->start_output) (&cinfo, dest_mgr); + + /* Process data */ + while (cinfo.output_scanline < cinfo.output_height) { + num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer, + dest_mgr->buffer_height); + (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines); + } + +#ifdef PROGRESS_REPORT + /* Hack: count final pass as done in case finish_output does an extra pass. + * The library won't have updated completed_passes. + */ + progress.pub.completed_passes = progress.pub.total_passes; +#endif + + /* Finish decompression and release memory. + * I must do it in this order because output module has allocated memory + * of lifespan JPOOL_IMAGE; it needs to finish before releasing memory. + */ + (*dest_mgr->finish_output) (&cinfo, dest_mgr); + (void) jpeg_finish_decompress(&cinfo); + jpeg_destroy_decompress(&cinfo); + + /* Close files, if we opened them */ + if (input_file != stdin) + fclose(input_file); + if (output_file != stdout) + fclose(output_file); + +#ifdef PROGRESS_REPORT + end_progress_monitor((j_common_ptr) &cinfo); +#endif + + /* All done. */ + exit(jerr.num_warnings ? EXIT_WARNING : EXIT_SUCCESS); + return 0; /* suppress no-return-value warnings */ +} diff --git a/mk4/modimage/jpeg-6b/example.c b/mk4/modimage/jpeg-6b/example.c new file mode 100644 index 0000000..7fc354f --- /dev/null +++ b/mk4/modimage/jpeg-6b/example.c @@ -0,0 +1,433 @@ +/* + * example.c + * + * This file illustrates how to use the IJG code as a subroutine library + * to read or write JPEG image files. You should look at this code in + * conjunction with the documentation file libjpeg.doc. + * + * This code will not do anything useful as-is, but it may be helpful as a + * skeleton for constructing routines that call the JPEG library. + * + * We present these routines in the same coding style used in the JPEG code + * (ANSI function definitions, etc); but you are of course free to code your + * routines in a different style if you prefer. + */ + +#include + +/* + * Include file for users of JPEG library. + * You will need to have included system headers that define at least + * the typedefs FILE and size_t before you can include jpeglib.h. + * (stdio.h is sufficient on ANSI-conforming systems.) + * You may also wish to include "jerror.h". + */ + +#include "jpeglib.h" + +/* + * is used for the optional error recovery mechanism shown in + * the second part of the example. + */ + +#include + + + +/******************** JPEG COMPRESSION SAMPLE INTERFACE *******************/ + +/* This half of the example shows how to feed data into the JPEG compressor. + * We present a minimal version that does not worry about refinements such + * as error recovery (the JPEG code will just exit() if it gets an error). + */ + + +/* + * IMAGE DATA FORMATS: + * + * The standard input image format is a rectangular array of pixels, with + * each pixel having the same number of "component" values (color channels). + * Each pixel row is an array of JSAMPLEs (which typically are unsigned chars). + * If you are working with color data, then the color values for each pixel + * must be adjacent in the row; for example, R,G,B,R,G,B,R,G,B,... for 24-bit + * RGB color. + * + * For this example, we'll assume that this data structure matches the way + * our application has stored the image in memory, so we can just pass a + * pointer to our image buffer. In particular, let's say that the image is + * RGB color and is described by: + */ + +extern JSAMPLE * image_buffer; /* Points to large array of R,G,B-order data */ +extern int image_height; /* Number of rows in image */ +extern int image_width; /* Number of columns in image */ + + +/* + * Sample routine for JPEG compression. We assume that the target file name + * and a compression quality factor are passed in. + */ + +GLOBAL(void) +write_JPEG_file (char * filename, int quality) +{ + /* This struct contains the JPEG compression parameters and pointers to + * working space (which is allocated as needed by the JPEG library). + * It is possible to have several such structures, representing multiple + * compression/decompression processes, in existence at once. We refer + * to any one struct (and its associated working data) as a "JPEG object". + */ + struct jpeg_compress_struct cinfo; + /* This struct represents a JPEG error handler. It is declared separately + * because applications often want to supply a specialized error handler + * (see the second half of this file for an example). But here we just + * take the easy way out and use the standard error handler, which will + * print a message on stderr and call exit() if compression fails. + * Note that this struct must live as long as the main JPEG parameter + * struct, to avoid dangling-pointer problems. + */ + struct jpeg_error_mgr jerr; + /* More stuff */ + FILE * outfile; /* target file */ + JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ + int row_stride; /* physical row width in image buffer */ + + /* Step 1: allocate and initialize JPEG compression object */ + + /* We have to set up the error handler first, in case the initialization + * step fails. (Unlikely, but it could happen if you are out of memory.) + * This routine fills in the contents of struct jerr, and returns jerr's + * address which we place into the link field in cinfo. + */ + cinfo.err = jpeg_std_error(&jerr); + /* Now we can initialize the JPEG compression object. */ + jpeg_create_compress(&cinfo); + + /* Step 2: specify data destination (eg, a file) */ + /* Note: steps 2 and 3 can be done in either order. */ + + /* Here we use the library-supplied code to send compressed data to a + * stdio stream. You can also write your own code to do something else. + * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that + * requires it in order to write binary files. + */ + if ((outfile = fopen(filename, "wb")) == NULL) { + fprintf(stderr, "can't open %s\n", filename); + exit(1); + } + jpeg_stdio_dest(&cinfo, outfile); + + /* Step 3: set parameters for compression */ + + /* First we supply a description of the input image. + * Four fields of the cinfo struct must be filled in: + */ + cinfo.image_width = image_width; /* image width and height, in pixels */ + cinfo.image_height = image_height; + cinfo.input_components = 3; /* # of color components per pixel */ + cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ + /* Now use the library's routine to set default compression parameters. + * (You must set at least cinfo.in_color_space before calling this, + * since the defaults depend on the source color space.) + */ + jpeg_set_defaults(&cinfo); + /* Now you can set any non-default parameters you wish to. + * Here we just illustrate the use of quality (quantization table) scaling: + */ + jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */); + + /* Step 4: Start compressor */ + + /* TRUE ensures that we will write a complete interchange-JPEG file. + * Pass TRUE unless you are very sure of what you're doing. + */ + jpeg_start_compress(&cinfo, TRUE); + + /* Step 5: while (scan lines remain to be written) */ + /* jpeg_write_scanlines(...); */ + + /* Here we use the library's state variable cinfo.next_scanline as the + * loop counter, so that we don't have to keep track ourselves. + * To keep things simple, we pass one scanline per call; you can pass + * more if you wish, though. + */ + row_stride = image_width * 3; /* JSAMPLEs per row in image_buffer */ + + while (cinfo.next_scanline < cinfo.image_height) { + /* jpeg_write_scanlines expects an array of pointers to scanlines. + * Here the array is only one element long, but you could pass + * more than one scanline at a time if that's more convenient. + */ + row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride]; + (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); + } + + /* Step 6: Finish compression */ + + jpeg_finish_compress(&cinfo); + /* After finish_compress, we can close the output file. */ + fclose(outfile); + + /* Step 7: release JPEG compression object */ + + /* This is an important step since it will release a good deal of memory. */ + jpeg_destroy_compress(&cinfo); + + /* And we're done! */ +} + + +/* + * SOME FINE POINTS: + * + * In the above loop, we ignored the return value of jpeg_write_scanlines, + * which is the number of scanlines actually written. We could get away + * with this because we were only relying on the value of cinfo.next_scanline, + * which will be incremented correctly. If you maintain additional loop + * variables then you should be careful to increment them properly. + * Actually, for output to a stdio stream you needn't worry, because + * then jpeg_write_scanlines will write all the lines passed (or else exit + * with a fatal error). Partial writes can only occur if you use a data + * destination module that can demand suspension of the compressor. + * (If you don't know what that's for, you don't need it.) + * + * If the compressor requires full-image buffers (for entropy-coding + * optimization or a multi-scan JPEG file), it will create temporary + * files for anything that doesn't fit within the maximum-memory setting. + * (Note that temp files are NOT needed if you use the default parameters.) + * On some systems you may need to set up a signal handler to ensure that + * temporary files are deleted if the program is interrupted. See libjpeg.doc. + * + * Scanlines MUST be supplied in top-to-bottom order if you want your JPEG + * files to be compatible with everyone else's. If you cannot readily read + * your data in that order, you'll need an intermediate array to hold the + * image. See rdtarga.c or rdbmp.c for examples of handling bottom-to-top + * source data using the JPEG code's internal virtual-array mechanisms. + */ + + + +/******************** JPEG DECOMPRESSION SAMPLE INTERFACE *******************/ + +/* This half of the example shows how to read data from the JPEG decompressor. + * It's a bit more refined than the above, in that we show: + * (a) how to modify the JPEG library's standard error-reporting behavior; + * (b) how to allocate workspace using the library's memory manager. + * + * Just to make this example a little different from the first one, we'll + * assume that we do not intend to put the whole image into an in-memory + * buffer, but to send it line-by-line someplace else. We need a one- + * scanline-high JSAMPLE array as a work buffer, and we will let the JPEG + * memory manager allocate it for us. This approach is actually quite useful + * because we don't need to remember to deallocate the buffer separately: it + * will go away automatically when the JPEG object is cleaned up. + */ + + +/* + * ERROR HANDLING: + * + * The JPEG library's standard error handler (jerror.c) is divided into + * several "methods" which you can override individually. This lets you + * adjust the behavior without duplicating a lot of code, which you might + * have to update with each future release. + * + * Our example here shows how to override the "error_exit" method so that + * control is returned to the library's caller when a fatal error occurs, + * rather than calling exit() as the standard error_exit method does. + * + * We use C's setjmp/longjmp facility to return control. This means that the + * routine which calls the JPEG library must first execute a setjmp() call to + * establish the return point. We want the replacement error_exit to do a + * longjmp(). But we need to make the setjmp buffer accessible to the + * error_exit routine. To do this, we make a private extension of the + * standard JPEG error handler object. (If we were using C++, we'd say we + * were making a subclass of the regular error handler.) + * + * Here's the extended error handler struct: + */ + +struct my_error_mgr { + struct jpeg_error_mgr pub; /* "public" fields */ + + jmp_buf setjmp_buffer; /* for return to caller */ +}; + +typedef struct my_error_mgr * my_error_ptr; + +/* + * Here's the routine that will replace the standard error_exit method: + */ + +METHODDEF(void) +my_error_exit (j_common_ptr cinfo) +{ + /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */ + my_error_ptr myerr = (my_error_ptr) cinfo->err; + + /* Always display the message. */ + /* We could postpone this until after returning, if we chose. */ + (*cinfo->err->output_message) (cinfo); + + /* Return control to the setjmp point */ + longjmp(myerr->setjmp_buffer, 1); +} + + +/* + * Sample routine for JPEG decompression. We assume that the source file name + * is passed in. We want to return 1 on success, 0 on error. + */ + + +GLOBAL(int) +read_JPEG_file (char * filename) +{ + /* This struct contains the JPEG decompression parameters and pointers to + * working space (which is allocated as needed by the JPEG library). + */ + struct jpeg_decompress_struct cinfo; + /* We use our private extension JPEG error handler. + * Note that this struct must live as long as the main JPEG parameter + * struct, to avoid dangling-pointer problems. + */ + struct my_error_mgr jerr; + /* More stuff */ + FILE * infile; /* source file */ + JSAMPARRAY buffer; /* Output row buffer */ + int row_stride; /* physical row width in output buffer */ + + /* In this example we want to open the input file before doing anything else, + * so that the setjmp() error recovery below can assume the file is open. + * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that + * requires it in order to read binary files. + */ + + if ((infile = fopen(filename, "rb")) == NULL) { + fprintf(stderr, "can't open %s\n", filename); + return 0; + } + + /* Step 1: allocate and initialize JPEG decompression object */ + + /* We set up the normal JPEG error routines, then override error_exit. */ + cinfo.err = jpeg_std_error(&jerr.pub); + jerr.pub.error_exit = my_error_exit; + /* Establish the setjmp return context for my_error_exit to use. */ + if (setjmp(jerr.setjmp_buffer)) { + /* If we get here, the JPEG code has signaled an error. + * We need to clean up the JPEG object, close the input file, and return. + */ + jpeg_destroy_decompress(&cinfo); + fclose(infile); + return 0; + } + /* Now we can initialize the JPEG decompression object. */ + jpeg_create_decompress(&cinfo); + + /* Step 2: specify data source (eg, a file) */ + + jpeg_stdio_src(&cinfo, infile); + + /* Step 3: read file parameters with jpeg_read_header() */ + + (void) jpeg_read_header(&cinfo, TRUE); + /* We can ignore the return value from jpeg_read_header since + * (a) suspension is not possible with the stdio data source, and + * (b) we passed TRUE to reject a tables-only JPEG file as an error. + * See libjpeg.doc for more info. + */ + + /* Step 4: set parameters for decompression */ + + /* In this example, we don't need to change any of the defaults set by + * jpeg_read_header(), so we do nothing here. + */ + + /* Step 5: Start decompressor */ + + (void) jpeg_start_decompress(&cinfo); + /* We can ignore the return value since suspension is not possible + * with the stdio data source. + */ + + /* We may need to do some setup of our own at this point before reading + * the data. After jpeg_start_decompress() we have the correct scaled + * output image dimensions available, as well as the output colormap + * if we asked for color quantization. + * In this example, we need to make an output work buffer of the right size. + */ + /* JSAMPLEs per row in output buffer */ + row_stride = cinfo.output_width * cinfo.output_components; + /* Make a one-row-high sample array that will go away when done with image */ + buffer = (*cinfo.mem->alloc_sarray) + ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); + + /* Step 6: while (scan lines remain to be read) */ + /* jpeg_read_scanlines(...); */ + + /* Here we use the library's state variable cinfo.output_scanline as the + * loop counter, so that we don't have to keep track ourselves. + */ + while (cinfo.output_scanline < cinfo.output_height) { + /* jpeg_read_scanlines expects an array of pointers to scanlines. + * Here the array is only one element long, but you could ask for + * more than one scanline at a time if that's more convenient. + */ + (void) jpeg_read_scanlines(&cinfo, buffer, 1); + /* Assume put_scanline_someplace wants a pointer and sample count. */ + put_scanline_someplace(buffer[0], row_stride); + } + + /* Step 7: Finish decompression */ + + (void) jpeg_finish_decompress(&cinfo); + /* We can ignore the return value since suspension is not possible + * with the stdio data source. + */ + + /* Step 8: Release JPEG decompression object */ + + /* This is an important step since it will release a good deal of memory. */ + jpeg_destroy_decompress(&cinfo); + + /* After finish_decompress, we can close the input file. + * Here we postpone it until after no more JPEG errors are possible, + * so as to simplify the setjmp error logic above. (Actually, I don't + * think that jpeg_destroy can do an error exit, but why assume anything...) + */ + fclose(infile); + + /* At this point you may want to check to see whether any corrupt-data + * warnings occurred (test whether jerr.pub.num_warnings is nonzero). + */ + + /* And we're done! */ + return 1; +} + + +/* + * SOME FINE POINTS: + * + * In the above code, we ignored the return value of jpeg_read_scanlines, + * which is the number of scanlines actually read. We could get away with + * this because we asked for only one line at a time and we weren't using + * a suspending data source. See libjpeg.doc for more info. + * + * We cheated a bit by calling alloc_sarray() after jpeg_start_decompress(); + * we should have done it beforehand to ensure that the space would be + * counted against the JPEG max_memory setting. In some systems the above + * code would risk an out-of-memory error. However, in general we don't + * know the output image dimensions before jpeg_start_decompress(), unless we + * call jpeg_calc_output_dimensions(). See libjpeg.doc for more about this. + * + * Scanlines are returned in the same order as they appear in the JPEG file, + * which is standardly top-to-bottom. If you must emit data bottom-to-top, + * you can use one of the virtual arrays provided by the JPEG memory manager + * to invert the data. See wrbmp.c for an example. + * + * As with compression, some operating modes may require temporary files. + * On some systems you may need to set up a signal handler to ensure that + * temporary files are deleted if the program is interrupted. See libjpeg.doc. + */ diff --git a/mk4/modimage/jpeg-6b/filelist.doc b/mk4/modimage/jpeg-6b/filelist.doc new file mode 100644 index 0000000..e14982c --- /dev/null +++ b/mk4/modimage/jpeg-6b/filelist.doc @@ -0,0 +1,210 @@ +IJG JPEG LIBRARY: FILE LIST + +Copyright (C) 1994-1998, Thomas G. Lane. +This file is part of the Independent JPEG Group's software. +For conditions of distribution and use, see the accompanying README file. + + +Here is a road map to the files in the IJG JPEG distribution. The +distribution includes the JPEG library proper, plus two application +programs ("cjpeg" and "djpeg") which use the library to convert JPEG +files to and from some other popular image formats. A third application +"jpegtran" uses the library to do lossless conversion between different +variants of JPEG. There are also two stand-alone applications, +"rdjpgcom" and "wrjpgcom". + + +THE JPEG LIBRARY +================ + +Include files: + +jpeglib.h JPEG library's exported data and function declarations. +jconfig.h Configuration declarations. Note: this file is not present + in the distribution; it is generated during installation. +jmorecfg.h Additional configuration declarations; need not be changed + for a standard installation. +jerror.h Declares JPEG library's error and trace message codes. +jinclude.h Central include file used by all IJG .c files to reference + system include files. +jpegint.h JPEG library's internal data structures. +jchuff.h Private declarations for Huffman encoder modules. +jdhuff.h Private declarations for Huffman decoder modules. +jdct.h Private declarations for forward & reverse DCT subsystems. +jmemsys.h Private declarations for memory management subsystem. +jversion.h Version information. + +Applications using the library should include jpeglib.h (which in turn +includes jconfig.h and jmorecfg.h). Optionally, jerror.h may be included +if the application needs to reference individual JPEG error codes. The +other include files are intended for internal use and would not normally +be included by an application program. (cjpeg/djpeg/etc do use jinclude.h, +since its function is to improve portability of the whole IJG distribution. +Most other applications will directly include the system include files they +want, and hence won't need jinclude.h.) + + +C source code files: + +These files contain most of the functions intended to be called directly by +an application program: + +jcapimin.c Application program interface: core routines for compression. +jcapistd.c Application program interface: standard compression. +jdapimin.c Application program interface: core routines for decompression. +jdapistd.c Application program interface: standard decompression. +jcomapi.c Application program interface routines common to compression + and decompression. +jcparam.c Compression parameter setting helper routines. +jctrans.c API and library routines for transcoding compression. +jdtrans.c API and library routines for transcoding decompression. + +Compression side of the library: + +jcinit.c Initialization: determines which other modules to use. +jcmaster.c Master control: setup and inter-pass sequencing logic. +jcmainct.c Main buffer controller (preprocessor => JPEG compressor). +jcprepct.c Preprocessor buffer controller. +jccoefct.c Buffer controller for DCT coefficient buffer. +jccolor.c Color space conversion. +jcsample.c Downsampling. +jcdctmgr.c DCT manager (DCT implementation selection & control). +jfdctint.c Forward DCT using slow-but-accurate integer method. +jfdctfst.c Forward DCT using faster, less accurate integer method. +jfdctflt.c Forward DCT using floating-point arithmetic. +jchuff.c Huffman entropy coding for sequential JPEG. +jcphuff.c Huffman entropy coding for progressive JPEG. +jcmarker.c JPEG marker writing. +jdatadst.c Data destination manager for stdio output. + +Decompression side of the library: + +jdmaster.c Master control: determines which other modules to use. +jdinput.c Input controller: controls input processing modules. +jdmainct.c Main buffer controller (JPEG decompressor => postprocessor). +jdcoefct.c Buffer controller for DCT coefficient buffer. +jdpostct.c Postprocessor buffer controller. +jdmarker.c JPEG marker reading. +jdhuff.c Huffman entropy decoding for sequential JPEG. +jdphuff.c Huffman entropy decoding for progressive JPEG. +jddctmgr.c IDCT manager (IDCT implementation selection & control). +jidctint.c Inverse DCT using slow-but-accurate integer method. +jidctfst.c Inverse DCT using faster, less accurate integer method. +jidctflt.c Inverse DCT using floating-point arithmetic. +jidctred.c Inverse DCTs with reduced-size outputs. +jdsample.c Upsampling. +jdcolor.c Color space conversion. +jdmerge.c Merged upsampling/color conversion (faster, lower quality). +jquant1.c One-pass color quantization using a fixed-spacing colormap. +jquant2.c Two-pass color quantization using a custom-generated colormap. + Also handles one-pass quantization to an externally given map. +jdatasrc.c Data source manager for stdio input. + +Support files for both compression and decompression: + +jerror.c Standard error handling routines (application replaceable). +jmemmgr.c System-independent (more or less) memory management code. +jutils.c Miscellaneous utility routines. + +jmemmgr.c relies on a system-dependent memory management module. The IJG +distribution includes the following implementations of the system-dependent +module: + +jmemnobs.c "No backing store": assumes adequate virtual memory exists. +jmemansi.c Makes temporary files with ANSI-standard routine tmpfile(). +jmemname.c Makes temporary files with program-generated file names. +jmemdos.c Custom implementation for MS-DOS (16-bit environment only): + can use extended and expanded memory as well as temp files. +jmemmac.c Custom implementation for Apple Macintosh. + +Exactly one of the system-dependent modules should be configured into an +installed JPEG library (see install.doc for hints about which one to use). +On unusual systems you may find it worthwhile to make a special +system-dependent memory manager. + + +Non-C source code files: + +jmemdosa.asm 80x86 assembly code support for jmemdos.c; used only in + MS-DOS-specific configurations of the JPEG library. + + +CJPEG/DJPEG/JPEGTRAN +==================== + +Include files: + +cdjpeg.h Declarations shared by cjpeg/djpeg/jpegtran modules. +cderror.h Additional error and trace message codes for cjpeg et al. +transupp.h Declarations for jpegtran support routines in transupp.c. + +C source code files: + +cjpeg.c Main program for cjpeg. +djpeg.c Main program for djpeg. +jpegtran.c Main program for jpegtran. +cdjpeg.c Utility routines used by all three programs. +rdcolmap.c Code to read a colormap file for djpeg's "-map" switch. +rdswitch.c Code to process some of cjpeg's more complex switches. + Also used by jpegtran. +transupp.c Support code for jpegtran: lossless image manipulations. + +Image file reader modules for cjpeg: + +rdbmp.c BMP file input. +rdgif.c GIF file input (now just a stub). +rdppm.c PPM/PGM file input. +rdrle.c Utah RLE file input. +rdtarga.c Targa file input. + +Image file writer modules for djpeg: + +wrbmp.c BMP file output. +wrgif.c GIF file output (a mere shadow of its former self). +wrppm.c PPM/PGM file output. +wrrle.c Utah RLE file output. +wrtarga.c Targa file output. + + +RDJPGCOM/WRJPGCOM +================= + +C source code files: + +rdjpgcom.c Stand-alone rdjpgcom application. +wrjpgcom.c Stand-alone wrjpgcom application. + +These programs do not depend on the IJG library. They do use +jconfig.h and jinclude.h, only to improve portability. + + +ADDITIONAL FILES +================ + +Documentation (see README for a guide to the documentation files): + +README Master documentation file. +*.doc Other documentation files. +*.1 Documentation in Unix man page format. +change.log Version-to-version change highlights. +example.c Sample code for calling JPEG library. + +Configuration/installation files and programs (see install.doc for more info): + +configure Unix shell script to perform automatic configuration. +ltconfig Support scripts for configure (from GNU libtool). +ltmain.sh +config.guess +config.sub +install-sh Install shell script for those Unix systems lacking one. +ckconfig.c Program to generate jconfig.h on non-Unix systems. +jconfig.doc Template for making jconfig.h by hand. +makefile.* Sample makefiles for particular systems. +jconfig.* Sample jconfig.h for particular systems. +ansi2knr.c De-ANSIfier for pre-ANSI C compilers (courtesy of + L. Peter Deutsch and Aladdin Enterprises). + +Test files (see install.doc for test procedure): + +test*.* Source and comparison files for confidence test. + These are binary image files, NOT text files. diff --git a/mk4/modimage/jpeg-6b/install-sh b/mk4/modimage/jpeg-6b/install-sh new file mode 100644 index 0000000..e843669 --- /dev/null +++ b/mk4/modimage/jpeg-6b/install-sh @@ -0,0 +1,250 @@ +#!/bin/sh +# +# install - install a program, script, or datafile +# This comes from X11R5 (mit/util/scripts/install.sh). +# +# Copyright 1991 by the Massachusetts Institute of Technology +# +# Permission to use, copy, modify, distribute, and sell this software and its +# documentation for any purpose is hereby granted without fee, 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 M.I.T. not be used in advertising or +# publicity pertaining to distribution of the software without specific, +# written prior permission. M.I.T. makes no representations about the +# suitability of this software for any purpose. It is provided "as is" +# without express or implied warranty. +# +# 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 "install: no input file specified" + exit 1 +else + true +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d $dst ]; then + instcmd=: + else + instcmd=mkdir + 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 -o -d $src ] + then + true + else + echo "install: $src does not exist" + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "install: no destination specified" + exit 1 + else + true + 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 + true + 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 + true + fi + + pathcomp="${pathcomp}/" +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd $dst && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; 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 + true + fi + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + + $doit $instcmd $src $dsttmp && + + trap "rm -f ${dsttmp}" 0 && + +# 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 true;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && + +# Now rename the file to the real destination. + + $doit $rmcmd -f $dstdir/$dstfile && + $doit $mvcmd $dsttmp $dstdir/$dstfile + +fi && + + +exit 0 diff --git a/mk4/modimage/jpeg-6b/install.doc b/mk4/modimage/jpeg-6b/install.doc new file mode 100644 index 0000000..3702b98 --- /dev/null +++ b/mk4/modimage/jpeg-6b/install.doc @@ -0,0 +1,1063 @@ +INSTALLATION INSTRUCTIONS for the Independent JPEG Group's JPEG software + +Copyright (C) 1991-1998, Thomas G. Lane. +This file is part of the Independent JPEG Group's software. +For conditions of distribution and use, see the accompanying README file. + + +This file explains how to configure and install the IJG software. We have +tried to make this software extremely portable and flexible, so that it can be +adapted to almost any environment. The downside of this decision is that the +installation process is complicated. We have provided shortcuts to simplify +the task on common systems. But in any case, you will need at least a little +familiarity with C programming and program build procedures for your system. + +If you are only using this software as part of a larger program, the larger +program's installation procedure may take care of configuring the IJG code. +For example, Ghostscript's installation script will configure the IJG code. +You don't need to read this file if you just want to compile Ghostscript. + +If you are on a Unix machine, you may not need to read this file at all. +Try doing + ./configure + make + make test +If that doesn't complain, do + make install +(better do "make -n install" first to see if the makefile will put the files +where you want them). Read further if you run into snags or want to customize +the code for your system. + + +TABLE OF CONTENTS +----------------- + +Before you start +Configuring the software: + using the automatic "configure" script + using one of the supplied jconfig and makefile files + by hand +Building the software +Testing the software +Installing the software +Optional stuff +Optimization +Hints for specific systems + + +BEFORE YOU START +================ + +Before installing the software you must unpack the distributed source code. +Since you are reading this file, you have probably already succeeded in this +task. However, there is a potential for error if you needed to convert the +files to the local standard text file format (for example, if you are on +MS-DOS you may have converted LF end-of-line to CR/LF). You must apply +such conversion to all the files EXCEPT those whose names begin with "test". +The test files contain binary data; if you change them in any way then the +self-test will give bad results. + +Please check the last section of this file to see if there are hints for the +specific machine or compiler you are using. + + +CONFIGURING THE SOFTWARE +======================== + +To configure the IJG code for your system, you need to create two files: + * jconfig.h: contains values for system-dependent #define symbols. + * Makefile: controls the compilation process. +(On a non-Unix machine, you may create "project files" or some other +substitute for a Makefile. jconfig.h is needed in any environment.) + +We provide three different ways to generate these files: + * On a Unix system, you can just run the "configure" script. + * We provide sample jconfig files and makefiles for popular machines; + if your machine matches one of the samples, just copy the right sample + files to jconfig.h and Makefile. + * If all else fails, read the instructions below and make your own files. + + +Configuring the software using the automatic "configure" script +--------------------------------------------------------------- + +If you are on a Unix machine, you can just type + ./configure +and let the configure script construct appropriate configuration files. +If you're using "csh" on an old version of System V, you might need to type + sh configure +instead to prevent csh from trying to execute configure itself. +Expect configure to run for a few minutes, particularly on slower machines; +it works by compiling a series of test programs. + +Configure was created with GNU Autoconf and it follows the usual conventions +for GNU configure scripts. It makes a few assumptions that you may want to +override. You can do this by providing optional switches to configure: + +* If you want to build libjpeg as a shared library, say + ./configure --enable-shared +To get both shared and static libraries, say + ./configure --enable-shared --enable-static +Note that these switches invoke GNU libtool to take care of system-dependent +shared library building methods. If things don't work this way, please try +running configure without either switch; that should build a static library +without using libtool. If that works, your problem is probably with libtool +not with the IJG code. libtool is fairly new and doesn't support all flavors +of Unix yet. (You might be able to find a newer version of libtool than the +one included with libjpeg; see ftp.gnu.org. Report libtool problems to +bug-libtool@gnu.org.) + +* Configure will use gcc (GNU C compiler) if it's available, otherwise cc. +To force a particular compiler to be selected, use the CC option, for example + ./configure CC='cc' +The same method can be used to include any unusual compiler switches. +For example, on HP-UX you probably want to say + ./configure CC='cc -Aa' +to get HP's compiler to run in ANSI mode. + +* The default CFLAGS setting is "-O" for non-gcc compilers, "-O2" for gcc. +You can override this by saying, for example, + ./configure CFLAGS='-g' +if you want to compile with debugging support. + +* Configure will set up the makefile so that "make install" will install files +into /usr/local/bin, /usr/local/man, etc. You can specify an installation +prefix other than "/usr/local" by giving configure the option "--prefix=PATH". + +* If you don't have a lot of swap space, you may need to enable the IJG +software's internal virtual memory mechanism. To do this, give the option +"--enable-maxmem=N" where N is the default maxmemory limit in megabytes. +This is discussed in more detail under "Selecting a memory manager", below. +You probably don't need to worry about this on reasonably-sized Unix machines, +unless you plan to process very large images. + +Configure has some other features that are useful if you are cross-compiling +or working in a network of multiple machine types; but if you need those +features, you probably already know how to use them. + + +Configuring the software using one of the supplied jconfig and makefile files +----------------------------------------------------------------------------- + +If you have one of these systems, you can just use the provided configuration +files: + +Makefile jconfig file System and/or compiler + +makefile.manx jconfig.manx Amiga, Manx Aztec C +makefile.sas jconfig.sas Amiga, SAS C +makeproj.mac jconfig.mac Apple Macintosh, Metrowerks CodeWarrior +mak*jpeg.st jconfig.st Atari ST/STE/TT, Pure C or Turbo C +makefile.bcc jconfig.bcc MS-DOS or OS/2, Borland C +makefile.dj jconfig.dj MS-DOS, DJGPP (Delorie's port of GNU C) +makefile.mc6 jconfig.mc6 MS-DOS, Microsoft C (16-bit only) +makefile.wat jconfig.wat MS-DOS, OS/2, or Windows NT, Watcom C +makefile.vc jconfig.vc Windows NT/95, MS Visual C++ +make*.ds jconfig.vc Windows NT/95, MS Developer Studio +makefile.mms jconfig.vms Digital VMS, with MMS software +makefile.vms jconfig.vms Digital VMS, without MMS software + +Copy the proper jconfig file to jconfig.h and the makefile to Makefile (or +whatever your system uses as the standard makefile name). For more info see +the appropriate system-specific hints section near the end of this file. + + +Configuring the software by hand +-------------------------------- + +First, generate a jconfig.h file. If you are moderately familiar with C, +the comments in jconfig.doc should be enough information to do this; just +copy jconfig.doc to jconfig.h and edit it appropriately. Otherwise, you may +prefer to use the ckconfig.c program. You will need to compile and execute +ckconfig.c by hand --- we hope you know at least enough to do that. +ckconfig.c may not compile the first try (in fact, the whole idea is for it +to fail if anything is going to). If you get compile errors, fix them by +editing ckconfig.c according to the directions given in ckconfig.c. Once +you get it to run, it will write a suitable jconfig.h file, and will also +print out some advice about which makefile to use. + +You may also want to look at the canned jconfig files, if there is one for a +system similar to yours. + +Second, select a makefile and copy it to Makefile (or whatever your system +uses as the standard makefile name). The most generic makefiles we provide +are + makefile.ansi: if your C compiler supports function prototypes + makefile.unix: if not. +(You have function prototypes if ckconfig.c put "#define HAVE_PROTOTYPES" +in jconfig.h.) You may want to start from one of the other makefiles if +there is one for a system similar to yours. + +Look over the selected Makefile and adjust options as needed. In particular +you may want to change the CC and CFLAGS definitions. For instance, if you +are using GCC, set CC=gcc. If you had to use any compiler switches to get +ckconfig.c to work, make sure the same switches are in CFLAGS. + +If you are on a system that doesn't use makefiles, you'll need to set up +project files (or whatever you do use) to compile all the source files and +link them into executable files cjpeg, djpeg, jpegtran, rdjpgcom, and wrjpgcom. +See the file lists in any of the makefiles to find out which files go into +each program. Note that the provided makefiles all make a "library" file +libjpeg first, but you don't have to do that if you don't want to; the file +lists identify which source files are actually needed for compression, +decompression, or both. As a last resort, you can make a batch script that +just compiles everything and links it all together; makefile.vms is an example +of this (it's for VMS systems that have no make-like utility). + +Here are comments about some specific configuration decisions you'll +need to make: + +Command line style +------------------ + +These programs can use a Unix-like command line style which supports +redirection and piping, like this: + cjpeg inputfile >outputfile + cjpeg outputfile + source program | cjpeg >outputfile +The simpler "two file" command line style is just + cjpeg inputfile outputfile +You may prefer the two-file style, particularly if you don't have pipes. + +You MUST use two-file style on any system that doesn't cope well with binary +data fed through stdin/stdout; this is true for some MS-DOS compilers, for +example. If you're not on a Unix system, it's safest to assume you need +two-file style. (But if your compiler provides either the Posix-standard +fdopen() library routine or a Microsoft-compatible setmode() routine, you +can safely use the Unix command line style, by defining USE_FDOPEN or +USE_SETMODE respectively.) + +To use the two-file style, make jconfig.h say "#define TWO_FILE_COMMANDLINE". + +Selecting a memory manager +-------------------------- + +The IJG code is capable of working on images that are too big to fit in main +memory; data is swapped out to temporary files as necessary. However, the +code to do this is rather system-dependent. We provide five different +memory managers: + +* jmemansi.c This version uses the ANSI-standard library routine tmpfile(), + which not all non-ANSI systems have. On some systems + tmpfile() may put the temporary file in a non-optimal + location; if you don't like what it does, use jmemname.c. + +* jmemname.c This version creates named temporary files. For anything + except a Unix machine, you'll need to configure the + select_file_name() routine appropriately; see the comments + near the head of jmemname.c. If you use this version, define + NEED_SIGNAL_CATCHER in jconfig.h to make sure the temp files + are removed if the program is aborted. + +* jmemnobs.c (That stands for No Backing Store :-).) This will compile on + almost any system, but it assumes you have enough main memory + or virtual memory to hold the biggest images you work with. + +* jmemdos.c This should be used with most 16-bit MS-DOS compilers. + See the system-specific notes about MS-DOS for more info. + IMPORTANT: if you use this, define USE_MSDOS_MEMMGR in + jconfig.h, and include the assembly file jmemdosa.asm in the + programs. The supplied makefiles and jconfig files for + 16-bit MS-DOS compilers already do both. + +* jmemmac.c Custom version for Apple Macintosh; see the system-specific + notes for Macintosh for more info. + +To use a particular memory manager, change the SYSDEPMEM variable in your +makefile to equal the corresponding object file name (for example, jmemansi.o +or jmemansi.obj for jmemansi.c). + +If you have plenty of (real or virtual) main memory, just use jmemnobs.c. +"Plenty" means about ten bytes for every pixel in the largest images +you plan to process, so a lot of systems don't meet this criterion. +If yours doesn't, try jmemansi.c first. If that doesn't compile, you'll have +to use jmemname.c; be sure to adjust select_file_name() for local conditions. +You may also need to change unlink() to remove() in close_backing_store(). + +Except with jmemnobs.c or jmemmac.c, you need to adjust the DEFAULT_MAX_MEM +setting to a reasonable value for your system (either by adding a #define for +DEFAULT_MAX_MEM to jconfig.h, or by adding a -D switch to the Makefile). +This value limits the amount of data space the program will attempt to +allocate. Code and static data space isn't counted, so the actual memory +needs for cjpeg or djpeg are typically 100 to 150Kb more than the max-memory +setting. Larger max-memory settings reduce the amount of I/O needed to +process a large image, but too large a value can result in "insufficient +memory" failures. On most Unix machines (and other systems with virtual +memory), just set DEFAULT_MAX_MEM to several million and forget it. At the +other end of the spectrum, for MS-DOS machines you probably can't go much +above 300K to 400K. (On MS-DOS the value refers to conventional memory only. +Extended/expanded memory is handled separately by jmemdos.c.) + + +BUILDING THE SOFTWARE +===================== + +Now you should be able to compile the software. Just say "make" (or +whatever's necessary to start the compilation). Have a cup of coffee. + +Here are some things that could go wrong: + +If your compiler complains about undefined structures, you should be able to +shut it up by putting "#define INCOMPLETE_TYPES_BROKEN" in jconfig.h. + +If you have trouble with missing system include files or inclusion of the +wrong ones, read jinclude.h. This shouldn't happen if you used configure +or ckconfig.c to set up jconfig.h. + +There are a fair number of routines that do not use all of their parameters; +some compilers will issue warnings about this, which you can ignore. There +are also a few configuration checks that may give "unreachable code" warnings. +Any other warning deserves investigation. + +If you don't have a getenv() library routine, define NO_GETENV. + +Also see the system-specific hints, below. + + +TESTING THE SOFTWARE +==================== + +As a quick test of functionality we've included a small sample image in +several forms: + testorig.jpg Starting point for the djpeg tests. + testimg.ppm The output of djpeg testorig.jpg + testimg.bmp The output of djpeg -bmp -colors 256 testorig.jpg + testimg.jpg The output of cjpeg testimg.ppm + testprog.jpg Progressive-mode equivalent of testorig.jpg. + testimgp.jpg The output of cjpeg -progressive -optimize testimg.ppm +(The first- and second-generation .jpg files aren't identical since JPEG is +lossy.) If you can generate duplicates of the testimg* files then you +probably have working programs. + +With most of the makefiles, "make test" will perform the necessary +comparisons. + +If you're using a makefile that doesn't provide the test option, run djpeg +and cjpeg by hand and compare the output files to testimg* with whatever +binary file comparison tool you have. The files should be bit-for-bit +identical. + +If the programs complain "MAX_ALLOC_CHUNK is wrong, please fix", then you +need to reduce MAX_ALLOC_CHUNK to a value that fits in type size_t. +Try adding "#define MAX_ALLOC_CHUNK 65520L" to jconfig.h. A less likely +configuration error is "ALIGN_TYPE is wrong, please fix": defining ALIGN_TYPE +as long should take care of that one. + +If the cjpeg test run fails with "Missing Huffman code table entry", it's a +good bet that you needed to define RIGHT_SHIFT_IS_UNSIGNED. Go back to the +configuration step and run ckconfig.c. (This is a good plan for any other +test failure, too.) + +If you are using Unix (one-file) command line style on a non-Unix system, +it's a good idea to check that binary I/O through stdin/stdout actually +works. You should get the same results from "djpeg out.ppm" +as from "djpeg -outfile out.ppm testorig.jpg". Note that the makefiles all +use the latter style and therefore do not exercise stdin/stdout! If this +check fails, try recompiling with USE_SETMODE or USE_FDOPEN defined. +If it still doesn't work, better use two-file style. + +If you chose a memory manager other than jmemnobs.c, you should test that +temporary-file usage works. Try "djpeg -bmp -colors 256 -max 0 testorig.jpg" +and make sure its output matches testimg.bmp. If you have any really large +images handy, try compressing them with -optimize and/or decompressing with +-colors 256 to make sure your DEFAULT_MAX_MEM setting is not too large. + +NOTE: this is far from an exhaustive test of the JPEG software; some modules, +such as 1-pass color quantization, are not exercised at all. It's just a +quick test to give you some confidence that you haven't missed something +major. + + +INSTALLING THE SOFTWARE +======================= + +Once you're done with the above steps, you can install the software by +copying the executable files (cjpeg, djpeg, jpegtran, rdjpgcom, and wrjpgcom) +to wherever you normally install programs. On Unix systems, you'll also want +to put the man pages (cjpeg.1, djpeg.1, jpegtran.1, rdjpgcom.1, wrjpgcom.1) +in the man-page directory. The pre-fab makefiles don't support this step +since there's such a wide variety of installation procedures on different +systems. + +If you generated a Makefile with the "configure" script, you can just say + make install +to install the programs and their man pages into the standard places. +(You'll probably need to be root to do this.) We recommend first saying + make -n install +to see where configure thought the files should go. You may need to edit +the Makefile, particularly if your system's conventions for man page +filenames don't match what configure expects. + +If you want to install the IJG library itself, for use in compiling other +programs besides ours, then you need to put the four include files + jpeglib.h jerror.h jconfig.h jmorecfg.h +into your include-file directory, and put the library file libjpeg.a +(extension may vary depending on system) wherever library files go. +If you generated a Makefile with "configure", it will do what it thinks +is the right thing if you say + make install-lib + + +OPTIONAL STUFF +============== + +Progress monitor: + +If you like, you can #define PROGRESS_REPORT (in jconfig.h) to enable display +of percent-done progress reports. The routine provided in cdjpeg.c merely +prints percentages to stderr, but you can customize it to do something +fancier. + +Utah RLE file format support: + +We distribute the software with support for RLE image files (Utah Raster +Toolkit format) disabled, because the RLE support won't compile without the +Utah library. If you have URT version 3.1 or later, you can enable RLE +support as follows: + 1. #define RLE_SUPPORTED in jconfig.h. + 2. Add a -I option to CFLAGS in the Makefile for the directory + containing the URT .h files (typically the "include" + subdirectory of the URT distribution). + 3. Add -L... -lrle to LDLIBS in the Makefile, where ... specifies + the directory containing the URT "librle.a" file (typically the + "lib" subdirectory of the URT distribution). + +Support for 12-bit-deep pixel data: + +The JPEG standard allows either 8-bit or 12-bit data precision. (For color, +this means 8 or 12 bits per channel, of course.) If you need to work with +deeper than 8-bit data, you can compile the IJG code for 12-bit operation. +To do so: + 1. In jmorecfg.h, define BITS_IN_JSAMPLE as 12 rather than 8. + 2. In jconfig.h, undefine BMP_SUPPORTED, RLE_SUPPORTED, and TARGA_SUPPORTED, + because the code for those formats doesn't handle 12-bit data and won't + even compile. (The PPM code does work, as explained below. The GIF + code works too; it scales 8-bit GIF data to and from 12-bit depth + automatically.) + 3. Compile. Don't expect "make test" to pass, since the supplied test + files are for 8-bit data. + +Currently, 12-bit support does not work on 16-bit-int machines. + +Note that a 12-bit version will not read 8-bit JPEG files, nor vice versa; +so you'll want to keep around a regular 8-bit compilation as well. +(Run-time selection of data depth, to allow a single copy that does both, +is possible but would probably slow things down considerably; it's very low +on our to-do list.) + +The PPM reader (rdppm.c) can read 12-bit data from either text-format or +binary-format PPM and PGM files. Binary-format PPM/PGM files which have a +maxval greater than 255 are assumed to use 2 bytes per sample, LSB first +(little-endian order). As of early 1995, 2-byte binary format is not +officially supported by the PBMPLUS library, but it is expected that a +future release of PBMPLUS will support it. Note that the PPM reader will +read files of any maxval regardless of the BITS_IN_JSAMPLE setting; incoming +data is automatically rescaled to either maxval=255 or maxval=4095 as +appropriate for the cjpeg bit depth. + +The PPM writer (wrppm.c) will normally write 2-byte binary PPM or PGM +format, maxval 4095, when compiled with BITS_IN_JSAMPLE=12. Since this +format is not yet widely supported, you can disable it by compiling wrppm.c +with PPM_NORAWWORD defined; then the data is scaled down to 8 bits to make a +standard 1-byte/sample PPM or PGM file. (Yes, this means still another copy +of djpeg to keep around. But hopefully you won't need it for very long. +Poskanzer's supposed to get that new PBMPLUS release out Real Soon Now.) + +Of course, if you are working with 12-bit data, you probably have it stored +in some other, nonstandard format. In that case you'll probably want to +write your own I/O modules to read and write your format. + +Note that a 12-bit version of cjpeg always runs in "-optimize" mode, in +order to generate valid Huffman tables. This is necessary because our +default Huffman tables only cover 8-bit data. + +Removing code: + +If you need to make a smaller version of the JPEG software, some optional +functions can be removed at compile time. See the xxx_SUPPORTED #defines in +jconfig.h and jmorecfg.h. If at all possible, we recommend that you leave in +decoder support for all valid JPEG files, to ensure that you can read anyone's +output. Taking out support for image file formats that you don't use is the +most painless way to make the programs smaller. Another possibility is to +remove some of the DCT methods: in particular, the "IFAST" method may not be +enough faster than the others to be worth keeping on your machine. (If you +do remove ISLOW or IFAST, be sure to redefine JDCT_DEFAULT or JDCT_FASTEST +to a supported method, by adding a #define in jconfig.h.) + + +OPTIMIZATION +============ + +Unless you own a Cray, you'll probably be interested in making the JPEG +software go as fast as possible. This section covers some machine-dependent +optimizations you may want to try. We suggest that before trying any of +this, you first get the basic installation to pass the self-test step. +Repeat the self-test after any optimization to make sure that you haven't +broken anything. + +The integer DCT routines perform a lot of multiplications. These +multiplications must yield 32-bit results, but none of their input values +are more than 16 bits wide. On many machines, notably the 680x0 and 80x86 +CPUs, a 16x16=>32 bit multiply instruction is faster than a full 32x32=>32 +bit multiply. Unfortunately there is no portable way to specify such a +multiplication in C, but some compilers can generate one when you use the +right combination of casts. See the MULTIPLYxxx macro definitions in +jdct.h. If your compiler makes "int" be 32 bits and "short" be 16 bits, +defining SHORTxSHORT_32 is fairly likely to work. When experimenting with +alternate definitions, be sure to test not only whether the code still works +(use the self-test), but also whether it is actually faster --- on some +compilers, alternate definitions may compute the right answer, yet be slower +than the default. Timing cjpeg on a large PGM (grayscale) input file is the +best way to check this, as the DCT will be the largest fraction of the runtime +in that mode. (Note: some of the distributed compiler-specific jconfig files +already contain #define switches to select appropriate MULTIPLYxxx +definitions.) + +If your machine has sufficiently fast floating point hardware, you may find +that the float DCT method is faster than the integer DCT methods, even +after tweaking the integer multiply macros. In that case you may want to +make the float DCT be the default method. (The only objection to this is +that float DCT results may vary slightly across machines.) To do that, add +"#define JDCT_DEFAULT JDCT_FLOAT" to jconfig.h. Even if you don't change +the default, you should redefine JDCT_FASTEST, which is the method selected +by djpeg's -fast switch. Don't forget to update the documentation files +(usage.doc and/or cjpeg.1, djpeg.1) to agree with what you've done. + +If access to "short" arrays is slow on your machine, it may be a win to +define type JCOEF as int rather than short. This will cost a good deal of +memory though, particularly in some multi-pass modes, so don't do it unless +you have memory to burn and short is REALLY slow. + +If your compiler can compile function calls in-line, make sure the INLINE +macro in jmorecfg.h is defined as the keyword that marks a function +inline-able. Some compilers have a switch that tells the compiler to inline +any function it thinks is profitable (e.g., -finline-functions for gcc). +Enabling such a switch is likely to make the compiled code bigger but faster. + +In general, it's worth trying the maximum optimization level of your compiler, +and experimenting with any optional optimizations such as loop unrolling. +(Unfortunately, far too many compilers have optimizer bugs ... be prepared to +back off if the code fails self-test.) If you do any experimentation along +these lines, please report the optimal settings to jpeg-info@uunet.uu.net so +we can mention them in future releases. Be sure to specify your machine and +compiler version. + + +HINTS FOR SPECIFIC SYSTEMS +========================== + +We welcome reports on changes needed for systems not mentioned here. Submit +'em to jpeg-info@uunet.uu.net. Also, if configure or ckconfig.c is wrong +about how to configure the JPEG software for your system, please let us know. + + +Acorn RISC OS: + +(Thanks to Simon Middleton for these hints on compiling with Desktop C.) +After renaming the files according to Acorn conventions, take a copy of +makefile.ansi, change all occurrences of 'libjpeg.a' to 'libjpeg.o' and +change these definitions as indicated: + +CFLAGS= -throwback -IC: -Wn +LDLIBS=C:o.Stubs +SYSDEPMEM=jmemansi.o +LN=Link +AR=LibFile -c -o + +Also add a new line '.c.o:; $(cc) $< $(cflags) -c -o $@'. Remove the +lines '$(RM) libjpeg.o' and '$(AR2) libjpeg.o' and the 'jconfig.h' +dependency section. + +Copy jconfig.doc to jconfig.h. Edit jconfig.h to define TWO_FILE_COMMANDLINE +and CHAR_IS_UNSIGNED. + +Run the makefile using !AMU not !Make. If you want to use the 'clean' and +'test' makefile entries then you will have to fiddle with the syntax a bit +and rename the test files. + + +Amiga: + +SAS C 6.50 reportedly is too buggy to compile the IJG code properly. +A patch to update to 6.51 is available from SAS or AmiNet FTP sites. + +The supplied config files are set up to use jmemname.c as the memory +manager, with temporary files being created on the device named by +"JPEGTMP:". + + +Atari ST/STE/TT: + +Copy the project files makcjpeg.st, makdjpeg.st, maktjpeg.st, and makljpeg.st +to cjpeg.prj, djpeg.prj, jpegtran.prj, and libjpeg.prj respectively. The +project files should work as-is with Pure C. For Turbo C, change library +filenames "pc..." to "tc..." in each project file. Note that libjpeg.prj +selects jmemansi.c as the recommended memory manager. You'll probably want to +adjust the DEFAULT_MAX_MEM setting --- you want it to be a couple hundred K +less than your normal free memory. Put "#define DEFAULT_MAX_MEM nnnn" into +jconfig.h to do this. + +To use the 68881/68882 coprocessor for the floating point DCT, add the +compiler option "-8" to the project files and replace pcfltlib.lib with +pc881lib.lib in cjpeg.prj and djpeg.prj. Or if you don't have a +coprocessor, you may prefer to remove the float DCT code by undefining +DCT_FLOAT_SUPPORTED in jmorecfg.h (since without a coprocessor, the float +code will be too slow to be useful). In that case, you can delete +pcfltlib.lib from the project files. + +Note that you must make libjpeg.lib before making cjpeg.ttp, djpeg.ttp, +or jpegtran.ttp. You'll have to perform the self-test by hand. + +We haven't bothered to include project files for rdjpgcom and wrjpgcom. +Those source files should just be compiled by themselves; they don't +depend on the JPEG library. + +There is a bug in some older versions of the Turbo C library which causes the +space used by temporary files created with "tmpfile()" not to be freed after +an abnormal program exit. If you check your disk afterwards, you will find +cluster chains that are allocated but not used by a file. This should not +happen in cjpeg/djpeg/jpegtran, since we enable a signal catcher to explicitly +close temp files before exiting. But if you use the JPEG library with your +own code, be sure to supply a signal catcher, or else use a different +system-dependent memory manager. + + +Cray: + +Should you be so fortunate as to be running JPEG on a Cray YMP, there is a +compiler bug in old versions of Cray's Standard C (prior to 3.1). If you +still have an old compiler, you'll need to insert a line reading +"#pragma novector" just before the loop + for (i = 1; i <= (int) htbl->bits[l]; i++) + huffsize[p++] = (char) l; +in fix_huff_tbl (in V5beta1, line 204 of jchuff.c and line 176 of jdhuff.c). +[This bug may or may not still occur with the current IJG code, but it's +probably a dead issue anyway...] + + +HP-UX: + +If you have HP-UX 7.05 or later with the "software development" C compiler, +you should run the compiler in ANSI mode. If using the configure script, +say + ./configure CC='cc -Aa' +(or -Ae if you prefer). If configuring by hand, use makefile.ansi and add +"-Aa" to the CFLAGS line in the makefile. + +If you have a pre-7.05 system, or if you are using the non-ANSI C compiler +delivered with a minimum HP-UX system, then you must use makefile.unix +(and do NOT add -Aa); or just run configure without the CC option. + +On HP 9000 series 800 machines, the HP C compiler is buggy in revisions prior +to A.08.07. If you get complaints about "not a typedef name", you'll have to +use makefile.unix, or run configure without the CC option. + + +Macintosh, generic comments: + +The supplied user-interface files (cjpeg.c, djpeg.c, etc) are set up to +provide a Unix-style command line interface. You can use this interface on +the Mac by means of the ccommand() library routine provided by Metrowerks +CodeWarrior or Think C. This is only appropriate for testing the library, +however; to make a user-friendly equivalent of cjpeg/djpeg you'd really want +to develop a Mac-style user interface. There isn't a complete example +available at the moment, but there are some helpful starting points: +1. Sam Bushell's free "To JPEG" applet provides drag-and-drop conversion to +JPEG under System 7 and later. This only illustrates how to use the +compression half of the library, but it does a very nice job of that part. +The CodeWarrior source code is available from http://www.pobox.com/~jsam. +2. Jim Brunner prepared a Mac-style user interface for both compression and +decompression. Unfortunately, it hasn't been updated since IJG v4, and +the library's API has changed considerably since then. Still it may be of +some help, particularly as a guide to compiling the IJG code under Think C. +Jim's code is available from the Info-Mac archives, at sumex-aim.stanford.edu +or mirrors thereof; see file /info-mac/dev/src/jpeg-convert-c.hqx. + +jmemmac.c is the recommended memory manager back end for Macintosh. It uses +NewPtr/DisposePtr instead of malloc/free, and has a Mac-specific +implementation of jpeg_mem_available(). It also creates temporary files that +follow Mac conventions. (That part of the code relies on System-7-or-later OS +functions. See the comments in jmemmac.c if you need to run it on System 6.) +NOTE that USE_MAC_MEMMGR must be defined in jconfig.h to use jmemmac.c. + +You can also use jmemnobs.c, if you don't care about handling images larger +than available memory. If you use any memory manager back end other than +jmemmac.c, we recommend replacing "malloc" and "free" by "NewPtr" and +"DisposePtr", because Mac C libraries often have peculiar implementations of +malloc/free. (For instance, free() may not return the freed space to the +Mac Memory Manager. This is undesirable for the IJG code because jmemmgr.c +already clumps space requests.) + + +Macintosh, Metrowerks CodeWarrior: + +The Unix-command-line-style interface can be used by defining USE_CCOMMAND. +You'll also need to define TWO_FILE_COMMANDLINE to avoid stdin/stdout. +This means that when using the cjpeg/djpeg programs, you'll have to type the +input and output file names in the "Arguments" text-edit box, rather than +using the file radio buttons. (Perhaps USE_FDOPEN or USE_SETMODE would +eliminate the problem, but I haven't heard from anyone who's tried it.) + +On 680x0 Macs, Metrowerks defines type "double" as a 10-byte IEEE extended +float. jmemmgr.c won't like this: it wants sizeof(ALIGN_TYPE) to be a power +of 2. Add "#define ALIGN_TYPE long" to jconfig.h to eliminate the complaint. + +The supplied configuration file jconfig.mac can be used for your jconfig.h; +it includes all the recommended symbol definitions. If you have AppleScript +installed, you can run the supplied script makeproj.mac to create CodeWarrior +project files for the library and the testbed applications, then build the +library and applications. (Thanks to Dan Sears and Don Agro for this nifty +hack, which saves us from trying to maintain CodeWarrior project files as part +of the IJG distribution...) + + +Macintosh, Think C: + +The documentation in Jim Brunner's "JPEG Convert" source code (see above) +includes detailed build instructions for Think C; it's probably somewhat +out of date for the current release, but may be helpful. + +If you want to build the minimal command line version, proceed as follows. +You'll have to prepare project files for the programs; we don't include any +in the distribution since they are not text files. Use the file lists in +any of the supplied makefiles as a guide. Also add the ANSI and Unix C +libraries in a separate segment. You may need to divide the JPEG files into +more than one segment; we recommend dividing compression and decompression +modules. Define USE_CCOMMAND in jconfig.h so that the ccommand() routine is +called. You must also define TWO_FILE_COMMANDLINE because stdin/stdout +don't handle binary data correctly. + +On 680x0 Macs, Think C defines type "double" as a 12-byte IEEE extended float. +jmemmgr.c won't like this: it wants sizeof(ALIGN_TYPE) to be a power of 2. +Add "#define ALIGN_TYPE long" to jconfig.h to eliminate the complaint. + +jconfig.mac should work as a jconfig.h configuration file for Think C, +but the makeproj.mac AppleScript script is specific to CodeWarrior. Sorry. + + +MIPS R3000: + +MIPS's cc version 1.31 has a rather nasty optimization bug. Don't use -O +if you have that compiler version. (Use "cc -V" to check the version.) +Note that the R3000 chip is found in workstations from DEC and others. + + +MS-DOS, generic comments for 16-bit compilers: + +The IJG code is designed to work well in 80x86 "small" or "medium" memory +models (i.e., data pointers are 16 bits unless explicitly declared "far"; +code pointers can be either size). You may be able to use small model to +compile cjpeg or djpeg by itself, but you will probably have to use medium +model for any larger application. This won't make much difference in +performance. You *will* take a noticeable performance hit if you use a +large-data memory model, and you should avoid "huge" model if at all +possible. Be sure that NEED_FAR_POINTERS is defined in jconfig.h if you use +a small-data memory model; be sure it is NOT defined if you use a large-data +model. (The supplied makefiles and jconfig files for Borland and Microsoft C +compile in medium model and define NEED_FAR_POINTERS.) + +The DOS-specific memory manager, jmemdos.c, should be used if possible. +It needs some assembly-code routines which are in jmemdosa.asm; make sure +your makefile assembles that file and includes it in the library. If you +don't have a suitable assembler, you can get pre-assembled object files for +jmemdosa by FTP from ftp.uu.net:/graphics/jpeg/jdosaobj.zip. (DOS-oriented +distributions of the IJG source code often include these object files.) + +When using jmemdos.c, jconfig.h must define USE_MSDOS_MEMMGR and must set +MAX_ALLOC_CHUNK to less than 64K (65520L is a typical value). If your +C library's far-heap malloc() can't allocate blocks that large, reduce +MAX_ALLOC_CHUNK to whatever it can handle. + +If you can't use jmemdos.c for some reason --- for example, because you +don't have an assembler to assemble jmemdosa.asm --- you'll have to fall +back to jmemansi.c or jmemname.c. You'll probably still need to set +MAX_ALLOC_CHUNK in jconfig.h, because most DOS C libraries won't malloc() +more than 64K at a time. IMPORTANT: if you use jmemansi.c or jmemname.c, +you will have to compile in a large-data memory model in order to get the +right stdio library. Too bad. + +wrjpgcom needs to be compiled in large model, because it malloc()s a 64KB +work area to hold the comment text. If your C library's malloc can't +handle that, reduce MAX_COM_LENGTH as necessary in wrjpgcom.c. + +Most MS-DOS compilers treat stdin/stdout as text files, so you must use +two-file command line style. But if your compiler has either fdopen() or +setmode(), you can use one-file style if you like. To do this, define +USE_SETMODE or USE_FDOPEN so that stdin/stdout will be set to binary mode. +(USE_SETMODE seems to work with more DOS compilers than USE_FDOPEN.) You +should test that I/O through stdin/stdout produces the same results as I/O +to explicitly named files... the "make test" procedures in the supplied +makefiles do NOT use stdin/stdout. + + +MS-DOS, generic comments for 32-bit compilers: + +None of the above comments about memory models apply if you are using a +32-bit flat-memory-space environment, such as DJGPP or Watcom C. (And you +should use one if you have it, as performance will be much better than +8086-compatible code!) For flat-memory-space compilers, do NOT define +NEED_FAR_POINTERS, and do NOT use jmemdos.c. Use jmemnobs.c if the +environment supplies adequate virtual memory, otherwise use jmemansi.c or +jmemname.c. + +You'll still need to be careful about binary I/O through stdin/stdout. +See the last paragraph of the previous section. + + +MS-DOS, Borland C: + +Be sure to convert all the source files to DOS text format (CR/LF newlines). +Although Borland C will often work OK with unmodified Unix (LF newlines) +source files, sometimes it will give bogus compile errors. +"Illegal character '#'" is the most common such error. (This is true with +Borland C 3.1, but perhaps is fixed in newer releases.) + +If you want one-file command line style, just undefine TWO_FILE_COMMANDLINE. +jconfig.bcc already includes #define USE_SETMODE to make this work. +(fdopen does not work correctly.) + + +MS-DOS, Microsoft C: + +makefile.mc6 works with Microsoft C, DOS Visual C++, etc. It should only +be used if you want to build a 16-bit (small or medium memory model) program. + +If you want one-file command line style, just undefine TWO_FILE_COMMANDLINE. +jconfig.mc6 already includes #define USE_SETMODE to make this work. +(fdopen does not work correctly.) + +Note that this makefile assumes that the working copy of itself is called +"makefile". If you want to call it something else, say "makefile.mak", +be sure to adjust the dependency line that reads "$(RFILE) : makefile". +Otherwise the make will fail because it doesn't know how to create "makefile". +Worse, some releases of Microsoft's make utilities give an incorrect error +message in this situation. + +Old versions of MS C fail with an "out of macro expansion space" error +because they can't cope with the macro TRACEMS8 (defined in jerror.h). +If this happens to you, the easiest solution is to change TRACEMS8 to +expand to nothing. You'll lose the ability to dump out JPEG coefficient +tables with djpeg -debug -debug, but at least you can compile. + +Original MS C 6.0 is very buggy; it compiles incorrect code unless you turn +off optimization entirely (remove -O from CFLAGS). 6.00A is better, but it +still generates bad code if you enable loop optimizations (-Ol or -Ox). + +MS C 8.0 crashes when compiling jquant1.c with optimization switch /Oo ... +which is on by default. To work around this bug, compile that one file +with /Oo-. + + +Microsoft Windows (all versions), generic comments: + +Some Windows system include files define typedef boolean as "unsigned char". +The IJG code also defines typedef boolean, but we make it "int" by default. +This doesn't affect the IJG programs because we don't import those Windows +include files. But if you use the JPEG library in your own program, and some +of your program's files import one definition of boolean while some import the +other, you can get all sorts of mysterious problems. A good preventive step +is to make the IJG library use "unsigned char" for boolean. To do that, +add something like this to your jconfig.h file: + /* Define "boolean" as unsigned char, not int, per Windows custom */ + #ifndef __RPCNDR_H__ /* don't conflict if rpcndr.h already read */ + typedef unsigned char boolean; + #endif + #define HAVE_BOOLEAN /* prevent jmorecfg.h from redefining it */ +(This is already in jconfig.vc, by the way.) + +windef.h contains the declarations + #define far + #define FAR far +Since jmorecfg.h tries to define FAR as empty, you may get a compiler +warning if you include both jpeglib.h and windef.h (which windows.h +includes). To suppress the warning, you can put "#ifndef FAR"/"#endif" +around the line "#define FAR" in jmorecfg.h. + +When using the library in a Windows application, you will almost certainly +want to modify or replace the error handler module jerror.c, since our +default error handler does a couple of inappropriate things: + 1. it tries to write error and warning messages on stderr; + 2. in event of a fatal error, it exits by calling exit(). + +A simple stopgap solution for problem 1 is to replace the line + fprintf(stderr, "%s\n", buffer); +(in output_message in jerror.c) with + MessageBox(GetActiveWindow(),buffer,"JPEG Error",MB_OK|MB_ICONERROR); +It's highly recommended that you at least do that much, since otherwise +error messages will disappear into nowhere. (Beginning with IJG v6b, this +code is already present in jerror.c; just define USE_WINDOWS_MESSAGEBOX in +jconfig.h to enable it.) + +The proper solution for problem 2 is to return control to your calling +application after a library error. This can be done with the setjmp/longjmp +technique discussed in libjpeg.doc and illustrated in example.c. (NOTE: +some older Windows C compilers provide versions of setjmp/longjmp that +don't actually work under Windows. You may need to use the Windows system +functions Catch and Throw instead.) + +The recommended memory manager under Windows is jmemnobs.c; in other words, +let Windows do any virtual memory management needed. You should NOT use +jmemdos.c nor jmemdosa.asm under Windows. + +For Windows 3.1, we recommend compiling in medium or large memory model; +for newer Windows versions, use a 32-bit flat memory model. (See the MS-DOS +sections above for more info about memory models.) In the 16-bit memory +models only, you'll need to put + #define MAX_ALLOC_CHUNK 65520L /* Maximum request to malloc() */ +into jconfig.h to limit allocation chunks to 64Kb. (Without that, you'd +have to use huge memory model, which slows things down unnecessarily.) +jmemnobs.c works without modification in large or flat memory models, but to +use medium model, you need to modify its jpeg_get_large and jpeg_free_large +routines to allocate far memory. In any case, you might like to replace +its calls to malloc and free with direct calls on Windows memory allocation +functions. + +You may also want to modify jdatasrc.c and jdatadst.c to use Windows file +operations rather than fread/fwrite. This is only necessary if your C +compiler doesn't provide a competent implementation of C stdio functions. + +You might want to tweak the RGB_xxx macros in jmorecfg.h so that the library +will accept or deliver color pixels in BGR sample order, not RGB; BGR order +is usually more convenient under Windows. Note that this change will break +the sample applications cjpeg/djpeg, but the library itself works fine. + + +Many people want to convert the IJG library into a DLL. This is reasonably +straightforward, but watch out for the following: + + 1. Don't try to compile as a DLL in small or medium memory model; use +large model, or even better, 32-bit flat model. Many places in the IJG code +assume the address of a local variable is an ordinary (not FAR) pointer; +that isn't true in a medium-model DLL. + + 2. Microsoft C cannot pass file pointers between applications and DLLs. +(See Microsoft Knowledge Base, PSS ID Number Q50336.) So jdatasrc.c and +jdatadst.c don't work if you open a file in your application and then pass +the pointer to the DLL. One workaround is to make jdatasrc.c/jdatadst.c +part of your main application rather than part of the DLL. + + 3. You'll probably need to modify the macros GLOBAL() and EXTERN() to +attach suitable linkage keywords to the exported routine names. Similarly, +you'll want to modify METHODDEF() and JMETHOD() to ensure function pointers +are declared in a way that lets application routines be called back through +the function pointers. These macros are in jmorecfg.h. Typical definitions +for a 16-bit DLL are: + #define GLOBAL(type) type _far _pascal _loadds _export + #define EXTERN(type) extern type _far _pascal _loadds + #define METHODDEF(type) static type _far _pascal + #define JMETHOD(type,methodname,arglist) \ + type (_far _pascal *methodname) arglist +For a 32-bit DLL you may want something like + #define GLOBAL(type) __declspec(dllexport) type + #define EXTERN(type) extern __declspec(dllexport) type +Although not all the GLOBAL routines are actually intended to be called by +the application, the performance cost of making them all DLL entry points is +negligible. + +The unmodified IJG library presents a very C-specific application interface, +so the resulting DLL is only usable from C or C++ applications. There has +been some talk of writing wrapper code that would present a simpler interface +usable from other languages, such as Visual Basic. This is on our to-do list +but hasn't been very high priority --- any volunteers out there? + + +Microsoft Windows, Borland C: + +The provided jconfig.bcc should work OK in a 32-bit Windows environment, +but you'll need to tweak it in a 16-bit environment (you'd need to define +NEED_FAR_POINTERS and MAX_ALLOC_CHUNK). Beware that makefile.bcc will need +alteration if you want to use it for Windows --- in particular, you should +use jmemnobs.c not jmemdos.c under Windows. + +Borland C++ 4.5 fails with an internal compiler error when trying to compile +jdmerge.c in 32-bit mode. If enough people complain, perhaps Borland will fix +it. In the meantime, the simplest known workaround is to add a redundant +definition of the variable range_limit in h2v1_merged_upsample(), at the head +of the block that handles odd image width (about line 268 in v6 jdmerge.c): + /* If image width is odd, do the last output column separately */ + if (cinfo->output_width & 1) { + register JSAMPLE * range_limit = cinfo->sample_range_limit; /* ADD THIS */ + cb = GETJSAMPLE(*inptr1); +Pretty bizarre, especially since the very similar routine h2v2_merged_upsample +doesn't trigger the bug. +Recent reports suggest that this bug does not occur with "bcc32a" (the +Pentium-optimized version of the compiler). + +Another report from a user of Borland C 4.5 was that incorrect code (leading +to a color shift in processed images) was produced if any of the following +optimization switch combinations were used: + -Ot -Og + -Ot -Op + -Ot -Om +So try backing off on optimization if you see such a problem. (Are there +several different releases all numbered "4.5"??) + + +Microsoft Windows, Microsoft Visual C++: + +jconfig.vc should work OK with any Microsoft compiler for a 32-bit memory +model. makefile.vc is intended for command-line use. (If you are using +the Developer Studio environment, you may prefer the DevStudio project +files; see below.) + +Some users feel that it's easier to call the library from C++ code if you +force VC++ to treat the library as C++ code, which you can do by renaming +all the *.c files to *.cpp (and adjusting the makefile to match). This +avoids the need to put extern "C" { ... } around #include "jpeglib.h" in +your C++ application. + + +Microsoft Windows, Microsoft Developer Studio: + +We include makefiles that should work as project files in DevStudio 4.2 or +later. There is a library makefile that builds the IJG library as a static +Win32 library, and an application makefile that builds the sample applications +as Win32 console applications. (Even if you only want the library, we +recommend building the applications so that you can run the self-test.) + +To use: +1. Copy jconfig.vc to jconfig.h, makelib.ds to jpeg.mak, and + makeapps.ds to apps.mak. (Note that the renaming is critical!) +2. Click on the .mak files to construct project workspaces. + (If you are using DevStudio more recent than 4.2, you'll probably + get a message saying that the makefiles are being updated.) +3. Build the library project, then the applications project. +4. Move the application .exe files from `app`\Release to an + appropriate location on your path. +5. To perform the self-test, execute the command line + NMAKE /f makefile.vc test + + +OS/2, Borland C++: + +Watch out for optimization bugs in older Borland compilers; you may need +to back off the optimization switch settings. See the comments in +makefile.bcc. + + +SGI: + +On some SGI systems, you may need to set "AR2= ar -ts" in the Makefile. +If you are using configure, you can do this by saying + ./configure RANLIB='ar -ts' +This change is not needed on all SGIs. Use it only if the make fails at the +stage of linking the completed programs. + +On the MIPS R4000 architecture (Indy, etc.), the compiler option "-mips2" +reportedly speeds up the float DCT method substantially, enough to make it +faster than the default int method (but still slower than the fast int +method). If you use -mips2, you may want to alter the default DCT method to +be float. To do this, put "#define JDCT_DEFAULT JDCT_FLOAT" in jconfig.h. + + +VMS: + +On an Alpha/VMS system with MMS, be sure to use the "/Marco=Alpha=1" +qualifier with MMS when building the JPEG package. + +VAX/VMS v5.5-1 may have problems with the test step of the build procedure +reporting differences when it compares the original and test images. If the +error points to the last block of the files, it is most likely bogus and may +be safely ignored. It seems to be because the files are Stream_LF and +Backup/Compare has difficulty with the (presumably) null padded files. +This problem was not observed on VAX/VMS v6.1 or AXP/VMS v6.1. diff --git a/mk4/modimage/jpeg-6b/jcapimin.c b/mk4/modimage/jpeg-6b/jcapimin.c new file mode 100644 index 0000000..54fb8c5 --- /dev/null +++ b/mk4/modimage/jpeg-6b/jcapimin.c @@ -0,0 +1,280 @@ +/* + * jcapimin.c + * + * Copyright (C) 1994-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains application interface code for the compression half + * of the JPEG library. These are the "minimum" API routines that may be + * needed in either the normal full-compression case or the transcoding-only + * case. + * + * Most of the routines intended to be called directly by an application + * are in this file or in jcapistd.c. But also see jcparam.c for + * parameter-setup helper routines, jcomapi.c for routines shared by + * compression and decompression, and jctrans.c for the transcoding case. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * Initialization of a JPEG compression object. + * The error manager must already be set up (in case memory manager fails). + */ + +GLOBAL(void) +jpeg_CreateCompress (j_compress_ptr cinfo, int version, size_t structsize) +{ + int i; + + /* Guard against version mismatches between library and caller. */ + cinfo->mem = NULL; /* so jpeg_destroy knows mem mgr not called */ + if (version != JPEG_LIB_VERSION) + ERREXIT2(cinfo, JERR_BAD_LIB_VERSION, JPEG_LIB_VERSION, version); + if (structsize != SIZEOF(struct jpeg_compress_struct)) + ERREXIT2(cinfo, JERR_BAD_STRUCT_SIZE, + (int) SIZEOF(struct jpeg_compress_struct), (int) structsize); + + /* For debugging purposes, we zero the whole master structure. + * But the application has already set the err pointer, and may have set + * client_data, so we have to save and restore those fields. + * Note: if application hasn't set client_data, tools like Purify may + * complain here. + */ + { + struct jpeg_error_mgr * err = cinfo->err; + void * client_data = cinfo->client_data; /* ignore Purify complaint here */ + MEMZERO(cinfo, SIZEOF(struct jpeg_compress_struct)); + cinfo->err = err; + cinfo->client_data = client_data; + } + cinfo->is_decompressor = FALSE; + + /* Initialize a memory manager instance for this object */ + jinit_memory_mgr((j_common_ptr) cinfo); + + /* Zero out pointers to permanent structures. */ + cinfo->progress = NULL; + cinfo->dest = NULL; + + cinfo->comp_info = NULL; + + for (i = 0; i < NUM_QUANT_TBLS; i++) + cinfo->quant_tbl_ptrs[i] = NULL; + + for (i = 0; i < NUM_HUFF_TBLS; i++) { + cinfo->dc_huff_tbl_ptrs[i] = NULL; + cinfo->ac_huff_tbl_ptrs[i] = NULL; + } + + cinfo->script_space = NULL; + + cinfo->input_gamma = 1.0; /* in case application forgets */ + + /* OK, I'm ready */ + cinfo->global_state = CSTATE_START; +} + + +/* + * Destruction of a JPEG compression object + */ + +GLOBAL(void) +jpeg_destroy_compress (j_compress_ptr cinfo) +{ + jpeg_destroy((j_common_ptr) cinfo); /* use common routine */ +} + + +/* + * Abort processing of a JPEG compression operation, + * but don't destroy the object itself. + */ + +GLOBAL(void) +jpeg_abort_compress (j_compress_ptr cinfo) +{ + jpeg_abort((j_common_ptr) cinfo); /* use common routine */ +} + + +/* + * Forcibly suppress or un-suppress all quantization and Huffman tables. + * Marks all currently defined tables as already written (if suppress) + * or not written (if !suppress). This will control whether they get emitted + * by a subsequent jpeg_start_compress call. + * + * This routine is exported for use by applications that want to produce + * abbreviated JPEG datastreams. It logically belongs in jcparam.c, but + * since it is called by jpeg_start_compress, we put it here --- otherwise + * jcparam.o would be linked whether the application used it or not. + */ + +GLOBAL(void) +jpeg_suppress_tables (j_compress_ptr cinfo, boolean suppress) +{ + int i; + JQUANT_TBL * qtbl; + JHUFF_TBL * htbl; + + for (i = 0; i < NUM_QUANT_TBLS; i++) { + if ((qtbl = cinfo->quant_tbl_ptrs[i]) != NULL) + qtbl->sent_table = suppress; + } + + for (i = 0; i < NUM_HUFF_TBLS; i++) { + if ((htbl = cinfo->dc_huff_tbl_ptrs[i]) != NULL) + htbl->sent_table = suppress; + if ((htbl = cinfo->ac_huff_tbl_ptrs[i]) != NULL) + htbl->sent_table = suppress; + } +} + + +/* + * Finish JPEG compression. + * + * If a multipass operating mode was selected, this may do a great deal of + * work including most of the actual output. + */ + +GLOBAL(void) +jpeg_finish_compress (j_compress_ptr cinfo) +{ + JDIMENSION iMCU_row; + + if (cinfo->global_state == CSTATE_SCANNING || + cinfo->global_state == CSTATE_RAW_OK) { + /* Terminate first pass */ + if (cinfo->next_scanline < cinfo->image_height) + ERREXIT(cinfo, JERR_TOO_LITTLE_DATA); + (*cinfo->master->finish_pass) (cinfo); + } else if (cinfo->global_state != CSTATE_WRCOEFS) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + /* Perform any remaining passes */ + while (! cinfo->master->is_last_pass) { + (*cinfo->master->prepare_for_pass) (cinfo); + for (iMCU_row = 0; iMCU_row < cinfo->total_iMCU_rows; iMCU_row++) { + if (cinfo->progress != NULL) { + cinfo->progress->pass_counter = (long) iMCU_row; + cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows; + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + } + /* We bypass the main controller and invoke coef controller directly; + * all work is being done from the coefficient buffer. + */ + if (! (*cinfo->coef->compress_data) (cinfo, (JSAMPIMAGE) NULL)) + ERREXIT(cinfo, JERR_CANT_SUSPEND); + } + (*cinfo->master->finish_pass) (cinfo); + } + /* Write EOI, do final cleanup */ + (*cinfo->marker->write_file_trailer) (cinfo); + (*cinfo->dest->term_destination) (cinfo); + /* We can use jpeg_abort to release memory and reset global_state */ + jpeg_abort((j_common_ptr) cinfo); +} + + +/* + * Write a special marker. + * This is only recommended for writing COM or APPn markers. + * Must be called after jpeg_start_compress() and before + * first call to jpeg_write_scanlines() or jpeg_write_raw_data(). + */ + +GLOBAL(void) +jpeg_write_marker (j_compress_ptr cinfo, int marker, + const JOCTET *dataptr, unsigned int datalen) +{ + JMETHOD(void, write_marker_byte, (j_compress_ptr info, int val)); + + if (cinfo->next_scanline != 0 || + (cinfo->global_state != CSTATE_SCANNING && + cinfo->global_state != CSTATE_RAW_OK && + cinfo->global_state != CSTATE_WRCOEFS)) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + (*cinfo->marker->write_marker_header) (cinfo, marker, datalen); + write_marker_byte = cinfo->marker->write_marker_byte; /* copy for speed */ + while (datalen--) { + (*write_marker_byte) (cinfo, *dataptr); + dataptr++; + } +} + +/* Same, but piecemeal. */ + +GLOBAL(void) +jpeg_write_m_header (j_compress_ptr cinfo, int marker, unsigned int datalen) +{ + if (cinfo->next_scanline != 0 || + (cinfo->global_state != CSTATE_SCANNING && + cinfo->global_state != CSTATE_RAW_OK && + cinfo->global_state != CSTATE_WRCOEFS)) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + (*cinfo->marker->write_marker_header) (cinfo, marker, datalen); +} + +GLOBAL(void) +jpeg_write_m_byte (j_compress_ptr cinfo, int val) +{ + (*cinfo->marker->write_marker_byte) (cinfo, val); +} + + +/* + * Alternate compression function: just write an abbreviated table file. + * Before calling this, all parameters and a data destination must be set up. + * + * To produce a pair of files containing abbreviated tables and abbreviated + * image data, one would proceed as follows: + * + * initialize JPEG object + * set JPEG parameters + * set destination to table file + * jpeg_write_tables(cinfo); + * set destination to image file + * jpeg_start_compress(cinfo, FALSE); + * write data... + * jpeg_finish_compress(cinfo); + * + * jpeg_write_tables has the side effect of marking all tables written + * (same as jpeg_suppress_tables(..., TRUE)). Thus a subsequent start_compress + * will not re-emit the tables unless it is passed write_all_tables=TRUE. + */ + +GLOBAL(void) +jpeg_write_tables (j_compress_ptr cinfo) +{ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + /* (Re)initialize error mgr and destination modules */ + (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo); + (*cinfo->dest->init_destination) (cinfo); + /* Initialize the marker writer ... bit of a crock to do it here. */ + jinit_marker_writer(cinfo); + /* Write them tables! */ + (*cinfo->marker->write_tables_only) (cinfo); + /* And clean up. */ + (*cinfo->dest->term_destination) (cinfo); + /* + * In library releases up through v6a, we called jpeg_abort() here to free + * any working memory allocated by the destination manager and marker + * writer. Some applications had a problem with that: they allocated space + * of their own from the library memory manager, and didn't want it to go + * away during write_tables. So now we do nothing. This will cause a + * memory leak if an app calls write_tables repeatedly without doing a full + * compression cycle or otherwise resetting the JPEG object. However, that + * seems less bad than unexpectedly freeing memory in the normal case. + * An app that prefers the old behavior can call jpeg_abort for itself after + * each call to jpeg_write_tables(). + */ +} diff --git a/mk4/modimage/jpeg-6b/jcapistd.c b/mk4/modimage/jpeg-6b/jcapistd.c new file mode 100644 index 0000000..c0320b1 --- /dev/null +++ b/mk4/modimage/jpeg-6b/jcapistd.c @@ -0,0 +1,161 @@ +/* + * jcapistd.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains application interface code for the compression half + * of the JPEG library. These are the "standard" API routines that are + * used in the normal full-compression case. They are not used by a + * transcoding-only application. Note that if an application links in + * jpeg_start_compress, it will end up linking in the entire compressor. + * We thus must separate this file from jcapimin.c to avoid linking the + * whole compression library into a transcoder. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * Compression initialization. + * Before calling this, all parameters and a data destination must be set up. + * + * We require a write_all_tables parameter as a failsafe check when writing + * multiple datastreams from the same compression object. Since prior runs + * will have left all the tables marked sent_table=TRUE, a subsequent run + * would emit an abbreviated stream (no tables) by default. This may be what + * is wanted, but for safety's sake it should not be the default behavior: + * programmers should have to make a deliberate choice to emit abbreviated + * images. Therefore the documentation and examples should encourage people + * to pass write_all_tables=TRUE; then it will take active thought to do the + * wrong thing. + */ + +GLOBAL(void) +jpeg_start_compress (j_compress_ptr cinfo, boolean write_all_tables) +{ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + if (write_all_tables) + jpeg_suppress_tables(cinfo, FALSE); /* mark all tables to be written */ + + /* (Re)initialize error mgr and destination modules */ + (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo); + (*cinfo->dest->init_destination) (cinfo); + /* Perform master selection of active modules */ + jinit_compress_master(cinfo); + /* Set up for the first pass */ + (*cinfo->master->prepare_for_pass) (cinfo); + /* Ready for application to drive first pass through jpeg_write_scanlines + * or jpeg_write_raw_data. + */ + cinfo->next_scanline = 0; + cinfo->global_state = (cinfo->raw_data_in ? CSTATE_RAW_OK : CSTATE_SCANNING); +} + + +/* + * Write some scanlines of data to the JPEG compressor. + * + * The return value will be the number of lines actually written. + * This should be less than the supplied num_lines only in case that + * the data destination module has requested suspension of the compressor, + * or if more than image_height scanlines are passed in. + * + * Note: we warn about excess calls to jpeg_write_scanlines() since + * this likely signals an application programmer error. However, + * excess scanlines passed in the last valid call are *silently* ignored, + * so that the application need not adjust num_lines for end-of-image + * when using a multiple-scanline buffer. + */ + +GLOBAL(JDIMENSION) +jpeg_write_scanlines (j_compress_ptr cinfo, JSAMPARRAY scanlines, + JDIMENSION num_lines) +{ + JDIMENSION row_ctr, rows_left; + + if (cinfo->global_state != CSTATE_SCANNING) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + if (cinfo->next_scanline >= cinfo->image_height) + WARNMS(cinfo, JWRN_TOO_MUCH_DATA); + + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) { + cinfo->progress->pass_counter = (long) cinfo->next_scanline; + cinfo->progress->pass_limit = (long) cinfo->image_height; + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + } + + /* Give master control module another chance if this is first call to + * jpeg_write_scanlines. This lets output of the frame/scan headers be + * delayed so that application can write COM, etc, markers between + * jpeg_start_compress and jpeg_write_scanlines. + */ + if (cinfo->master->call_pass_startup) + (*cinfo->master->pass_startup) (cinfo); + + /* Ignore any extra scanlines at bottom of image. */ + rows_left = cinfo->image_height - cinfo->next_scanline; + if (num_lines > rows_left) + num_lines = rows_left; + + row_ctr = 0; + (*cinfo->main->process_data) (cinfo, scanlines, &row_ctr, num_lines); + cinfo->next_scanline += row_ctr; + return row_ctr; +} + + +/* + * Alternate entry point to write raw data. + * Processes exactly one iMCU row per call, unless suspended. + */ + +GLOBAL(JDIMENSION) +jpeg_write_raw_data (j_compress_ptr cinfo, JSAMPIMAGE data, + JDIMENSION num_lines) +{ + JDIMENSION lines_per_iMCU_row; + + if (cinfo->global_state != CSTATE_RAW_OK) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + if (cinfo->next_scanline >= cinfo->image_height) { + WARNMS(cinfo, JWRN_TOO_MUCH_DATA); + return 0; + } + + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) { + cinfo->progress->pass_counter = (long) cinfo->next_scanline; + cinfo->progress->pass_limit = (long) cinfo->image_height; + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + } + + /* Give master control module another chance if this is first call to + * jpeg_write_raw_data. This lets output of the frame/scan headers be + * delayed so that application can write COM, etc, markers between + * jpeg_start_compress and jpeg_write_raw_data. + */ + if (cinfo->master->call_pass_startup) + (*cinfo->master->pass_startup) (cinfo); + + /* Verify that at least one iMCU row has been passed. */ + lines_per_iMCU_row = cinfo->max_v_samp_factor * DCTSIZE; + if (num_lines < lines_per_iMCU_row) + ERREXIT(cinfo, JERR_BUFFER_SIZE); + + /* Directly compress the row. */ + if (! (*cinfo->coef->compress_data) (cinfo, data)) { + /* If compressor did not consume the whole row, suspend processing. */ + return 0; + } + + /* OK, we processed one iMCU row. */ + cinfo->next_scanline += lines_per_iMCU_row; + return lines_per_iMCU_row; +} diff --git a/mk4/modimage/jpeg-6b/jccoefct.c b/mk4/modimage/jpeg-6b/jccoefct.c new file mode 100644 index 0000000..1963ddb --- /dev/null +++ b/mk4/modimage/jpeg-6b/jccoefct.c @@ -0,0 +1,449 @@ +/* + * jccoefct.c + * + * Copyright (C) 1994-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the coefficient buffer controller for compression. + * This controller is the top level of the JPEG compressor proper. + * The coefficient buffer lies between forward-DCT and entropy encoding steps. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* We use a full-image coefficient buffer when doing Huffman optimization, + * and also for writing multiple-scan JPEG files. In all cases, the DCT + * step is run during the first pass, and subsequent passes need only read + * the buffered coefficients. + */ +#ifdef ENTROPY_OPT_SUPPORTED +#define FULL_COEF_BUFFER_SUPPORTED +#else +#ifdef C_MULTISCAN_FILES_SUPPORTED +#define FULL_COEF_BUFFER_SUPPORTED +#endif +#endif + + +/* Private buffer controller object */ + +typedef struct { + struct jpeg_c_coef_controller pub; /* public fields */ + + JDIMENSION iMCU_row_num; /* iMCU row # within image */ + JDIMENSION mcu_ctr; /* counts MCUs processed in current row */ + int MCU_vert_offset; /* counts MCU rows within iMCU row */ + int MCU_rows_per_iMCU_row; /* number of such rows needed */ + + /* For single-pass compression, it's sufficient to buffer just one MCU + * (although this may prove a bit slow in practice). We allocate a + * workspace of C_MAX_BLOCKS_IN_MCU coefficient blocks, and reuse it for each + * MCU constructed and sent. (On 80x86, the workspace is FAR even though + * it's not really very big; this is to keep the module interfaces unchanged + * when a large coefficient buffer is necessary.) + * In multi-pass modes, this array points to the current MCU's blocks + * within the virtual arrays. + */ + JBLOCKROW MCU_buffer[C_MAX_BLOCKS_IN_MCU]; + + /* In multi-pass modes, we need a virtual block array for each component. */ + jvirt_barray_ptr whole_image[MAX_COMPONENTS]; +} my_coef_controller; + +typedef my_coef_controller * my_coef_ptr; + + +/* Forward declarations */ +METHODDEF(boolean) compress_data + JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf)); +#ifdef FULL_COEF_BUFFER_SUPPORTED +METHODDEF(boolean) compress_first_pass + JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf)); +METHODDEF(boolean) compress_output + JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf)); +#endif + + +LOCAL(void) +start_iMCU_row (j_compress_ptr cinfo) +/* Reset within-iMCU-row counters for a new row */ +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + + /* In an interleaved scan, an MCU row is the same as an iMCU row. + * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows. + * But at the bottom of the image, process only what's left. + */ + if (cinfo->comps_in_scan > 1) { + coef->MCU_rows_per_iMCU_row = 1; + } else { + if (coef->iMCU_row_num < (cinfo->total_iMCU_rows-1)) + coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor; + else + coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height; + } + + coef->mcu_ctr = 0; + coef->MCU_vert_offset = 0; +} + + +/* + * Initialize for a processing pass. + */ + +METHODDEF(void) +start_pass_coef (j_compress_ptr cinfo, J_BUF_MODE pass_mode) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + + coef->iMCU_row_num = 0; + start_iMCU_row(cinfo); + + switch (pass_mode) { + case JBUF_PASS_THRU: + if (coef->whole_image[0] != NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + coef->pub.compress_data = compress_data; + break; +#ifdef FULL_COEF_BUFFER_SUPPORTED + case JBUF_SAVE_AND_PASS: + if (coef->whole_image[0] == NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + coef->pub.compress_data = compress_first_pass; + break; + case JBUF_CRANK_DEST: + if (coef->whole_image[0] == NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + coef->pub.compress_data = compress_output; + break; +#endif + default: + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + break; + } +} + + +/* + * Process some data in the single-pass case. + * We process the equivalent of one fully interleaved MCU row ("iMCU" row) + * per call, ie, v_samp_factor block rows for each component in the image. + * Returns TRUE if the iMCU row is completed, FALSE if suspended. + * + * NB: input_buf contains a plane for each component in image, + * which we index according to the component's SOF position. + */ + +METHODDEF(boolean) +compress_data (j_compress_ptr cinfo, JSAMPIMAGE input_buf) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + JDIMENSION MCU_col_num; /* index of current MCU within row */ + JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1; + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + int blkn, bi, ci, yindex, yoffset, blockcnt; + JDIMENSION ypos, xpos; + jpeg_component_info *compptr; + + /* Loop to write as much as one whole iMCU row */ + for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row; + yoffset++) { + for (MCU_col_num = coef->mcu_ctr; MCU_col_num <= last_MCU_col; + MCU_col_num++) { + /* Determine where data comes from in input_buf and do the DCT thing. + * Each call on forward_DCT processes a horizontal row of DCT blocks + * as wide as an MCU; we rely on having allocated the MCU_buffer[] blocks + * sequentially. Dummy blocks at the right or bottom edge are filled in + * specially. The data in them does not matter for image reconstruction, + * so we fill them with values that will encode to the smallest amount of + * data, viz: all zeroes in the AC entries, DC entries equal to previous + * block's DC value. (Thanks to Thomas Kinsman for this idea.) + */ + blkn = 0; + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + blockcnt = (MCU_col_num < last_MCU_col) ? compptr->MCU_width + : compptr->last_col_width; + xpos = MCU_col_num * compptr->MCU_sample_width; + ypos = yoffset * DCTSIZE; /* ypos == (yoffset+yindex) * DCTSIZE */ + for (yindex = 0; yindex < compptr->MCU_height; yindex++) { + if (coef->iMCU_row_num < last_iMCU_row || + yoffset+yindex < compptr->last_row_height) { + (*cinfo->fdct->forward_DCT) (cinfo, compptr, + input_buf[compptr->component_index], + coef->MCU_buffer[blkn], + ypos, xpos, (JDIMENSION) blockcnt); + if (blockcnt < compptr->MCU_width) { + /* Create some dummy blocks at the right edge of the image. */ + jzero_far((void FAR *) coef->MCU_buffer[blkn + blockcnt], + (compptr->MCU_width - blockcnt) * SIZEOF(JBLOCK)); + for (bi = blockcnt; bi < compptr->MCU_width; bi++) { + coef->MCU_buffer[blkn+bi][0][0] = coef->MCU_buffer[blkn+bi-1][0][0]; + } + } + } else { + /* Create a row of dummy blocks at the bottom of the image. */ + jzero_far((void FAR *) coef->MCU_buffer[blkn], + compptr->MCU_width * SIZEOF(JBLOCK)); + for (bi = 0; bi < compptr->MCU_width; bi++) { + coef->MCU_buffer[blkn+bi][0][0] = coef->MCU_buffer[blkn-1][0][0]; + } + } + blkn += compptr->MCU_width; + ypos += DCTSIZE; + } + } + /* Try to write the MCU. In event of a suspension failure, we will + * re-DCT the MCU on restart (a bit inefficient, could be fixed...) + */ + if (! (*cinfo->entropy->encode_mcu) (cinfo, coef->MCU_buffer)) { + /* Suspension forced; update state counters and exit */ + coef->MCU_vert_offset = yoffset; + coef->mcu_ctr = MCU_col_num; + return FALSE; + } + } + /* Completed an MCU row, but perhaps not an iMCU row */ + coef->mcu_ctr = 0; + } + /* Completed the iMCU row, advance counters for next one */ + coef->iMCU_row_num++; + start_iMCU_row(cinfo); + return TRUE; +} + + +#ifdef FULL_COEF_BUFFER_SUPPORTED + +/* + * Process some data in the first pass of a multi-pass case. + * We process the equivalent of one fully interleaved MCU row ("iMCU" row) + * per call, ie, v_samp_factor block rows for each component in the image. + * This amount of data is read from the source buffer, DCT'd and quantized, + * and saved into the virtual arrays. We also generate suitable dummy blocks + * as needed at the right and lower edges. (The dummy blocks are constructed + * in the virtual arrays, which have been padded appropriately.) This makes + * it possible for subsequent passes not to worry about real vs. dummy blocks. + * + * We must also emit the data to the entropy encoder. This is conveniently + * done by calling compress_output() after we've loaded the current strip + * of the virtual arrays. + * + * NB: input_buf contains a plane for each component in image. All + * components are DCT'd and loaded into the virtual arrays in this pass. + * However, it may be that only a subset of the components are emitted to + * the entropy encoder during this first pass; be careful about looking + * at the scan-dependent variables (MCU dimensions, etc). + */ + +METHODDEF(boolean) +compress_first_pass (j_compress_ptr cinfo, JSAMPIMAGE input_buf) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + JDIMENSION blocks_across, MCUs_across, MCUindex; + int bi, ci, h_samp_factor, block_row, block_rows, ndummy; + JCOEF lastDC; + jpeg_component_info *compptr; + JBLOCKARRAY buffer; + JBLOCKROW thisblockrow, lastblockrow; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Align the virtual buffer for this component. */ + buffer = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef->whole_image[ci], + coef->iMCU_row_num * compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, TRUE); + /* Count non-dummy DCT block rows in this iMCU row. */ + if (coef->iMCU_row_num < last_iMCU_row) + block_rows = compptr->v_samp_factor; + else { + /* NB: can't use last_row_height here, since may not be set! */ + block_rows = (int) (compptr->height_in_blocks % compptr->v_samp_factor); + if (block_rows == 0) block_rows = compptr->v_samp_factor; + } + blocks_across = compptr->width_in_blocks; + h_samp_factor = compptr->h_samp_factor; + /* Count number of dummy blocks to be added at the right margin. */ + ndummy = (int) (blocks_across % h_samp_factor); + if (ndummy > 0) + ndummy = h_samp_factor - ndummy; + /* Perform DCT for all non-dummy blocks in this iMCU row. Each call + * on forward_DCT processes a complete horizontal row of DCT blocks. + */ + for (block_row = 0; block_row < block_rows; block_row++) { + thisblockrow = buffer[block_row]; + (*cinfo->fdct->forward_DCT) (cinfo, compptr, + input_buf[ci], thisblockrow, + (JDIMENSION) (block_row * DCTSIZE), + (JDIMENSION) 0, blocks_across); + if (ndummy > 0) { + /* Create dummy blocks at the right edge of the image. */ + thisblockrow += blocks_across; /* => first dummy block */ + jzero_far((void FAR *) thisblockrow, ndummy * SIZEOF(JBLOCK)); + lastDC = thisblockrow[-1][0]; + for (bi = 0; bi < ndummy; bi++) { + thisblockrow[bi][0] = lastDC; + } + } + } + /* If at end of image, create dummy block rows as needed. + * The tricky part here is that within each MCU, we want the DC values + * of the dummy blocks to match the last real block's DC value. + * This squeezes a few more bytes out of the resulting file... + */ + if (coef->iMCU_row_num == last_iMCU_row) { + blocks_across += ndummy; /* include lower right corner */ + MCUs_across = blocks_across / h_samp_factor; + for (block_row = block_rows; block_row < compptr->v_samp_factor; + block_row++) { + thisblockrow = buffer[block_row]; + lastblockrow = buffer[block_row-1]; + jzero_far((void FAR *) thisblockrow, + (size_t) (blocks_across * SIZEOF(JBLOCK))); + for (MCUindex = 0; MCUindex < MCUs_across; MCUindex++) { + lastDC = lastblockrow[h_samp_factor-1][0]; + for (bi = 0; bi < h_samp_factor; bi++) { + thisblockrow[bi][0] = lastDC; + } + thisblockrow += h_samp_factor; /* advance to next MCU in row */ + lastblockrow += h_samp_factor; + } + } + } + } + /* NB: compress_output will increment iMCU_row_num if successful. + * A suspension return will result in redoing all the work above next time. + */ + + /* Emit data to the entropy encoder, sharing code with subsequent passes */ + return compress_output(cinfo, input_buf); +} + + +/* + * Process some data in subsequent passes of a multi-pass case. + * We process the equivalent of one fully interleaved MCU row ("iMCU" row) + * per call, ie, v_samp_factor block rows for each component in the scan. + * The data is obtained from the virtual arrays and fed to the entropy coder. + * Returns TRUE if the iMCU row is completed, FALSE if suspended. + * + * NB: input_buf is ignored; it is likely to be a NULL pointer. + */ + +METHODDEF(boolean) +compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + JDIMENSION MCU_col_num; /* index of current MCU within row */ + int blkn, ci, xindex, yindex, yoffset; + JDIMENSION start_col; + JBLOCKARRAY buffer[MAX_COMPS_IN_SCAN]; + JBLOCKROW buffer_ptr; + jpeg_component_info *compptr; + + /* Align the virtual buffers for the components used in this scan. + * NB: during first pass, this is safe only because the buffers will + * already be aligned properly, so jmemmgr.c won't need to do any I/O. + */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + buffer[ci] = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef->whole_image[compptr->component_index], + coef->iMCU_row_num * compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } + + /* Loop to process one whole iMCU row */ + for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row; + yoffset++) { + for (MCU_col_num = coef->mcu_ctr; MCU_col_num < cinfo->MCUs_per_row; + MCU_col_num++) { + /* Construct list of pointers to DCT blocks belonging to this MCU */ + blkn = 0; /* index of current DCT block within MCU */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + start_col = MCU_col_num * compptr->MCU_width; + for (yindex = 0; yindex < compptr->MCU_height; yindex++) { + buffer_ptr = buffer[ci][yindex+yoffset] + start_col; + for (xindex = 0; xindex < compptr->MCU_width; xindex++) { + coef->MCU_buffer[blkn++] = buffer_ptr++; + } + } + } + /* Try to write the MCU. */ + if (! (*cinfo->entropy->encode_mcu) (cinfo, coef->MCU_buffer)) { + /* Suspension forced; update state counters and exit */ + coef->MCU_vert_offset = yoffset; + coef->mcu_ctr = MCU_col_num; + return FALSE; + } + } + /* Completed an MCU row, but perhaps not an iMCU row */ + coef->mcu_ctr = 0; + } + /* Completed the iMCU row, advance counters for next one */ + coef->iMCU_row_num++; + start_iMCU_row(cinfo); + return TRUE; +} + +#endif /* FULL_COEF_BUFFER_SUPPORTED */ + + +/* + * Initialize coefficient buffer controller. + */ + +GLOBAL(void) +jinit_c_coef_controller (j_compress_ptr cinfo, boolean need_full_buffer) +{ + my_coef_ptr coef; + + coef = (my_coef_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_coef_controller)); + cinfo->coef = (struct jpeg_c_coef_controller *) coef; + coef->pub.start_pass = start_pass_coef; + + /* Create the coefficient buffer. */ + if (need_full_buffer) { +#ifdef FULL_COEF_BUFFER_SUPPORTED + /* Allocate a full-image virtual array for each component, */ + /* padded to a multiple of samp_factor DCT blocks in each direction. */ + int ci; + jpeg_component_info *compptr; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + coef->whole_image[ci] = (*cinfo->mem->request_virt_barray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, + (JDIMENSION) jround_up((long) compptr->width_in_blocks, + (long) compptr->h_samp_factor), + (JDIMENSION) jround_up((long) compptr->height_in_blocks, + (long) compptr->v_samp_factor), + (JDIMENSION) compptr->v_samp_factor); + } +#else + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); +#endif + } else { + /* We only need a single-MCU buffer. */ + JBLOCKROW buffer; + int i; + + buffer = (JBLOCKROW) + (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE, + C_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK)); + for (i = 0; i < C_MAX_BLOCKS_IN_MCU; i++) { + coef->MCU_buffer[i] = buffer + i; + } + coef->whole_image[0] = NULL; /* flag for no virtual arrays */ + } +} diff --git a/mk4/modimage/jpeg-6b/jccolor.c b/mk4/modimage/jpeg-6b/jccolor.c new file mode 100644 index 0000000..0a8a4b5 --- /dev/null +++ b/mk4/modimage/jpeg-6b/jccolor.c @@ -0,0 +1,459 @@ +/* + * jccolor.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains input colorspace conversion routines. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Private subobject */ + +typedef struct { + struct jpeg_color_converter pub; /* public fields */ + + /* Private state for RGB->YCC conversion */ + INT32 * rgb_ycc_tab; /* => table for RGB to YCbCr conversion */ +} my_color_converter; + +typedef my_color_converter * my_cconvert_ptr; + + +/**************** RGB -> YCbCr conversion: most common case **************/ + +/* + * YCbCr is defined per CCIR 601-1, except that Cb and Cr are + * normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5. + * The conversion equations to be implemented are therefore + * Y = 0.29900 * R + 0.58700 * G + 0.11400 * B + * Cb = -0.16874 * R - 0.33126 * G + 0.50000 * B + CENTERJSAMPLE + * Cr = 0.50000 * R - 0.41869 * G - 0.08131 * B + CENTERJSAMPLE + * (These numbers are derived from TIFF 6.0 section 21, dated 3-June-92.) + * Note: older versions of the IJG code used a zero offset of MAXJSAMPLE/2, + * rather than CENTERJSAMPLE, for Cb and Cr. This gave equal positive and + * negative swings for Cb/Cr, but meant that grayscale values (Cb=Cr=0) + * were not represented exactly. Now we sacrifice exact representation of + * maximum red and maximum blue in order to get exact grayscales. + * + * To avoid floating-point arithmetic, we represent the fractional constants + * as integers scaled up by 2^16 (about 4 digits precision); we have to divide + * the products by 2^16, with appropriate rounding, to get the correct answer. + * + * For even more speed, we avoid doing any multiplications in the inner loop + * by precalculating the constants times R,G,B for all possible values. + * For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table); + * for 12-bit samples it is still acceptable. It's not very reasonable for + * 16-bit samples, but if you want lossless storage you shouldn't be changing + * colorspace anyway. + * The CENTERJSAMPLE offsets and the rounding fudge-factor of 0.5 are included + * in the tables to save adding them separately in the inner loop. + */ + +#define SCALEBITS 16 /* speediest right-shift on some machines */ +#define CBCR_OFFSET ((INT32) CENTERJSAMPLE << SCALEBITS) +#define ONE_HALF ((INT32) 1 << (SCALEBITS-1)) +#define FIX(x) ((INT32) ((x) * (1L< Y section */ +#define G_Y_OFF (1*(MAXJSAMPLE+1)) /* offset to G => Y section */ +#define B_Y_OFF (2*(MAXJSAMPLE+1)) /* etc. */ +#define R_CB_OFF (3*(MAXJSAMPLE+1)) +#define G_CB_OFF (4*(MAXJSAMPLE+1)) +#define B_CB_OFF (5*(MAXJSAMPLE+1)) +#define R_CR_OFF B_CB_OFF /* B=>Cb, R=>Cr are the same */ +#define G_CR_OFF (6*(MAXJSAMPLE+1)) +#define B_CR_OFF (7*(MAXJSAMPLE+1)) +#define TABLE_SIZE (8*(MAXJSAMPLE+1)) + + +/* + * Initialize for RGB->YCC colorspace conversion. + */ + +METHODDEF(void) +rgb_ycc_start (j_compress_ptr cinfo) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + INT32 * rgb_ycc_tab; + INT32 i; + + /* Allocate and fill in the conversion tables. */ + cconvert->rgb_ycc_tab = rgb_ycc_tab = (INT32 *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (TABLE_SIZE * SIZEOF(INT32))); + + for (i = 0; i <= MAXJSAMPLE; i++) { + rgb_ycc_tab[i+R_Y_OFF] = FIX(0.29900) * i; + rgb_ycc_tab[i+G_Y_OFF] = FIX(0.58700) * i; + rgb_ycc_tab[i+B_Y_OFF] = FIX(0.11400) * i + ONE_HALF; + rgb_ycc_tab[i+R_CB_OFF] = (-FIX(0.16874)) * i; + rgb_ycc_tab[i+G_CB_OFF] = (-FIX(0.33126)) * i; + /* We use a rounding fudge-factor of 0.5-epsilon for Cb and Cr. + * This ensures that the maximum output will round to MAXJSAMPLE + * not MAXJSAMPLE+1, and thus that we don't have to range-limit. + */ + rgb_ycc_tab[i+B_CB_OFF] = FIX(0.50000) * i + CBCR_OFFSET + ONE_HALF-1; +/* B=>Cb and R=>Cr tables are the same + rgb_ycc_tab[i+R_CR_OFF] = FIX(0.50000) * i + CBCR_OFFSET + ONE_HALF-1; +*/ + rgb_ycc_tab[i+G_CR_OFF] = (-FIX(0.41869)) * i; + rgb_ycc_tab[i+B_CR_OFF] = (-FIX(0.08131)) * i; + } +} + + +/* + * Convert some rows of samples to the JPEG colorspace. + * + * Note that we change from the application's interleaved-pixel format + * to our internal noninterleaved, one-plane-per-component format. + * The input buffer is therefore three times as wide as the output buffer. + * + * A starting row offset is provided only for the output buffer. The caller + * can easily adjust the passed input_buf value to accommodate any row + * offset required on that side. + */ + +METHODDEF(void) +rgb_ycc_convert (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + register int r, g, b; + register INT32 * ctab = cconvert->rgb_ycc_tab; + register JSAMPROW inptr; + register JSAMPROW outptr0, outptr1, outptr2; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->image_width; + + while (--num_rows >= 0) { + inptr = *input_buf++; + outptr0 = output_buf[0][output_row]; + outptr1 = output_buf[1][output_row]; + outptr2 = output_buf[2][output_row]; + output_row++; + for (col = 0; col < num_cols; col++) { + r = GETJSAMPLE(inptr[RGB_RED]); + g = GETJSAMPLE(inptr[RGB_GREEN]); + b = GETJSAMPLE(inptr[RGB_BLUE]); + inptr += RGB_PIXELSIZE; + /* If the inputs are 0..MAXJSAMPLE, the outputs of these equations + * must be too; we do not need an explicit range-limiting operation. + * Hence the value being shifted is never negative, and we don't + * need the general RIGHT_SHIFT macro. + */ + /* Y */ + outptr0[col] = (JSAMPLE) + ((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF]) + >> SCALEBITS); + /* Cb */ + outptr1[col] = (JSAMPLE) + ((ctab[r+R_CB_OFF] + ctab[g+G_CB_OFF] + ctab[b+B_CB_OFF]) + >> SCALEBITS); + /* Cr */ + outptr2[col] = (JSAMPLE) + ((ctab[r+R_CR_OFF] + ctab[g+G_CR_OFF] + ctab[b+B_CR_OFF]) + >> SCALEBITS); + } + } +} + + +/**************** Cases other than RGB -> YCbCr **************/ + + +/* + * Convert some rows of samples to the JPEG colorspace. + * This version handles RGB->grayscale conversion, which is the same + * as the RGB->Y portion of RGB->YCbCr. + * We assume rgb_ycc_start has been called (we only use the Y tables). + */ + +METHODDEF(void) +rgb_gray_convert (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + register int r, g, b; + register INT32 * ctab = cconvert->rgb_ycc_tab; + register JSAMPROW inptr; + register JSAMPROW outptr; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->image_width; + + while (--num_rows >= 0) { + inptr = *input_buf++; + outptr = output_buf[0][output_row]; + output_row++; + for (col = 0; col < num_cols; col++) { + r = GETJSAMPLE(inptr[RGB_RED]); + g = GETJSAMPLE(inptr[RGB_GREEN]); + b = GETJSAMPLE(inptr[RGB_BLUE]); + inptr += RGB_PIXELSIZE; + /* Y */ + outptr[col] = (JSAMPLE) + ((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF]) + >> SCALEBITS); + } + } +} + + +/* + * Convert some rows of samples to the JPEG colorspace. + * This version handles Adobe-style CMYK->YCCK conversion, + * where we convert R=1-C, G=1-M, and B=1-Y to YCbCr using the same + * conversion as above, while passing K (black) unchanged. + * We assume rgb_ycc_start has been called. + */ + +METHODDEF(void) +cmyk_ycck_convert (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + register int r, g, b; + register INT32 * ctab = cconvert->rgb_ycc_tab; + register JSAMPROW inptr; + register JSAMPROW outptr0, outptr1, outptr2, outptr3; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->image_width; + + while (--num_rows >= 0) { + inptr = *input_buf++; + outptr0 = output_buf[0][output_row]; + outptr1 = output_buf[1][output_row]; + outptr2 = output_buf[2][output_row]; + outptr3 = output_buf[3][output_row]; + output_row++; + for (col = 0; col < num_cols; col++) { + r = MAXJSAMPLE - GETJSAMPLE(inptr[0]); + g = MAXJSAMPLE - GETJSAMPLE(inptr[1]); + b = MAXJSAMPLE - GETJSAMPLE(inptr[2]); + /* K passes through as-is */ + outptr3[col] = inptr[3]; /* don't need GETJSAMPLE here */ + inptr += 4; + /* If the inputs are 0..MAXJSAMPLE, the outputs of these equations + * must be too; we do not need an explicit range-limiting operation. + * Hence the value being shifted is never negative, and we don't + * need the general RIGHT_SHIFT macro. + */ + /* Y */ + outptr0[col] = (JSAMPLE) + ((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF]) + >> SCALEBITS); + /* Cb */ + outptr1[col] = (JSAMPLE) + ((ctab[r+R_CB_OFF] + ctab[g+G_CB_OFF] + ctab[b+B_CB_OFF]) + >> SCALEBITS); + /* Cr */ + outptr2[col] = (JSAMPLE) + ((ctab[r+R_CR_OFF] + ctab[g+G_CR_OFF] + ctab[b+B_CR_OFF]) + >> SCALEBITS); + } + } +} + + +/* + * Convert some rows of samples to the JPEG colorspace. + * This version handles grayscale output with no conversion. + * The source can be either plain grayscale or YCbCr (since Y == gray). + */ + +METHODDEF(void) +grayscale_convert (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows) +{ + register JSAMPROW inptr; + register JSAMPROW outptr; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->image_width; + int instride = cinfo->input_components; + + while (--num_rows >= 0) { + inptr = *input_buf++; + outptr = output_buf[0][output_row]; + output_row++; + for (col = 0; col < num_cols; col++) { + outptr[col] = inptr[0]; /* don't need GETJSAMPLE() here */ + inptr += instride; + } + } +} + + +/* + * Convert some rows of samples to the JPEG colorspace. + * This version handles multi-component colorspaces without conversion. + * We assume input_components == num_components. + */ + +METHODDEF(void) +null_convert (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows) +{ + register JSAMPROW inptr; + register JSAMPROW outptr; + register JDIMENSION col; + register int ci; + int nc = cinfo->num_components; + JDIMENSION num_cols = cinfo->image_width; + + while (--num_rows >= 0) { + /* It seems fastest to make a separate pass for each component. */ + for (ci = 0; ci < nc; ci++) { + inptr = *input_buf; + outptr = output_buf[ci][output_row]; + for (col = 0; col < num_cols; col++) { + outptr[col] = inptr[ci]; /* don't need GETJSAMPLE() here */ + inptr += nc; + } + } + input_buf++; + output_row++; + } +} + + +/* + * Empty method for start_pass. + */ + +METHODDEF(void) +null_method (j_compress_ptr cinfo) +{ + /* no work needed */ +} + + +/* + * Module initialization routine for input colorspace conversion. + */ + +GLOBAL(void) +jinit_color_converter (j_compress_ptr cinfo) +{ + my_cconvert_ptr cconvert; + + cconvert = (my_cconvert_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_color_converter)); + cinfo->cconvert = (struct jpeg_color_converter *) cconvert; + /* set start_pass to null method until we find out differently */ + cconvert->pub.start_pass = null_method; + + /* Make sure input_components agrees with in_color_space */ + switch (cinfo->in_color_space) { + case JCS_GRAYSCALE: + if (cinfo->input_components != 1) + ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE); + break; + + case JCS_RGB: +#if RGB_PIXELSIZE != 3 + if (cinfo->input_components != RGB_PIXELSIZE) + ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE); + break; +#endif /* else share code with YCbCr */ + + case JCS_YCbCr: + if (cinfo->input_components != 3) + ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE); + break; + + case JCS_CMYK: + case JCS_YCCK: + if (cinfo->input_components != 4) + ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE); + break; + + default: /* JCS_UNKNOWN can be anything */ + if (cinfo->input_components < 1) + ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE); + break; + } + + /* Check num_components, set conversion method based on requested space */ + switch (cinfo->jpeg_color_space) { + case JCS_GRAYSCALE: + if (cinfo->num_components != 1) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + if (cinfo->in_color_space == JCS_GRAYSCALE) + cconvert->pub.color_convert = grayscale_convert; + else if (cinfo->in_color_space == JCS_RGB) { + cconvert->pub.start_pass = rgb_ycc_start; + cconvert->pub.color_convert = rgb_gray_convert; + } else if (cinfo->in_color_space == JCS_YCbCr) + cconvert->pub.color_convert = grayscale_convert; + else + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + + case JCS_RGB: + if (cinfo->num_components != 3) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + if (cinfo->in_color_space == JCS_RGB && RGB_PIXELSIZE == 3) + cconvert->pub.color_convert = null_convert; + else + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + + case JCS_YCbCr: + if (cinfo->num_components != 3) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + if (cinfo->in_color_space == JCS_RGB) { + cconvert->pub.start_pass = rgb_ycc_start; + cconvert->pub.color_convert = rgb_ycc_convert; + } else if (cinfo->in_color_space == JCS_YCbCr) + cconvert->pub.color_convert = null_convert; + else + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + + case JCS_CMYK: + if (cinfo->num_components != 4) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + if (cinfo->in_color_space == JCS_CMYK) + cconvert->pub.color_convert = null_convert; + else + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + + case JCS_YCCK: + if (cinfo->num_components != 4) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + if (cinfo->in_color_space == JCS_CMYK) { + cconvert->pub.start_pass = rgb_ycc_start; + cconvert->pub.color_convert = cmyk_ycck_convert; + } else if (cinfo->in_color_space == JCS_YCCK) + cconvert->pub.color_convert = null_convert; + else + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + + default: /* allow null conversion of JCS_UNKNOWN */ + if (cinfo->jpeg_color_space != cinfo->in_color_space || + cinfo->num_components != cinfo->input_components) + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + cconvert->pub.color_convert = null_convert; + break; + } +} diff --git a/mk4/modimage/jpeg-6b/jcdctmgr.c b/mk4/modimage/jpeg-6b/jcdctmgr.c new file mode 100644 index 0000000..61fa79b --- /dev/null +++ b/mk4/modimage/jpeg-6b/jcdctmgr.c @@ -0,0 +1,387 @@ +/* + * jcdctmgr.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the forward-DCT management logic. + * This code selects a particular DCT implementation to be used, + * and it performs related housekeeping chores including coefficient + * quantization. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + + +/* Private subobject for this module */ + +typedef struct { + struct jpeg_forward_dct pub; /* public fields */ + + /* Pointer to the DCT routine actually in use */ + forward_DCT_method_ptr do_dct; + + /* The actual post-DCT divisors --- not identical to the quant table + * entries, because of scaling (especially for an unnormalized DCT). + * Each table is given in normal array order. + */ + DCTELEM * divisors[NUM_QUANT_TBLS]; + +#ifdef DCT_FLOAT_SUPPORTED + /* Same as above for the floating-point case. */ + float_DCT_method_ptr do_float_dct; + FAST_FLOAT * float_divisors[NUM_QUANT_TBLS]; +#endif +} my_fdct_controller; + +typedef my_fdct_controller * my_fdct_ptr; + + +/* + * Initialize for a processing pass. + * Verify that all referenced Q-tables are present, and set up + * the divisor table for each one. + * In the current implementation, DCT of all components is done during + * the first pass, even if only some components will be output in the + * first scan. Hence all components should be examined here. + */ + +METHODDEF(void) +start_pass_fdctmgr (j_compress_ptr cinfo) +{ + my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct; + int ci, qtblno, i; + jpeg_component_info *compptr; + JQUANT_TBL * qtbl; + DCTELEM * dtbl; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + qtblno = compptr->quant_tbl_no; + /* Make sure specified quantization table is present */ + if (qtblno < 0 || qtblno >= NUM_QUANT_TBLS || + cinfo->quant_tbl_ptrs[qtblno] == NULL) + ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, qtblno); + qtbl = cinfo->quant_tbl_ptrs[qtblno]; + /* Compute divisors for this quant table */ + /* We may do this more than once for same table, but it's not a big deal */ + switch (cinfo->dct_method) { +#ifdef DCT_ISLOW_SUPPORTED + case JDCT_ISLOW: + /* For LL&M IDCT method, divisors are equal to raw quantization + * coefficients multiplied by 8 (to counteract scaling). + */ + if (fdct->divisors[qtblno] == NULL) { + fdct->divisors[qtblno] = (DCTELEM *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + DCTSIZE2 * SIZEOF(DCTELEM)); + } + dtbl = fdct->divisors[qtblno]; + for (i = 0; i < DCTSIZE2; i++) { + dtbl[i] = ((DCTELEM) qtbl->quantval[i]) << 3; + } + break; +#endif +#ifdef DCT_IFAST_SUPPORTED + case JDCT_IFAST: + { + /* For AA&N IDCT method, divisors are equal to quantization + * coefficients scaled by scalefactor[row]*scalefactor[col], where + * scalefactor[0] = 1 + * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7 + * We apply a further scale factor of 8. + */ +#define CONST_BITS 14 + static const INT16 aanscales[DCTSIZE2] = { + /* precomputed values scaled up by 14 bits */ + 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, + 22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270, + 21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906, + 19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315, + 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, + 12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552, + 8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446, + 4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247 + }; + SHIFT_TEMPS + + if (fdct->divisors[qtblno] == NULL) { + fdct->divisors[qtblno] = (DCTELEM *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + DCTSIZE2 * SIZEOF(DCTELEM)); + } + dtbl = fdct->divisors[qtblno]; + for (i = 0; i < DCTSIZE2; i++) { + dtbl[i] = (DCTELEM) + DESCALE(MULTIPLY16V16((INT32) qtbl->quantval[i], + (INT32) aanscales[i]), + CONST_BITS-3); + } + } + break; +#endif +#ifdef DCT_FLOAT_SUPPORTED + case JDCT_FLOAT: + { + /* For float AA&N IDCT method, divisors are equal to quantization + * coefficients scaled by scalefactor[row]*scalefactor[col], where + * scalefactor[0] = 1 + * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7 + * We apply a further scale factor of 8. + * What's actually stored is 1/divisor so that the inner loop can + * use a multiplication rather than a division. + */ + FAST_FLOAT * fdtbl; + int row, col; + static const double aanscalefactor[DCTSIZE] = { + 1.0, 1.387039845, 1.306562965, 1.175875602, + 1.0, 0.785694958, 0.541196100, 0.275899379 + }; + + if (fdct->float_divisors[qtblno] == NULL) { + fdct->float_divisors[qtblno] = (FAST_FLOAT *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + DCTSIZE2 * SIZEOF(FAST_FLOAT)); + } + fdtbl = fdct->float_divisors[qtblno]; + i = 0; + for (row = 0; row < DCTSIZE; row++) { + for (col = 0; col < DCTSIZE; col++) { + fdtbl[i] = (FAST_FLOAT) + (1.0 / (((double) qtbl->quantval[i] * + aanscalefactor[row] * aanscalefactor[col] * 8.0))); + i++; + } + } + } + break; +#endif + default: + ERREXIT(cinfo, JERR_NOT_COMPILED); + break; + } + } +} + + +/* + * Perform forward DCT on one or more blocks of a component. + * + * The input samples are taken from the sample_data[] array starting at + * position start_row/start_col, and moving to the right for any additional + * blocks. The quantized coefficients are returned in coef_blocks[]. + */ + +METHODDEF(void) +forward_DCT (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY sample_data, JBLOCKROW coef_blocks, + JDIMENSION start_row, JDIMENSION start_col, + JDIMENSION num_blocks) +/* This version is used for integer DCT implementations. */ +{ + /* This routine is heavily used, so it's worth coding it tightly. */ + my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct; + forward_DCT_method_ptr do_dct = fdct->do_dct; + DCTELEM * divisors = fdct->divisors[compptr->quant_tbl_no]; + DCTELEM workspace[DCTSIZE2]; /* work area for FDCT subroutine */ + JDIMENSION bi; + + sample_data += start_row; /* fold in the vertical offset once */ + + for (bi = 0; bi < num_blocks; bi++, start_col += DCTSIZE) { + /* Load data into workspace, applying unsigned->signed conversion */ + { register DCTELEM *workspaceptr; + register JSAMPROW elemptr; + register int elemr; + + workspaceptr = workspace; + for (elemr = 0; elemr < DCTSIZE; elemr++) { + elemptr = sample_data[elemr] + start_col; +#if DCTSIZE == 8 /* unroll the inner loop */ + *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; +#else + { register int elemc; + for (elemc = DCTSIZE; elemc > 0; elemc--) { + *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + } + } +#endif + } + } + + /* Perform the DCT */ + (*do_dct) (workspace); + + /* Quantize/descale the coefficients, and store into coef_blocks[] */ + { register DCTELEM temp, qval; + register int i; + register JCOEFPTR output_ptr = coef_blocks[bi]; + + for (i = 0; i < DCTSIZE2; i++) { + qval = divisors[i]; + temp = workspace[i]; + /* Divide the coefficient value by qval, ensuring proper rounding. + * Since C does not specify the direction of rounding for negative + * quotients, we have to force the dividend positive for portability. + * + * In most files, at least half of the output values will be zero + * (at default quantization settings, more like three-quarters...) + * so we should ensure that this case is fast. On many machines, + * a comparison is enough cheaper than a divide to make a special test + * a win. Since both inputs will be nonnegative, we need only test + * for a < b to discover whether a/b is 0. + * If your machine's division is fast enough, define FAST_DIVIDE. + */ +#ifdef FAST_DIVIDE +#define DIVIDE_BY(a,b) a /= b +#else +#define DIVIDE_BY(a,b) if (a >= b) a /= b; else a = 0 +#endif + if (temp < 0) { + temp = -temp; + temp += qval>>1; /* for rounding */ + DIVIDE_BY(temp, qval); + temp = -temp; + } else { + temp += qval>>1; /* for rounding */ + DIVIDE_BY(temp, qval); + } + output_ptr[i] = (JCOEF) temp; + } + } + } +} + + +#ifdef DCT_FLOAT_SUPPORTED + +METHODDEF(void) +forward_DCT_float (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY sample_data, JBLOCKROW coef_blocks, + JDIMENSION start_row, JDIMENSION start_col, + JDIMENSION num_blocks) +/* This version is used for floating-point DCT implementations. */ +{ + /* This routine is heavily used, so it's worth coding it tightly. */ + my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct; + float_DCT_method_ptr do_dct = fdct->do_float_dct; + FAST_FLOAT * divisors = fdct->float_divisors[compptr->quant_tbl_no]; + FAST_FLOAT workspace[DCTSIZE2]; /* work area for FDCT subroutine */ + JDIMENSION bi; + + sample_data += start_row; /* fold in the vertical offset once */ + + for (bi = 0; bi < num_blocks; bi++, start_col += DCTSIZE) { + /* Load data into workspace, applying unsigned->signed conversion */ + { register FAST_FLOAT *workspaceptr; + register JSAMPROW elemptr; + register int elemr; + + workspaceptr = workspace; + for (elemr = 0; elemr < DCTSIZE; elemr++) { + elemptr = sample_data[elemr] + start_col; +#if DCTSIZE == 8 /* unroll the inner loop */ + *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); + *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); + *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); + *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); + *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); + *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); + *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); + *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); +#else + { register int elemc; + for (elemc = DCTSIZE; elemc > 0; elemc--) { + *workspaceptr++ = (FAST_FLOAT) + (GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); + } + } +#endif + } + } + + /* Perform the DCT */ + (*do_dct) (workspace); + + /* Quantize/descale the coefficients, and store into coef_blocks[] */ + { register FAST_FLOAT temp; + register int i; + register JCOEFPTR output_ptr = coef_blocks[bi]; + + for (i = 0; i < DCTSIZE2; i++) { + /* Apply the quantization and scaling factor */ + temp = workspace[i] * divisors[i]; + /* Round to nearest integer. + * Since C does not specify the direction of rounding for negative + * quotients, we have to force the dividend positive for portability. + * The maximum coefficient size is +-16K (for 12-bit data), so this + * code should work for either 16-bit or 32-bit ints. + */ + output_ptr[i] = (JCOEF) ((int) (temp + (FAST_FLOAT) 16384.5) - 16384); + } + } + } +} + +#endif /* DCT_FLOAT_SUPPORTED */ + + +/* + * Initialize FDCT manager. + */ + +GLOBAL(void) +jinit_forward_dct (j_compress_ptr cinfo) +{ + my_fdct_ptr fdct; + int i; + + fdct = (my_fdct_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_fdct_controller)); + cinfo->fdct = (struct jpeg_forward_dct *) fdct; + fdct->pub.start_pass = start_pass_fdctmgr; + + switch (cinfo->dct_method) { +#ifdef DCT_ISLOW_SUPPORTED + case JDCT_ISLOW: + fdct->pub.forward_DCT = forward_DCT; + fdct->do_dct = jpeg_fdct_islow; + break; +#endif +#ifdef DCT_IFAST_SUPPORTED + case JDCT_IFAST: + fdct->pub.forward_DCT = forward_DCT; + fdct->do_dct = jpeg_fdct_ifast; + break; +#endif +#ifdef DCT_FLOAT_SUPPORTED + case JDCT_FLOAT: + fdct->pub.forward_DCT = forward_DCT_float; + fdct->do_float_dct = jpeg_fdct_float; + break; +#endif + default: + ERREXIT(cinfo, JERR_NOT_COMPILED); + break; + } + + /* Mark divisor tables unallocated */ + for (i = 0; i < NUM_QUANT_TBLS; i++) { + fdct->divisors[i] = NULL; +#ifdef DCT_FLOAT_SUPPORTED + fdct->float_divisors[i] = NULL; +#endif + } +} diff --git a/mk4/modimage/jpeg-6b/jchuff.c b/mk4/modimage/jpeg-6b/jchuff.c new file mode 100644 index 0000000..f235250 --- /dev/null +++ b/mk4/modimage/jpeg-6b/jchuff.c @@ -0,0 +1,909 @@ +/* + * jchuff.c + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains Huffman entropy encoding routines. + * + * Much of the complexity here has to do with supporting output suspension. + * If the data destination module demands suspension, we want to be able to + * back up to the start of the current MCU. To do this, we copy state + * variables into local working storage, and update them back to the + * permanent JPEG objects only upon successful completion of an MCU. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jchuff.h" /* Declarations shared with jcphuff.c */ + + +/* Expanded entropy encoder object for Huffman encoding. + * + * The savable_state subrecord contains fields that change within an MCU, + * but must not be updated permanently until we complete the MCU. + */ + +typedef struct { + INT32 put_buffer; /* current bit-accumulation buffer */ + int put_bits; /* # of bits now in it */ + int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */ +} savable_state; + +/* This macro is to work around compilers with missing or broken + * structure assignment. You'll need to fix this code if you have + * such a compiler and you change MAX_COMPS_IN_SCAN. + */ + +#ifndef NO_STRUCT_ASSIGN +#define ASSIGN_STATE(dest,src) ((dest) = (src)) +#else +#if MAX_COMPS_IN_SCAN == 4 +#define ASSIGN_STATE(dest,src) \ + ((dest).put_buffer = (src).put_buffer, \ + (dest).put_bits = (src).put_bits, \ + (dest).last_dc_val[0] = (src).last_dc_val[0], \ + (dest).last_dc_val[1] = (src).last_dc_val[1], \ + (dest).last_dc_val[2] = (src).last_dc_val[2], \ + (dest).last_dc_val[3] = (src).last_dc_val[3]) +#endif +#endif + + +typedef struct { + struct jpeg_entropy_encoder pub; /* public fields */ + + savable_state saved; /* Bit buffer & DC state at start of MCU */ + + /* These fields are NOT loaded into local working state. */ + unsigned int restarts_to_go; /* MCUs left in this restart interval */ + int next_restart_num; /* next restart number to write (0-7) */ + + /* Pointers to derived tables (these workspaces have image lifespan) */ + c_derived_tbl * dc_derived_tbls[NUM_HUFF_TBLS]; + c_derived_tbl * ac_derived_tbls[NUM_HUFF_TBLS]; + +#ifdef ENTROPY_OPT_SUPPORTED /* Statistics tables for optimization */ + long * dc_count_ptrs[NUM_HUFF_TBLS]; + long * ac_count_ptrs[NUM_HUFF_TBLS]; +#endif +} huff_entropy_encoder; + +typedef huff_entropy_encoder * huff_entropy_ptr; + +/* Working state while writing an MCU. + * This struct contains all the fields that are needed by subroutines. + */ + +typedef struct { + JOCTET * next_output_byte; /* => next byte to write in buffer */ + size_t free_in_buffer; /* # of byte spaces remaining in buffer */ + savable_state cur; /* Current bit buffer & DC state */ + j_compress_ptr cinfo; /* dump_buffer needs access to this */ +} working_state; + + +/* Forward declarations */ +METHODDEF(boolean) encode_mcu_huff JPP((j_compress_ptr cinfo, + JBLOCKROW *MCU_data)); +METHODDEF(void) finish_pass_huff JPP((j_compress_ptr cinfo)); +#ifdef ENTROPY_OPT_SUPPORTED +METHODDEF(boolean) encode_mcu_gather JPP((j_compress_ptr cinfo, + JBLOCKROW *MCU_data)); +METHODDEF(void) finish_pass_gather JPP((j_compress_ptr cinfo)); +#endif + + +/* + * Initialize for a Huffman-compressed scan. + * If gather_statistics is TRUE, we do not output anything during the scan, + * just count the Huffman symbols used and generate Huffman code tables. + */ + +METHODDEF(void) +start_pass_huff (j_compress_ptr cinfo, boolean gather_statistics) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + int ci, dctbl, actbl; + jpeg_component_info * compptr; + + if (gather_statistics) { +#ifdef ENTROPY_OPT_SUPPORTED + entropy->pub.encode_mcu = encode_mcu_gather; + entropy->pub.finish_pass = finish_pass_gather; +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else { + entropy->pub.encode_mcu = encode_mcu_huff; + entropy->pub.finish_pass = finish_pass_huff; + } + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + dctbl = compptr->dc_tbl_no; + actbl = compptr->ac_tbl_no; + if (gather_statistics) { +#ifdef ENTROPY_OPT_SUPPORTED + /* Check for invalid table indexes */ + /* (make_c_derived_tbl does this in the other path) */ + if (dctbl < 0 || dctbl >= NUM_HUFF_TBLS) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, dctbl); + if (actbl < 0 || actbl >= NUM_HUFF_TBLS) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, actbl); + /* Allocate and zero the statistics tables */ + /* Note that jpeg_gen_optimal_table expects 257 entries in each table! */ + if (entropy->dc_count_ptrs[dctbl] == NULL) + entropy->dc_count_ptrs[dctbl] = (long *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + 257 * SIZEOF(long)); + MEMZERO(entropy->dc_count_ptrs[dctbl], 257 * SIZEOF(long)); + if (entropy->ac_count_ptrs[actbl] == NULL) + entropy->ac_count_ptrs[actbl] = (long *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + 257 * SIZEOF(long)); + MEMZERO(entropy->ac_count_ptrs[actbl], 257 * SIZEOF(long)); +#endif + } else { + /* Compute derived values for Huffman tables */ + /* We may do this more than once for a table, but it's not expensive */ + jpeg_make_c_derived_tbl(cinfo, TRUE, dctbl, + & entropy->dc_derived_tbls[dctbl]); + jpeg_make_c_derived_tbl(cinfo, FALSE, actbl, + & entropy->ac_derived_tbls[actbl]); + } + /* Initialize DC predictions to 0 */ + entropy->saved.last_dc_val[ci] = 0; + } + + /* Initialize bit buffer to empty */ + entropy->saved.put_buffer = 0; + entropy->saved.put_bits = 0; + + /* Initialize restart stuff */ + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num = 0; +} + + +/* + * Compute the derived values for a Huffman table. + * This routine also performs some validation checks on the table. + * + * Note this is also used by jcphuff.c. + */ + +GLOBAL(void) +jpeg_make_c_derived_tbl (j_compress_ptr cinfo, boolean isDC, int tblno, + c_derived_tbl ** pdtbl) +{ + JHUFF_TBL *htbl; + c_derived_tbl *dtbl; + int p, i, l, lastp, si, maxsymbol; + char huffsize[257]; + unsigned int huffcode[257]; + unsigned int code; + + /* Note that huffsize[] and huffcode[] are filled in code-length order, + * paralleling the order of the symbols themselves in htbl->huffval[]. + */ + + /* Find the input Huffman table */ + if (tblno < 0 || tblno >= NUM_HUFF_TBLS) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tblno); + htbl = + isDC ? cinfo->dc_huff_tbl_ptrs[tblno] : cinfo->ac_huff_tbl_ptrs[tblno]; + if (htbl == NULL) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tblno); + + /* Allocate a workspace if we haven't already done so. */ + if (*pdtbl == NULL) + *pdtbl = (c_derived_tbl *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(c_derived_tbl)); + dtbl = *pdtbl; + + /* Figure C.1: make table of Huffman code length for each symbol */ + + p = 0; + for (l = 1; l <= 16; l++) { + i = (int) htbl->bits[l]; + if (i < 0 || p + i > 256) /* protect against table overrun */ + ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); + while (i--) + huffsize[p++] = (char) l; + } + huffsize[p] = 0; + lastp = p; + + /* Figure C.2: generate the codes themselves */ + /* We also validate that the counts represent a legal Huffman code tree. */ + + code = 0; + si = huffsize[0]; + p = 0; + while (huffsize[p]) { + while (((int) huffsize[p]) == si) { + huffcode[p++] = code; + code++; + } + /* code is now 1 more than the last code used for codelength si; but + * it must still fit in si bits, since no code is allowed to be all ones. + */ + if (((INT32) code) >= (((INT32) 1) << si)) + ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); + code <<= 1; + si++; + } + + /* Figure C.3: generate encoding tables */ + /* These are code and size indexed by symbol value */ + + /* Set all codeless symbols to have code length 0; + * this lets us detect duplicate VAL entries here, and later + * allows emit_bits to detect any attempt to emit such symbols. + */ + MEMZERO(dtbl->ehufsi, SIZEOF(dtbl->ehufsi)); + + /* This is also a convenient place to check for out-of-range + * and duplicated VAL entries. We allow 0..255 for AC symbols + * but only 0..15 for DC. (We could constrain them further + * based on data depth and mode, but this seems enough.) + */ + maxsymbol = isDC ? 15 : 255; + + for (p = 0; p < lastp; p++) { + i = htbl->huffval[p]; + if (i < 0 || i > maxsymbol || dtbl->ehufsi[i]) + ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); + dtbl->ehufco[i] = huffcode[p]; + dtbl->ehufsi[i] = huffsize[p]; + } +} + + +/* Outputting bytes to the file */ + +/* Emit a byte, taking 'action' if must suspend. */ +#define emit_byte(state,val,action) \ + { *(state)->next_output_byte++ = (JOCTET) (val); \ + if (--(state)->free_in_buffer == 0) \ + if (! dump_buffer(state)) \ + { action; } } + + +LOCAL(boolean) +dump_buffer (working_state * state) +/* Empty the output buffer; return TRUE if successful, FALSE if must suspend */ +{ + struct jpeg_destination_mgr * dest = state->cinfo->dest; + + if (! (*dest->empty_output_buffer) (state->cinfo)) + return FALSE; + /* After a successful buffer dump, must reset buffer pointers */ + state->next_output_byte = dest->next_output_byte; + state->free_in_buffer = dest->free_in_buffer; + return TRUE; +} + + +/* Outputting bits to the file */ + +/* Only the right 24 bits of put_buffer are used; the valid bits are + * left-justified in this part. At most 16 bits can be passed to emit_bits + * in one call, and we never retain more than 7 bits in put_buffer + * between calls, so 24 bits are sufficient. + */ + +INLINE +LOCAL(boolean) +emit_bits (working_state * state, unsigned int code, int size) +/* Emit some bits; return TRUE if successful, FALSE if must suspend */ +{ + /* This routine is heavily used, so it's worth coding tightly. */ + register INT32 put_buffer = (INT32) code; + register int put_bits = state->cur.put_bits; + + /* if size is 0, caller used an invalid Huffman table entry */ + if (size == 0) + ERREXIT(state->cinfo, JERR_HUFF_MISSING_CODE); + + put_buffer &= (((INT32) 1)<cur.put_buffer; /* and merge with old buffer contents */ + + while (put_bits >= 8) { + int c = (int) ((put_buffer >> 16) & 0xFF); + + emit_byte(state, c, return FALSE); + if (c == 0xFF) { /* need to stuff a zero byte? */ + emit_byte(state, 0, return FALSE); + } + put_buffer <<= 8; + put_bits -= 8; + } + + state->cur.put_buffer = put_buffer; /* update state variables */ + state->cur.put_bits = put_bits; + + return TRUE; +} + + +LOCAL(boolean) +flush_bits (working_state * state) +{ + if (! emit_bits(state, 0x7F, 7)) /* fill any partial byte with ones */ + return FALSE; + state->cur.put_buffer = 0; /* and reset bit-buffer to empty */ + state->cur.put_bits = 0; + return TRUE; +} + + +/* Encode a single block's worth of coefficients */ + +LOCAL(boolean) +encode_one_block (working_state * state, JCOEFPTR block, int last_dc_val, + c_derived_tbl *dctbl, c_derived_tbl *actbl) +{ + register int temp, temp2; + register int nbits; + register int k, r, i; + + /* Encode the DC coefficient difference per section F.1.2.1 */ + + temp = temp2 = block[0] - last_dc_val; + + if (temp < 0) { + temp = -temp; /* temp is abs value of input */ + /* For a negative input, want temp2 = bitwise complement of abs(input) */ + /* This code assumes we are on a two's complement machine */ + temp2--; + } + + /* Find the number of bits needed for the magnitude of the coefficient */ + nbits = 0; + while (temp) { + nbits++; + temp >>= 1; + } + /* Check for out-of-range coefficient values. + * Since we're encoding a difference, the range limit is twice as much. + */ + if (nbits > MAX_COEF_BITS+1) + ERREXIT(state->cinfo, JERR_BAD_DCT_COEF); + + /* Emit the Huffman-coded symbol for the number of bits */ + if (! emit_bits(state, dctbl->ehufco[nbits], dctbl->ehufsi[nbits])) + return FALSE; + + /* Emit that number of bits of the value, if positive, */ + /* or the complement of its magnitude, if negative. */ + if (nbits) /* emit_bits rejects calls with size 0 */ + if (! emit_bits(state, (unsigned int) temp2, nbits)) + return FALSE; + + /* Encode the AC coefficients per section F.1.2.2 */ + + r = 0; /* r = run length of zeros */ + + for (k = 1; k < DCTSIZE2; k++) { + if ((temp = block[jpeg_natural_order[k]]) == 0) { + r++; + } else { + /* if run length > 15, must emit special run-length-16 codes (0xF0) */ + while (r > 15) { + if (! emit_bits(state, actbl->ehufco[0xF0], actbl->ehufsi[0xF0])) + return FALSE; + r -= 16; + } + + temp2 = temp; + if (temp < 0) { + temp = -temp; /* temp is abs value of input */ + /* This code assumes we are on a two's complement machine */ + temp2--; + } + + /* Find the number of bits needed for the magnitude of the coefficient */ + nbits = 1; /* there must be at least one 1 bit */ + while ((temp >>= 1)) + nbits++; + /* Check for out-of-range coefficient values */ + if (nbits > MAX_COEF_BITS) + ERREXIT(state->cinfo, JERR_BAD_DCT_COEF); + + /* Emit Huffman symbol for run length / number of bits */ + i = (r << 4) + nbits; + if (! emit_bits(state, actbl->ehufco[i], actbl->ehufsi[i])) + return FALSE; + + /* Emit that number of bits of the value, if positive, */ + /* or the complement of its magnitude, if negative. */ + if (! emit_bits(state, (unsigned int) temp2, nbits)) + return FALSE; + + r = 0; + } + } + + /* If the last coef(s) were zero, emit an end-of-block code */ + if (r > 0) + if (! emit_bits(state, actbl->ehufco[0], actbl->ehufsi[0])) + return FALSE; + + return TRUE; +} + + +/* + * Emit a restart marker & resynchronize predictions. + */ + +LOCAL(boolean) +emit_restart (working_state * state, int restart_num) +{ + int ci; + + if (! flush_bits(state)) + return FALSE; + + emit_byte(state, 0xFF, return FALSE); + emit_byte(state, JPEG_RST0 + restart_num, return FALSE); + + /* Re-initialize DC predictions to 0 */ + for (ci = 0; ci < state->cinfo->comps_in_scan; ci++) + state->cur.last_dc_val[ci] = 0; + + /* The restart counter is not updated until we successfully write the MCU. */ + + return TRUE; +} + + +/* + * Encode and output one MCU's worth of Huffman-compressed coefficients. + */ + +METHODDEF(boolean) +encode_mcu_huff (j_compress_ptr cinfo, JBLOCKROW *MCU_data) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + working_state state; + int blkn, ci; + jpeg_component_info * compptr; + + /* Load up working state */ + state.next_output_byte = cinfo->dest->next_output_byte; + state.free_in_buffer = cinfo->dest->free_in_buffer; + ASSIGN_STATE(state.cur, entropy->saved); + state.cinfo = cinfo; + + /* Emit restart marker if needed */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + if (! emit_restart(&state, entropy->next_restart_num)) + return FALSE; + } + + /* Encode the MCU data blocks */ + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + ci = cinfo->MCU_membership[blkn]; + compptr = cinfo->cur_comp_info[ci]; + if (! encode_one_block(&state, + MCU_data[blkn][0], state.cur.last_dc_val[ci], + entropy->dc_derived_tbls[compptr->dc_tbl_no], + entropy->ac_derived_tbls[compptr->ac_tbl_no])) + return FALSE; + /* Update last_dc_val */ + state.cur.last_dc_val[ci] = MCU_data[blkn][0][0]; + } + + /* Completed MCU, so update state */ + cinfo->dest->next_output_byte = state.next_output_byte; + cinfo->dest->free_in_buffer = state.free_in_buffer; + ASSIGN_STATE(entropy->saved, state.cur); + + /* Update restart-interval state too */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num++; + entropy->next_restart_num &= 7; + } + entropy->restarts_to_go--; + } + + return TRUE; +} + + +/* + * Finish up at the end of a Huffman-compressed scan. + */ + +METHODDEF(void) +finish_pass_huff (j_compress_ptr cinfo) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + working_state state; + + /* Load up working state ... flush_bits needs it */ + state.next_output_byte = cinfo->dest->next_output_byte; + state.free_in_buffer = cinfo->dest->free_in_buffer; + ASSIGN_STATE(state.cur, entropy->saved); + state.cinfo = cinfo; + + /* Flush out the last data */ + if (! flush_bits(&state)) + ERREXIT(cinfo, JERR_CANT_SUSPEND); + + /* Update state */ + cinfo->dest->next_output_byte = state.next_output_byte; + cinfo->dest->free_in_buffer = state.free_in_buffer; + ASSIGN_STATE(entropy->saved, state.cur); +} + + +/* + * Huffman coding optimization. + * + * We first scan the supplied data and count the number of uses of each symbol + * that is to be Huffman-coded. (This process MUST agree with the code above.) + * Then we build a Huffman coding tree for the observed counts. + * Symbols which are not needed at all for the particular image are not + * assigned any code, which saves space in the DHT marker as well as in + * the compressed data. + */ + +#ifdef ENTROPY_OPT_SUPPORTED + + +/* Process a single block's worth of coefficients */ + +LOCAL(void) +htest_one_block (j_compress_ptr cinfo, JCOEFPTR block, int last_dc_val, + long dc_counts[], long ac_counts[]) +{ + register int temp; + register int nbits; + register int k, r; + + /* Encode the DC coefficient difference per section F.1.2.1 */ + + temp = block[0] - last_dc_val; + if (temp < 0) + temp = -temp; + + /* Find the number of bits needed for the magnitude of the coefficient */ + nbits = 0; + while (temp) { + nbits++; + temp >>= 1; + } + /* Check for out-of-range coefficient values. + * Since we're encoding a difference, the range limit is twice as much. + */ + if (nbits > MAX_COEF_BITS+1) + ERREXIT(cinfo, JERR_BAD_DCT_COEF); + + /* Count the Huffman symbol for the number of bits */ + dc_counts[nbits]++; + + /* Encode the AC coefficients per section F.1.2.2 */ + + r = 0; /* r = run length of zeros */ + + for (k = 1; k < DCTSIZE2; k++) { + if ((temp = block[jpeg_natural_order[k]]) == 0) { + r++; + } else { + /* if run length > 15, must emit special run-length-16 codes (0xF0) */ + while (r > 15) { + ac_counts[0xF0]++; + r -= 16; + } + + /* Find the number of bits needed for the magnitude of the coefficient */ + if (temp < 0) + temp = -temp; + + /* Find the number of bits needed for the magnitude of the coefficient */ + nbits = 1; /* there must be at least one 1 bit */ + while ((temp >>= 1)) + nbits++; + /* Check for out-of-range coefficient values */ + if (nbits > MAX_COEF_BITS) + ERREXIT(cinfo, JERR_BAD_DCT_COEF); + + /* Count Huffman symbol for run length / number of bits */ + ac_counts[(r << 4) + nbits]++; + + r = 0; + } + } + + /* If the last coef(s) were zero, emit an end-of-block code */ + if (r > 0) + ac_counts[0]++; +} + + +/* + * Trial-encode one MCU's worth of Huffman-compressed coefficients. + * No data is actually output, so no suspension return is possible. + */ + +METHODDEF(boolean) +encode_mcu_gather (j_compress_ptr cinfo, JBLOCKROW *MCU_data) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + int blkn, ci; + jpeg_component_info * compptr; + + /* Take care of restart intervals if needed */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + /* Re-initialize DC predictions to 0 */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) + entropy->saved.last_dc_val[ci] = 0; + /* Update restart state */ + entropy->restarts_to_go = cinfo->restart_interval; + } + entropy->restarts_to_go--; + } + + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + ci = cinfo->MCU_membership[blkn]; + compptr = cinfo->cur_comp_info[ci]; + htest_one_block(cinfo, MCU_data[blkn][0], entropy->saved.last_dc_val[ci], + entropy->dc_count_ptrs[compptr->dc_tbl_no], + entropy->ac_count_ptrs[compptr->ac_tbl_no]); + entropy->saved.last_dc_val[ci] = MCU_data[blkn][0][0]; + } + + return TRUE; +} + + +/* + * Generate the best Huffman code table for the given counts, fill htbl. + * Note this is also used by jcphuff.c. + * + * The JPEG standard requires that no symbol be assigned a codeword of all + * one bits (so that padding bits added at the end of a compressed segment + * can't look like a valid code). Because of the canonical ordering of + * codewords, this just means that there must be an unused slot in the + * longest codeword length category. Section K.2 of the JPEG spec suggests + * reserving such a slot by pretending that symbol 256 is a valid symbol + * with count 1. In theory that's not optimal; giving it count zero but + * including it in the symbol set anyway should give a better Huffman code. + * But the theoretically better code actually seems to come out worse in + * practice, because it produces more all-ones bytes (which incur stuffed + * zero bytes in the final file). In any case the difference is tiny. + * + * The JPEG standard requires Huffman codes to be no more than 16 bits long. + * If some symbols have a very small but nonzero probability, the Huffman tree + * must be adjusted to meet the code length restriction. We currently use + * the adjustment method suggested in JPEG section K.2. This method is *not* + * optimal; it may not choose the best possible limited-length code. But + * typically only very-low-frequency symbols will be given less-than-optimal + * lengths, so the code is almost optimal. Experimental comparisons against + * an optimal limited-length-code algorithm indicate that the difference is + * microscopic --- usually less than a hundredth of a percent of total size. + * So the extra complexity of an optimal algorithm doesn't seem worthwhile. + */ + +GLOBAL(void) +jpeg_gen_optimal_table (j_compress_ptr cinfo, JHUFF_TBL * htbl, long freq[]) +{ +#define MAX_CLEN 32 /* assumed maximum initial code length */ + UINT8 bits[MAX_CLEN+1]; /* bits[k] = # of symbols with code length k */ + int codesize[257]; /* codesize[k] = code length of symbol k */ + int others[257]; /* next symbol in current branch of tree */ + int c1, c2; + int p, i, j; + long v; + + /* This algorithm is explained in section K.2 of the JPEG standard */ + + MEMZERO(bits, SIZEOF(bits)); + MEMZERO(codesize, SIZEOF(codesize)); + for (i = 0; i < 257; i++) + others[i] = -1; /* init links to empty */ + + freq[256] = 1; /* make sure 256 has a nonzero count */ + /* Including the pseudo-symbol 256 in the Huffman procedure guarantees + * that no real symbol is given code-value of all ones, because 256 + * will be placed last in the largest codeword category. + */ + + /* Huffman's basic algorithm to assign optimal code lengths to symbols */ + + for (;;) { + /* Find the smallest nonzero frequency, set c1 = its symbol */ + /* In case of ties, take the larger symbol number */ + c1 = -1; + v = 1000000000L; + for (i = 0; i <= 256; i++) { + if (freq[i] && freq[i] <= v) { + v = freq[i]; + c1 = i; + } + } + + /* Find the next smallest nonzero frequency, set c2 = its symbol */ + /* In case of ties, take the larger symbol number */ + c2 = -1; + v = 1000000000L; + for (i = 0; i <= 256; i++) { + if (freq[i] && freq[i] <= v && i != c1) { + v = freq[i]; + c2 = i; + } + } + + /* Done if we've merged everything into one frequency */ + if (c2 < 0) + break; + + /* Else merge the two counts/trees */ + freq[c1] += freq[c2]; + freq[c2] = 0; + + /* Increment the codesize of everything in c1's tree branch */ + codesize[c1]++; + while (others[c1] >= 0) { + c1 = others[c1]; + codesize[c1]++; + } + + others[c1] = c2; /* chain c2 onto c1's tree branch */ + + /* Increment the codesize of everything in c2's tree branch */ + codesize[c2]++; + while (others[c2] >= 0) { + c2 = others[c2]; + codesize[c2]++; + } + } + + /* Now count the number of symbols of each code length */ + for (i = 0; i <= 256; i++) { + if (codesize[i]) { + /* The JPEG standard seems to think that this can't happen, */ + /* but I'm paranoid... */ + if (codesize[i] > MAX_CLEN) + ERREXIT(cinfo, JERR_HUFF_CLEN_OVERFLOW); + + bits[codesize[i]]++; + } + } + + /* JPEG doesn't allow symbols with code lengths over 16 bits, so if the pure + * Huffman procedure assigned any such lengths, we must adjust the coding. + * Here is what the JPEG spec says about how this next bit works: + * Since symbols are paired for the longest Huffman code, the symbols are + * removed from this length category two at a time. The prefix for the pair + * (which is one bit shorter) is allocated to one of the pair; then, + * skipping the BITS entry for that prefix length, a code word from the next + * shortest nonzero BITS entry is converted into a prefix for two code words + * one bit longer. + */ + + for (i = MAX_CLEN; i > 16; i--) { + while (bits[i] > 0) { + j = i - 2; /* find length of new prefix to be used */ + while (bits[j] == 0) + j--; + + bits[i] -= 2; /* remove two symbols */ + bits[i-1]++; /* one goes in this length */ + bits[j+1] += 2; /* two new symbols in this length */ + bits[j]--; /* symbol of this length is now a prefix */ + } + } + + /* Remove the count for the pseudo-symbol 256 from the largest codelength */ + while (bits[i] == 0) /* find largest codelength still in use */ + i--; + bits[i]--; + + /* Return final symbol counts (only for lengths 0..16) */ + MEMCOPY(htbl->bits, bits, SIZEOF(htbl->bits)); + + /* Return a list of the symbols sorted by code length */ + /* It's not real clear to me why we don't need to consider the codelength + * changes made above, but the JPEG spec seems to think this works. + */ + p = 0; + for (i = 1; i <= MAX_CLEN; i++) { + for (j = 0; j <= 255; j++) { + if (codesize[j] == i) { + htbl->huffval[p] = (UINT8) j; + p++; + } + } + } + + /* Set sent_table FALSE so updated table will be written to JPEG file. */ + htbl->sent_table = FALSE; +} + + +/* + * Finish up a statistics-gathering pass and create the new Huffman tables. + */ + +METHODDEF(void) +finish_pass_gather (j_compress_ptr cinfo) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + int ci, dctbl, actbl; + jpeg_component_info * compptr; + JHUFF_TBL **htblptr; + boolean did_dc[NUM_HUFF_TBLS]; + boolean did_ac[NUM_HUFF_TBLS]; + + /* It's important not to apply jpeg_gen_optimal_table more than once + * per table, because it clobbers the input frequency counts! + */ + MEMZERO(did_dc, SIZEOF(did_dc)); + MEMZERO(did_ac, SIZEOF(did_ac)); + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + dctbl = compptr->dc_tbl_no; + actbl = compptr->ac_tbl_no; + if (! did_dc[dctbl]) { + htblptr = & cinfo->dc_huff_tbl_ptrs[dctbl]; + if (*htblptr == NULL) + *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo); + jpeg_gen_optimal_table(cinfo, *htblptr, entropy->dc_count_ptrs[dctbl]); + did_dc[dctbl] = TRUE; + } + if (! did_ac[actbl]) { + htblptr = & cinfo->ac_huff_tbl_ptrs[actbl]; + if (*htblptr == NULL) + *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo); + jpeg_gen_optimal_table(cinfo, *htblptr, entropy->ac_count_ptrs[actbl]); + did_ac[actbl] = TRUE; + } + } +} + + +#endif /* ENTROPY_OPT_SUPPORTED */ + + +/* + * Module initialization routine for Huffman entropy encoding. + */ + +GLOBAL(void) +jinit_huff_encoder (j_compress_ptr cinfo) +{ + huff_entropy_ptr entropy; + int i; + + entropy = (huff_entropy_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(huff_entropy_encoder)); + cinfo->entropy = (struct jpeg_entropy_encoder *) entropy; + entropy->pub.start_pass = start_pass_huff; + + /* Mark tables unallocated */ + for (i = 0; i < NUM_HUFF_TBLS; i++) { + entropy->dc_derived_tbls[i] = entropy->ac_derived_tbls[i] = NULL; +#ifdef ENTROPY_OPT_SUPPORTED + entropy->dc_count_ptrs[i] = entropy->ac_count_ptrs[i] = NULL; +#endif + } +} diff --git a/mk4/modimage/jpeg-6b/jchuff.h b/mk4/modimage/jpeg-6b/jchuff.h new file mode 100644 index 0000000..a9599fc --- /dev/null +++ b/mk4/modimage/jpeg-6b/jchuff.h @@ -0,0 +1,47 @@ +/* + * jchuff.h + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains declarations for Huffman entropy encoding routines + * that are shared between the sequential encoder (jchuff.c) and the + * progressive encoder (jcphuff.c). No other modules need to see these. + */ + +/* The legal range of a DCT coefficient is + * -1024 .. +1023 for 8-bit data; + * -16384 .. +16383 for 12-bit data. + * Hence the magnitude should always fit in 10 or 14 bits respectively. + */ + +#if BITS_IN_JSAMPLE == 8 +#define MAX_COEF_BITS 10 +#else +#define MAX_COEF_BITS 14 +#endif + +/* Derived data constructed for each Huffman table */ + +typedef struct { + unsigned int ehufco[256]; /* code for each symbol */ + char ehufsi[256]; /* length of code for each symbol */ + /* If no code has been allocated for a symbol S, ehufsi[S] contains 0 */ +} c_derived_tbl; + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_make_c_derived_tbl jMkCDerived +#define jpeg_gen_optimal_table jGenOptTbl +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + +/* Expand a Huffman table definition into the derived format */ +EXTERN(void) jpeg_make_c_derived_tbl + JPP((j_compress_ptr cinfo, boolean isDC, int tblno, + c_derived_tbl ** pdtbl)); + +/* Generate an optimal table definition given the specified counts */ +EXTERN(void) jpeg_gen_optimal_table + JPP((j_compress_ptr cinfo, JHUFF_TBL * htbl, long freq[])); diff --git a/mk4/modimage/jpeg-6b/jcinit.c b/mk4/modimage/jpeg-6b/jcinit.c new file mode 100644 index 0000000..5efffe3 --- /dev/null +++ b/mk4/modimage/jpeg-6b/jcinit.c @@ -0,0 +1,72 @@ +/* + * jcinit.c + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains initialization logic for the JPEG compressor. + * This routine is in charge of selecting the modules to be executed and + * making an initialization call to each one. + * + * Logically, this code belongs in jcmaster.c. It's split out because + * linking this routine implies linking the entire compression library. + * For a transcoding-only application, we want to be able to use jcmaster.c + * without linking in the whole library. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * Master selection of compression modules. + * This is done once at the start of processing an image. We determine + * which modules will be used and give them appropriate initialization calls. + */ + +GLOBAL(void) +jinit_compress_master (j_compress_ptr cinfo) +{ + /* Initialize master control (includes parameter checking/processing) */ + jinit_c_master_control(cinfo, FALSE /* full compression */); + + /* Preprocessing */ + if (! cinfo->raw_data_in) { + jinit_color_converter(cinfo); + jinit_downsampler(cinfo); + jinit_c_prep_controller(cinfo, FALSE /* never need full buffer here */); + } + /* Forward DCT */ + jinit_forward_dct(cinfo); + /* Entropy encoding: either Huffman or arithmetic coding. */ + if (cinfo->arith_code) { + ERREXIT(cinfo, JERR_ARITH_NOTIMPL); + } else { + if (cinfo->progressive_mode) { +#ifdef C_PROGRESSIVE_SUPPORTED + jinit_phuff_encoder(cinfo); +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else + jinit_huff_encoder(cinfo); + } + + /* Need a full-image coefficient buffer in any multi-pass mode. */ + jinit_c_coef_controller(cinfo, + (boolean) (cinfo->num_scans > 1 || cinfo->optimize_coding)); + jinit_c_main_controller(cinfo, FALSE /* never need full buffer here */); + + jinit_marker_writer(cinfo); + + /* We can now tell the memory manager to allocate virtual arrays. */ + (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo); + + /* Write the datastream header (SOI) immediately. + * Frame and scan headers are postponed till later. + * This lets application insert special markers after the SOI. + */ + (*cinfo->marker->write_file_header) (cinfo); +} diff --git a/mk4/modimage/jpeg-6b/jcmainct.c b/mk4/modimage/jpeg-6b/jcmainct.c new file mode 100644 index 0000000..e0279a7 --- /dev/null +++ b/mk4/modimage/jpeg-6b/jcmainct.c @@ -0,0 +1,293 @@ +/* + * jcmainct.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the main buffer controller for compression. + * The main buffer lies between the pre-processor and the JPEG + * compressor proper; it holds downsampled data in the JPEG colorspace. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Note: currently, there is no operating mode in which a full-image buffer + * is needed at this step. If there were, that mode could not be used with + * "raw data" input, since this module is bypassed in that case. However, + * we've left the code here for possible use in special applications. + */ +#undef FULL_MAIN_BUFFER_SUPPORTED + + +/* Private buffer controller object */ + +typedef struct { + struct jpeg_c_main_controller pub; /* public fields */ + + JDIMENSION cur_iMCU_row; /* number of current iMCU row */ + JDIMENSION rowgroup_ctr; /* counts row groups received in iMCU row */ + boolean suspended; /* remember if we suspended output */ + J_BUF_MODE pass_mode; /* current operating mode */ + + /* If using just a strip buffer, this points to the entire set of buffers + * (we allocate one for each component). In the full-image case, this + * points to the currently accessible strips of the virtual arrays. + */ + JSAMPARRAY buffer[MAX_COMPONENTS]; + +#ifdef FULL_MAIN_BUFFER_SUPPORTED + /* If using full-image storage, this array holds pointers to virtual-array + * control blocks for each component. Unused if not full-image storage. + */ + jvirt_sarray_ptr whole_image[MAX_COMPONENTS]; +#endif +} my_main_controller; + +typedef my_main_controller * my_main_ptr; + + +/* Forward declarations */ +METHODDEF(void) process_data_simple_main + JPP((j_compress_ptr cinfo, JSAMPARRAY input_buf, + JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail)); +#ifdef FULL_MAIN_BUFFER_SUPPORTED +METHODDEF(void) process_data_buffer_main + JPP((j_compress_ptr cinfo, JSAMPARRAY input_buf, + JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail)); +#endif + + +/* + * Initialize for a processing pass. + */ + +METHODDEF(void) +start_pass_main (j_compress_ptr cinfo, J_BUF_MODE pass_mode) +{ + my_main_ptr main = (my_main_ptr) cinfo->main; + + /* Do nothing in raw-data mode. */ + if (cinfo->raw_data_in) + return; + + main->cur_iMCU_row = 0; /* initialize counters */ + main->rowgroup_ctr = 0; + main->suspended = FALSE; + main->pass_mode = pass_mode; /* save mode for use by process_data */ + + switch (pass_mode) { + case JBUF_PASS_THRU: +#ifdef FULL_MAIN_BUFFER_SUPPORTED + if (main->whole_image[0] != NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); +#endif + main->pub.process_data = process_data_simple_main; + break; +#ifdef FULL_MAIN_BUFFER_SUPPORTED + case JBUF_SAVE_SOURCE: + case JBUF_CRANK_DEST: + case JBUF_SAVE_AND_PASS: + if (main->whole_image[0] == NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + main->pub.process_data = process_data_buffer_main; + break; +#endif + default: + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + break; + } +} + + +/* + * Process some data. + * This routine handles the simple pass-through mode, + * where we have only a strip buffer. + */ + +METHODDEF(void) +process_data_simple_main (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail) +{ + my_main_ptr main = (my_main_ptr) cinfo->main; + + while (main->cur_iMCU_row < cinfo->total_iMCU_rows) { + /* Read input data if we haven't filled the main buffer yet */ + if (main->rowgroup_ctr < DCTSIZE) + (*cinfo->prep->pre_process_data) (cinfo, + input_buf, in_row_ctr, in_rows_avail, + main->buffer, &main->rowgroup_ctr, + (JDIMENSION) DCTSIZE); + + /* If we don't have a full iMCU row buffered, return to application for + * more data. Note that preprocessor will always pad to fill the iMCU row + * at the bottom of the image. + */ + if (main->rowgroup_ctr != DCTSIZE) + return; + + /* Send the completed row to the compressor */ + if (! (*cinfo->coef->compress_data) (cinfo, main->buffer)) { + /* If compressor did not consume the whole row, then we must need to + * suspend processing and return to the application. In this situation + * we pretend we didn't yet consume the last input row; otherwise, if + * it happened to be the last row of the image, the application would + * think we were done. + */ + if (! main->suspended) { + (*in_row_ctr)--; + main->suspended = TRUE; + } + return; + } + /* We did finish the row. Undo our little suspension hack if a previous + * call suspended; then mark the main buffer empty. + */ + if (main->suspended) { + (*in_row_ctr)++; + main->suspended = FALSE; + } + main->rowgroup_ctr = 0; + main->cur_iMCU_row++; + } +} + + +#ifdef FULL_MAIN_BUFFER_SUPPORTED + +/* + * Process some data. + * This routine handles all of the modes that use a full-size buffer. + */ + +METHODDEF(void) +process_data_buffer_main (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail) +{ + my_main_ptr main = (my_main_ptr) cinfo->main; + int ci; + jpeg_component_info *compptr; + boolean writing = (main->pass_mode != JBUF_CRANK_DEST); + + while (main->cur_iMCU_row < cinfo->total_iMCU_rows) { + /* Realign the virtual buffers if at the start of an iMCU row. */ + if (main->rowgroup_ctr == 0) { + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + main->buffer[ci] = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, main->whole_image[ci], + main->cur_iMCU_row * (compptr->v_samp_factor * DCTSIZE), + (JDIMENSION) (compptr->v_samp_factor * DCTSIZE), writing); + } + /* In a read pass, pretend we just read some source data. */ + if (! writing) { + *in_row_ctr += cinfo->max_v_samp_factor * DCTSIZE; + main->rowgroup_ctr = DCTSIZE; + } + } + + /* If a write pass, read input data until the current iMCU row is full. */ + /* Note: preprocessor will pad if necessary to fill the last iMCU row. */ + if (writing) { + (*cinfo->prep->pre_process_data) (cinfo, + input_buf, in_row_ctr, in_rows_avail, + main->buffer, &main->rowgroup_ctr, + (JDIMENSION) DCTSIZE); + /* Return to application if we need more data to fill the iMCU row. */ + if (main->rowgroup_ctr < DCTSIZE) + return; + } + + /* Emit data, unless this is a sink-only pass. */ + if (main->pass_mode != JBUF_SAVE_SOURCE) { + if (! (*cinfo->coef->compress_data) (cinfo, main->buffer)) { + /* If compressor did not consume the whole row, then we must need to + * suspend processing and return to the application. In this situation + * we pretend we didn't yet consume the last input row; otherwise, if + * it happened to be the last row of the image, the application would + * think we were done. + */ + if (! main->suspended) { + (*in_row_ctr)--; + main->suspended = TRUE; + } + return; + } + /* We did finish the row. Undo our little suspension hack if a previous + * call suspended; then mark the main buffer empty. + */ + if (main->suspended) { + (*in_row_ctr)++; + main->suspended = FALSE; + } + } + + /* If get here, we are done with this iMCU row. Mark buffer empty. */ + main->rowgroup_ctr = 0; + main->cur_iMCU_row++; + } +} + +#endif /* FULL_MAIN_BUFFER_SUPPORTED */ + + +/* + * Initialize main buffer controller. + */ + +GLOBAL(void) +jinit_c_main_controller (j_compress_ptr cinfo, boolean need_full_buffer) +{ + my_main_ptr main; + int ci; + jpeg_component_info *compptr; + + main = (my_main_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_main_controller)); + cinfo->main = (struct jpeg_c_main_controller *) main; + main->pub.start_pass = start_pass_main; + + /* We don't need to create a buffer in raw-data mode. */ + if (cinfo->raw_data_in) + return; + + /* Create the buffer. It holds downsampled data, so each component + * may be of a different size. + */ + if (need_full_buffer) { +#ifdef FULL_MAIN_BUFFER_SUPPORTED + /* Allocate a full-image virtual array for each component */ + /* Note we pad the bottom to a multiple of the iMCU height */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + main->whole_image[ci] = (*cinfo->mem->request_virt_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, + compptr->width_in_blocks * DCTSIZE, + (JDIMENSION) jround_up((long) compptr->height_in_blocks, + (long) compptr->v_samp_factor) * DCTSIZE, + (JDIMENSION) (compptr->v_samp_factor * DCTSIZE)); + } +#else + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); +#endif + } else { +#ifdef FULL_MAIN_BUFFER_SUPPORTED + main->whole_image[0] = NULL; /* flag for no virtual arrays */ +#endif + /* Allocate a strip buffer for each component */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + main->buffer[ci] = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + compptr->width_in_blocks * DCTSIZE, + (JDIMENSION) (compptr->v_samp_factor * DCTSIZE)); + } + } +} diff --git a/mk4/modimage/jpeg-6b/jcmarker.c b/mk4/modimage/jpeg-6b/jcmarker.c new file mode 100644 index 0000000..3d1e6c6 --- /dev/null +++ b/mk4/modimage/jpeg-6b/jcmarker.c @@ -0,0 +1,664 @@ +/* + * jcmarker.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to write JPEG datastream markers. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +typedef enum { /* JPEG marker codes */ + M_SOF0 = 0xc0, + M_SOF1 = 0xc1, + M_SOF2 = 0xc2, + M_SOF3 = 0xc3, + + M_SOF5 = 0xc5, + M_SOF6 = 0xc6, + M_SOF7 = 0xc7, + + M_JPG = 0xc8, + M_SOF9 = 0xc9, + M_SOF10 = 0xca, + M_SOF11 = 0xcb, + + M_SOF13 = 0xcd, + M_SOF14 = 0xce, + M_SOF15 = 0xcf, + + M_DHT = 0xc4, + + M_DAC = 0xcc, + + M_RST0 = 0xd0, + M_RST1 = 0xd1, + M_RST2 = 0xd2, + M_RST3 = 0xd3, + M_RST4 = 0xd4, + M_RST5 = 0xd5, + M_RST6 = 0xd6, + M_RST7 = 0xd7, + + M_SOI = 0xd8, + M_EOI = 0xd9, + M_SOS = 0xda, + M_DQT = 0xdb, + M_DNL = 0xdc, + M_DRI = 0xdd, + M_DHP = 0xde, + M_EXP = 0xdf, + + M_APP0 = 0xe0, + M_APP1 = 0xe1, + M_APP2 = 0xe2, + M_APP3 = 0xe3, + M_APP4 = 0xe4, + M_APP5 = 0xe5, + M_APP6 = 0xe6, + M_APP7 = 0xe7, + M_APP8 = 0xe8, + M_APP9 = 0xe9, + M_APP10 = 0xea, + M_APP11 = 0xeb, + M_APP12 = 0xec, + M_APP13 = 0xed, + M_APP14 = 0xee, + M_APP15 = 0xef, + + M_JPG0 = 0xf0, + M_JPG13 = 0xfd, + M_COM = 0xfe, + + M_TEM = 0x01, + + M_ERROR = 0x100 +} JPEG_MARKER; + + +/* Private state */ + +typedef struct { + struct jpeg_marker_writer pub; /* public fields */ + + unsigned int last_restart_interval; /* last DRI value emitted; 0 after SOI */ +} my_marker_writer; + +typedef my_marker_writer * my_marker_ptr; + + +/* + * Basic output routines. + * + * Note that we do not support suspension while writing a marker. + * Therefore, an application using suspension must ensure that there is + * enough buffer space for the initial markers (typ. 600-700 bytes) before + * calling jpeg_start_compress, and enough space to write the trailing EOI + * (a few bytes) before calling jpeg_finish_compress. Multipass compression + * modes are not supported at all with suspension, so those two are the only + * points where markers will be written. + */ + +LOCAL(void) +emit_byte (j_compress_ptr cinfo, int val) +/* Emit a byte */ +{ + struct jpeg_destination_mgr * dest = cinfo->dest; + + *(dest->next_output_byte)++ = (JOCTET) val; + if (--dest->free_in_buffer == 0) { + if (! (*dest->empty_output_buffer) (cinfo)) + ERREXIT(cinfo, JERR_CANT_SUSPEND); + } +} + + +LOCAL(void) +emit_marker (j_compress_ptr cinfo, JPEG_MARKER mark) +/* Emit a marker code */ +{ + emit_byte(cinfo, 0xFF); + emit_byte(cinfo, (int) mark); +} + + +LOCAL(void) +emit_2bytes (j_compress_ptr cinfo, int value) +/* Emit a 2-byte integer; these are always MSB first in JPEG files */ +{ + emit_byte(cinfo, (value >> 8) & 0xFF); + emit_byte(cinfo, value & 0xFF); +} + + +/* + * Routines to write specific marker types. + */ + +LOCAL(int) +emit_dqt (j_compress_ptr cinfo, int index) +/* Emit a DQT marker */ +/* Returns the precision used (0 = 8bits, 1 = 16bits) for baseline checking */ +{ + JQUANT_TBL * qtbl = cinfo->quant_tbl_ptrs[index]; + int prec; + int i; + + if (qtbl == NULL) + ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, index); + + prec = 0; + for (i = 0; i < DCTSIZE2; i++) { + if (qtbl->quantval[i] > 255) + prec = 1; + } + + if (! qtbl->sent_table) { + emit_marker(cinfo, M_DQT); + + emit_2bytes(cinfo, prec ? DCTSIZE2*2 + 1 + 2 : DCTSIZE2 + 1 + 2); + + emit_byte(cinfo, index + (prec<<4)); + + for (i = 0; i < DCTSIZE2; i++) { + /* The table entries must be emitted in zigzag order. */ + unsigned int qval = qtbl->quantval[jpeg_natural_order[i]]; + if (prec) + emit_byte(cinfo, (int) (qval >> 8)); + emit_byte(cinfo, (int) (qval & 0xFF)); + } + + qtbl->sent_table = TRUE; + } + + return prec; +} + + +LOCAL(void) +emit_dht (j_compress_ptr cinfo, int index, boolean is_ac) +/* Emit a DHT marker */ +{ + JHUFF_TBL * htbl; + int length, i; + + if (is_ac) { + htbl = cinfo->ac_huff_tbl_ptrs[index]; + index += 0x10; /* output index has AC bit set */ + } else { + htbl = cinfo->dc_huff_tbl_ptrs[index]; + } + + if (htbl == NULL) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, index); + + if (! htbl->sent_table) { + emit_marker(cinfo, M_DHT); + + length = 0; + for (i = 1; i <= 16; i++) + length += htbl->bits[i]; + + emit_2bytes(cinfo, length + 2 + 1 + 16); + emit_byte(cinfo, index); + + for (i = 1; i <= 16; i++) + emit_byte(cinfo, htbl->bits[i]); + + for (i = 0; i < length; i++) + emit_byte(cinfo, htbl->huffval[i]); + + htbl->sent_table = TRUE; + } +} + + +LOCAL(void) +emit_dac (j_compress_ptr cinfo) +/* Emit a DAC marker */ +/* Since the useful info is so small, we want to emit all the tables in */ +/* one DAC marker. Therefore this routine does its own scan of the table. */ +{ +#ifdef C_ARITH_CODING_SUPPORTED + char dc_in_use[NUM_ARITH_TBLS]; + char ac_in_use[NUM_ARITH_TBLS]; + int length, i; + jpeg_component_info *compptr; + + for (i = 0; i < NUM_ARITH_TBLS; i++) + dc_in_use[i] = ac_in_use[i] = 0; + + for (i = 0; i < cinfo->comps_in_scan; i++) { + compptr = cinfo->cur_comp_info[i]; + dc_in_use[compptr->dc_tbl_no] = 1; + ac_in_use[compptr->ac_tbl_no] = 1; + } + + length = 0; + for (i = 0; i < NUM_ARITH_TBLS; i++) + length += dc_in_use[i] + ac_in_use[i]; + + emit_marker(cinfo, M_DAC); + + emit_2bytes(cinfo, length*2 + 2); + + for (i = 0; i < NUM_ARITH_TBLS; i++) { + if (dc_in_use[i]) { + emit_byte(cinfo, i); + emit_byte(cinfo, cinfo->arith_dc_L[i] + (cinfo->arith_dc_U[i]<<4)); + } + if (ac_in_use[i]) { + emit_byte(cinfo, i + 0x10); + emit_byte(cinfo, cinfo->arith_ac_K[i]); + } + } +#endif /* C_ARITH_CODING_SUPPORTED */ +} + + +LOCAL(void) +emit_dri (j_compress_ptr cinfo) +/* Emit a DRI marker */ +{ + emit_marker(cinfo, M_DRI); + + emit_2bytes(cinfo, 4); /* fixed length */ + + emit_2bytes(cinfo, (int) cinfo->restart_interval); +} + + +LOCAL(void) +emit_sof (j_compress_ptr cinfo, JPEG_MARKER code) +/* Emit a SOF marker */ +{ + int ci; + jpeg_component_info *compptr; + + emit_marker(cinfo, code); + + emit_2bytes(cinfo, 3 * cinfo->num_components + 2 + 5 + 1); /* length */ + + /* Make sure image isn't bigger than SOF field can handle */ + if ((long) cinfo->image_height > 65535L || + (long) cinfo->image_width > 65535L) + ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) 65535); + + emit_byte(cinfo, cinfo->data_precision); + emit_2bytes(cinfo, (int) cinfo->image_height); + emit_2bytes(cinfo, (int) cinfo->image_width); + + emit_byte(cinfo, cinfo->num_components); + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + emit_byte(cinfo, compptr->component_id); + emit_byte(cinfo, (compptr->h_samp_factor << 4) + compptr->v_samp_factor); + emit_byte(cinfo, compptr->quant_tbl_no); + } +} + + +LOCAL(void) +emit_sos (j_compress_ptr cinfo) +/* Emit a SOS marker */ +{ + int i, td, ta; + jpeg_component_info *compptr; + + emit_marker(cinfo, M_SOS); + + emit_2bytes(cinfo, 2 * cinfo->comps_in_scan + 2 + 1 + 3); /* length */ + + emit_byte(cinfo, cinfo->comps_in_scan); + + for (i = 0; i < cinfo->comps_in_scan; i++) { + compptr = cinfo->cur_comp_info[i]; + emit_byte(cinfo, compptr->component_id); + td = compptr->dc_tbl_no; + ta = compptr->ac_tbl_no; + if (cinfo->progressive_mode) { + /* Progressive mode: only DC or only AC tables are used in one scan; + * furthermore, Huffman coding of DC refinement uses no table at all. + * We emit 0 for unused field(s); this is recommended by the P&M text + * but does not seem to be specified in the standard. + */ + if (cinfo->Ss == 0) { + ta = 0; /* DC scan */ + if (cinfo->Ah != 0 && !cinfo->arith_code) + td = 0; /* no DC table either */ + } else { + td = 0; /* AC scan */ + } + } + emit_byte(cinfo, (td << 4) + ta); + } + + emit_byte(cinfo, cinfo->Ss); + emit_byte(cinfo, cinfo->Se); + emit_byte(cinfo, (cinfo->Ah << 4) + cinfo->Al); +} + + +LOCAL(void) +emit_jfif_app0 (j_compress_ptr cinfo) +/* Emit a JFIF-compliant APP0 marker */ +{ + /* + * Length of APP0 block (2 bytes) + * Block ID (4 bytes - ASCII "JFIF") + * Zero byte (1 byte to terminate the ID string) + * Version Major, Minor (2 bytes - major first) + * Units (1 byte - 0x00 = none, 0x01 = inch, 0x02 = cm) + * Xdpu (2 bytes - dots per unit horizontal) + * Ydpu (2 bytes - dots per unit vertical) + * Thumbnail X size (1 byte) + * Thumbnail Y size (1 byte) + */ + + emit_marker(cinfo, M_APP0); + + emit_2bytes(cinfo, 2 + 4 + 1 + 2 + 1 + 2 + 2 + 1 + 1); /* length */ + + emit_byte(cinfo, 0x4A); /* Identifier: ASCII "JFIF" */ + emit_byte(cinfo, 0x46); + emit_byte(cinfo, 0x49); + emit_byte(cinfo, 0x46); + emit_byte(cinfo, 0); + emit_byte(cinfo, cinfo->JFIF_major_version); /* Version fields */ + emit_byte(cinfo, cinfo->JFIF_minor_version); + emit_byte(cinfo, cinfo->density_unit); /* Pixel size information */ + emit_2bytes(cinfo, (int) cinfo->X_density); + emit_2bytes(cinfo, (int) cinfo->Y_density); + emit_byte(cinfo, 0); /* No thumbnail image */ + emit_byte(cinfo, 0); +} + + +LOCAL(void) +emit_adobe_app14 (j_compress_ptr cinfo) +/* Emit an Adobe APP14 marker */ +{ + /* + * Length of APP14 block (2 bytes) + * Block ID (5 bytes - ASCII "Adobe") + * Version Number (2 bytes - currently 100) + * Flags0 (2 bytes - currently 0) + * Flags1 (2 bytes - currently 0) + * Color transform (1 byte) + * + * Although Adobe TN 5116 mentions Version = 101, all the Adobe files + * now in circulation seem to use Version = 100, so that's what we write. + * + * We write the color transform byte as 1 if the JPEG color space is + * YCbCr, 2 if it's YCCK, 0 otherwise. Adobe's definition has to do with + * whether the encoder performed a transformation, which is pretty useless. + */ + + emit_marker(cinfo, M_APP14); + + emit_2bytes(cinfo, 2 + 5 + 2 + 2 + 2 + 1); /* length */ + + emit_byte(cinfo, 0x41); /* Identifier: ASCII "Adobe" */ + emit_byte(cinfo, 0x64); + emit_byte(cinfo, 0x6F); + emit_byte(cinfo, 0x62); + emit_byte(cinfo, 0x65); + emit_2bytes(cinfo, 100); /* Version */ + emit_2bytes(cinfo, 0); /* Flags0 */ + emit_2bytes(cinfo, 0); /* Flags1 */ + switch (cinfo->jpeg_color_space) { + case JCS_YCbCr: + emit_byte(cinfo, 1); /* Color transform = 1 */ + break; + case JCS_YCCK: + emit_byte(cinfo, 2); /* Color transform = 2 */ + break; + default: + emit_byte(cinfo, 0); /* Color transform = 0 */ + break; + } +} + + +/* + * These routines allow writing an arbitrary marker with parameters. + * The only intended use is to emit COM or APPn markers after calling + * write_file_header and before calling write_frame_header. + * Other uses are not guaranteed to produce desirable results. + * Counting the parameter bytes properly is the caller's responsibility. + */ + +METHODDEF(void) +write_marker_header (j_compress_ptr cinfo, int marker, unsigned int datalen) +/* Emit an arbitrary marker header */ +{ + if (datalen > (unsigned int) 65533) /* safety check */ + ERREXIT(cinfo, JERR_BAD_LENGTH); + + emit_marker(cinfo, (JPEG_MARKER) marker); + + emit_2bytes(cinfo, (int) (datalen + 2)); /* total length */ +} + +METHODDEF(void) +write_marker_byte (j_compress_ptr cinfo, int val) +/* Emit one byte of marker parameters following write_marker_header */ +{ + emit_byte(cinfo, val); +} + + +/* + * Write datastream header. + * This consists of an SOI and optional APPn markers. + * We recommend use of the JFIF marker, but not the Adobe marker, + * when using YCbCr or grayscale data. The JFIF marker should NOT + * be used for any other JPEG colorspace. The Adobe marker is helpful + * to distinguish RGB, CMYK, and YCCK colorspaces. + * Note that an application can write additional header markers after + * jpeg_start_compress returns. + */ + +METHODDEF(void) +write_file_header (j_compress_ptr cinfo) +{ + my_marker_ptr marker = (my_marker_ptr) cinfo->marker; + + emit_marker(cinfo, M_SOI); /* first the SOI */ + + /* SOI is defined to reset restart interval to 0 */ + marker->last_restart_interval = 0; + + if (cinfo->write_JFIF_header) /* next an optional JFIF APP0 */ + emit_jfif_app0(cinfo); + if (cinfo->write_Adobe_marker) /* next an optional Adobe APP14 */ + emit_adobe_app14(cinfo); +} + + +/* + * Write frame header. + * This consists of DQT and SOFn markers. + * Note that we do not emit the SOF until we have emitted the DQT(s). + * This avoids compatibility problems with incorrect implementations that + * try to error-check the quant table numbers as soon as they see the SOF. + */ + +METHODDEF(void) +write_frame_header (j_compress_ptr cinfo) +{ + int ci, prec; + boolean is_baseline; + jpeg_component_info *compptr; + + /* Emit DQT for each quantization table. + * Note that emit_dqt() suppresses any duplicate tables. + */ + prec = 0; + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + prec += emit_dqt(cinfo, compptr->quant_tbl_no); + } + /* now prec is nonzero iff there are any 16-bit quant tables. */ + + /* Check for a non-baseline specification. + * Note we assume that Huffman table numbers won't be changed later. + */ + if (cinfo->arith_code || cinfo->progressive_mode || + cinfo->data_precision != 8) { + is_baseline = FALSE; + } else { + is_baseline = TRUE; + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + if (compptr->dc_tbl_no > 1 || compptr->ac_tbl_no > 1) + is_baseline = FALSE; + } + if (prec && is_baseline) { + is_baseline = FALSE; + /* If it's baseline except for quantizer size, warn the user */ + TRACEMS(cinfo, 0, JTRC_16BIT_TABLES); + } + } + + /* Emit the proper SOF marker */ + if (cinfo->arith_code) { + emit_sof(cinfo, M_SOF9); /* SOF code for arithmetic coding */ + } else { + if (cinfo->progressive_mode) + emit_sof(cinfo, M_SOF2); /* SOF code for progressive Huffman */ + else if (is_baseline) + emit_sof(cinfo, M_SOF0); /* SOF code for baseline implementation */ + else + emit_sof(cinfo, M_SOF1); /* SOF code for non-baseline Huffman file */ + } +} + + +/* + * Write scan header. + * This consists of DHT or DAC markers, optional DRI, and SOS. + * Compressed data will be written following the SOS. + */ + +METHODDEF(void) +write_scan_header (j_compress_ptr cinfo) +{ + my_marker_ptr marker = (my_marker_ptr) cinfo->marker; + int i; + jpeg_component_info *compptr; + + if (cinfo->arith_code) { + /* Emit arith conditioning info. We may have some duplication + * if the file has multiple scans, but it's so small it's hardly + * worth worrying about. + */ + emit_dac(cinfo); + } else { + /* Emit Huffman tables. + * Note that emit_dht() suppresses any duplicate tables. + */ + for (i = 0; i < cinfo->comps_in_scan; i++) { + compptr = cinfo->cur_comp_info[i]; + if (cinfo->progressive_mode) { + /* Progressive mode: only DC or only AC tables are used in one scan */ + if (cinfo->Ss == 0) { + if (cinfo->Ah == 0) /* DC needs no table for refinement scan */ + emit_dht(cinfo, compptr->dc_tbl_no, FALSE); + } else { + emit_dht(cinfo, compptr->ac_tbl_no, TRUE); + } + } else { + /* Sequential mode: need both DC and AC tables */ + emit_dht(cinfo, compptr->dc_tbl_no, FALSE); + emit_dht(cinfo, compptr->ac_tbl_no, TRUE); + } + } + } + + /* Emit DRI if required --- note that DRI value could change for each scan. + * We avoid wasting space with unnecessary DRIs, however. + */ + if (cinfo->restart_interval != marker->last_restart_interval) { + emit_dri(cinfo); + marker->last_restart_interval = cinfo->restart_interval; + } + + emit_sos(cinfo); +} + + +/* + * Write datastream trailer. + */ + +METHODDEF(void) +write_file_trailer (j_compress_ptr cinfo) +{ + emit_marker(cinfo, M_EOI); +} + + +/* + * Write an abbreviated table-specification datastream. + * This consists of SOI, DQT and DHT tables, and EOI. + * Any table that is defined and not marked sent_table = TRUE will be + * emitted. Note that all tables will be marked sent_table = TRUE at exit. + */ + +METHODDEF(void) +write_tables_only (j_compress_ptr cinfo) +{ + int i; + + emit_marker(cinfo, M_SOI); + + for (i = 0; i < NUM_QUANT_TBLS; i++) { + if (cinfo->quant_tbl_ptrs[i] != NULL) + (void) emit_dqt(cinfo, i); + } + + if (! cinfo->arith_code) { + for (i = 0; i < NUM_HUFF_TBLS; i++) { + if (cinfo->dc_huff_tbl_ptrs[i] != NULL) + emit_dht(cinfo, i, FALSE); + if (cinfo->ac_huff_tbl_ptrs[i] != NULL) + emit_dht(cinfo, i, TRUE); + } + } + + emit_marker(cinfo, M_EOI); +} + + +/* + * Initialize the marker writer module. + */ + +GLOBAL(void) +jinit_marker_writer (j_compress_ptr cinfo) +{ + my_marker_ptr marker; + + /* Create the subobject */ + marker = (my_marker_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_marker_writer)); + cinfo->marker = (struct jpeg_marker_writer *) marker; + /* Initialize method pointers */ + marker->pub.write_file_header = write_file_header; + marker->pub.write_frame_header = write_frame_header; + marker->pub.write_scan_header = write_scan_header; + marker->pub.write_file_trailer = write_file_trailer; + marker->pub.write_tables_only = write_tables_only; + marker->pub.write_marker_header = write_marker_header; + marker->pub.write_marker_byte = write_marker_byte; + /* Initialize private state */ + marker->last_restart_interval = 0; +} diff --git a/mk4/modimage/jpeg-6b/jcmaster.c b/mk4/modimage/jpeg-6b/jcmaster.c new file mode 100644 index 0000000..aab4020 --- /dev/null +++ b/mk4/modimage/jpeg-6b/jcmaster.c @@ -0,0 +1,590 @@ +/* + * jcmaster.c + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains master control logic for the JPEG compressor. + * These routines are concerned with parameter validation, initial setup, + * and inter-pass control (determining the number of passes and the work + * to be done in each pass). + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Private state */ + +typedef enum { + main_pass, /* input data, also do first output step */ + huff_opt_pass, /* Huffman code optimization pass */ + output_pass /* data output pass */ +} c_pass_type; + +typedef struct { + struct jpeg_comp_master pub; /* public fields */ + + c_pass_type pass_type; /* the type of the current pass */ + + int pass_number; /* # of passes completed */ + int total_passes; /* total # of passes needed */ + + int scan_number; /* current index in scan_info[] */ +} my_comp_master; + +typedef my_comp_master * my_master_ptr; + + +/* + * Support routines that do various essential calculations. + */ + +LOCAL(void) +initial_setup (j_compress_ptr cinfo) +/* Do computations that are needed before master selection phase */ +{ + int ci; + jpeg_component_info *compptr; + long samplesperrow; + JDIMENSION jd_samplesperrow; + + /* Sanity check on image dimensions */ + if (cinfo->image_height <= 0 || cinfo->image_width <= 0 + || cinfo->num_components <= 0 || cinfo->input_components <= 0) + ERREXIT(cinfo, JERR_EMPTY_IMAGE); + + /* Make sure image isn't bigger than I can handle */ + if ((long) cinfo->image_height > (long) JPEG_MAX_DIMENSION || + (long) cinfo->image_width > (long) JPEG_MAX_DIMENSION) + ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) JPEG_MAX_DIMENSION); + + /* Width of an input scanline must be representable as JDIMENSION. */ + samplesperrow = (long) cinfo->image_width * (long) cinfo->input_components; + jd_samplesperrow = (JDIMENSION) samplesperrow; + if ((long) jd_samplesperrow != samplesperrow) + ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); + + /* For now, precision must match compiled-in value... */ + if (cinfo->data_precision != BITS_IN_JSAMPLE) + ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision); + + /* Check that number of components won't exceed internal array sizes */ + if (cinfo->num_components > MAX_COMPONENTS) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components, + MAX_COMPONENTS); + + /* Compute maximum sampling factors; check factor validity */ + cinfo->max_h_samp_factor = 1; + cinfo->max_v_samp_factor = 1; + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + if (compptr->h_samp_factor<=0 || compptr->h_samp_factor>MAX_SAMP_FACTOR || + compptr->v_samp_factor<=0 || compptr->v_samp_factor>MAX_SAMP_FACTOR) + ERREXIT(cinfo, JERR_BAD_SAMPLING); + cinfo->max_h_samp_factor = MAX(cinfo->max_h_samp_factor, + compptr->h_samp_factor); + cinfo->max_v_samp_factor = MAX(cinfo->max_v_samp_factor, + compptr->v_samp_factor); + } + + /* Compute dimensions of components */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Fill in the correct component_index value; don't rely on application */ + compptr->component_index = ci; + /* For compression, we never do DCT scaling. */ + compptr->DCT_scaled_size = DCTSIZE; + /* Size in DCT blocks */ + compptr->width_in_blocks = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor, + (long) (cinfo->max_h_samp_factor * DCTSIZE)); + compptr->height_in_blocks = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor, + (long) (cinfo->max_v_samp_factor * DCTSIZE)); + /* Size in samples */ + compptr->downsampled_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor, + (long) cinfo->max_h_samp_factor); + compptr->downsampled_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor, + (long) cinfo->max_v_samp_factor); + /* Mark component needed (this flag isn't actually used for compression) */ + compptr->component_needed = TRUE; + } + + /* Compute number of fully interleaved MCU rows (number of times that + * main controller will call coefficient controller). + */ + cinfo->total_iMCU_rows = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height, + (long) (cinfo->max_v_samp_factor*DCTSIZE)); +} + + +#ifdef C_MULTISCAN_FILES_SUPPORTED + +LOCAL(void) +validate_script (j_compress_ptr cinfo) +/* Verify that the scan script in cinfo->scan_info[] is valid; also + * determine whether it uses progressive JPEG, and set cinfo->progressive_mode. + */ +{ + const jpeg_scan_info * scanptr; + int scanno, ncomps, ci, coefi, thisi; + int Ss, Se, Ah, Al; + boolean component_sent[MAX_COMPONENTS]; +#ifdef C_PROGRESSIVE_SUPPORTED + int * last_bitpos_ptr; + int last_bitpos[MAX_COMPONENTS][DCTSIZE2]; + /* -1 until that coefficient has been seen; then last Al for it */ +#endif + + if (cinfo->num_scans <= 0) + ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, 0); + + /* For sequential JPEG, all scans must have Ss=0, Se=DCTSIZE2-1; + * for progressive JPEG, no scan can have this. + */ + scanptr = cinfo->scan_info; + if (scanptr->Ss != 0 || scanptr->Se != DCTSIZE2-1) { +#ifdef C_PROGRESSIVE_SUPPORTED + cinfo->progressive_mode = TRUE; + last_bitpos_ptr = & last_bitpos[0][0]; + for (ci = 0; ci < cinfo->num_components; ci++) + for (coefi = 0; coefi < DCTSIZE2; coefi++) + *last_bitpos_ptr++ = -1; +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else { + cinfo->progressive_mode = FALSE; + for (ci = 0; ci < cinfo->num_components; ci++) + component_sent[ci] = FALSE; + } + + for (scanno = 1; scanno <= cinfo->num_scans; scanptr++, scanno++) { + /* Validate component indexes */ + ncomps = scanptr->comps_in_scan; + if (ncomps <= 0 || ncomps > MAX_COMPS_IN_SCAN) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, ncomps, MAX_COMPS_IN_SCAN); + for (ci = 0; ci < ncomps; ci++) { + thisi = scanptr->component_index[ci]; + if (thisi < 0 || thisi >= cinfo->num_components) + ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno); + /* Components must appear in SOF order within each scan */ + if (ci > 0 && thisi <= scanptr->component_index[ci-1]) + ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno); + } + /* Validate progression parameters */ + Ss = scanptr->Ss; + Se = scanptr->Se; + Ah = scanptr->Ah; + Al = scanptr->Al; + if (cinfo->progressive_mode) { +#ifdef C_PROGRESSIVE_SUPPORTED + /* The JPEG spec simply gives the ranges 0..13 for Ah and Al, but that + * seems wrong: the upper bound ought to depend on data precision. + * Perhaps they really meant 0..N+1 for N-bit precision. + * Here we allow 0..10 for 8-bit data; Al larger than 10 results in + * out-of-range reconstructed DC values during the first DC scan, + * which might cause problems for some decoders. + */ +#if BITS_IN_JSAMPLE == 8 +#define MAX_AH_AL 10 +#else +#define MAX_AH_AL 13 +#endif + if (Ss < 0 || Ss >= DCTSIZE2 || Se < Ss || Se >= DCTSIZE2 || + Ah < 0 || Ah > MAX_AH_AL || Al < 0 || Al > MAX_AH_AL) + ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); + if (Ss == 0) { + if (Se != 0) /* DC and AC together not OK */ + ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); + } else { + if (ncomps != 1) /* AC scans must be for only one component */ + ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); + } + for (ci = 0; ci < ncomps; ci++) { + last_bitpos_ptr = & last_bitpos[scanptr->component_index[ci]][0]; + if (Ss != 0 && last_bitpos_ptr[0] < 0) /* AC without prior DC scan */ + ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); + for (coefi = Ss; coefi <= Se; coefi++) { + if (last_bitpos_ptr[coefi] < 0) { + /* first scan of this coefficient */ + if (Ah != 0) + ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); + } else { + /* not first scan */ + if (Ah != last_bitpos_ptr[coefi] || Al != Ah-1) + ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); + } + last_bitpos_ptr[coefi] = Al; + } + } +#endif + } else { + /* For sequential JPEG, all progression parameters must be these: */ + if (Ss != 0 || Se != DCTSIZE2-1 || Ah != 0 || Al != 0) + ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); + /* Make sure components are not sent twice */ + for (ci = 0; ci < ncomps; ci++) { + thisi = scanptr->component_index[ci]; + if (component_sent[thisi]) + ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno); + component_sent[thisi] = TRUE; + } + } + } + + /* Now verify that everything got sent. */ + if (cinfo->progressive_mode) { +#ifdef C_PROGRESSIVE_SUPPORTED + /* For progressive mode, we only check that at least some DC data + * got sent for each component; the spec does not require that all bits + * of all coefficients be transmitted. Would it be wiser to enforce + * transmission of all coefficient bits?? + */ + for (ci = 0; ci < cinfo->num_components; ci++) { + if (last_bitpos[ci][0] < 0) + ERREXIT(cinfo, JERR_MISSING_DATA); + } +#endif + } else { + for (ci = 0; ci < cinfo->num_components; ci++) { + if (! component_sent[ci]) + ERREXIT(cinfo, JERR_MISSING_DATA); + } + } +} + +#endif /* C_MULTISCAN_FILES_SUPPORTED */ + + +LOCAL(void) +select_scan_parameters (j_compress_ptr cinfo) +/* Set up the scan parameters for the current scan */ +{ + int ci; + +#ifdef C_MULTISCAN_FILES_SUPPORTED + if (cinfo->scan_info != NULL) { + /* Prepare for current scan --- the script is already validated */ + my_master_ptr master = (my_master_ptr) cinfo->master; + const jpeg_scan_info * scanptr = cinfo->scan_info + master->scan_number; + + cinfo->comps_in_scan = scanptr->comps_in_scan; + for (ci = 0; ci < scanptr->comps_in_scan; ci++) { + cinfo->cur_comp_info[ci] = + &cinfo->comp_info[scanptr->component_index[ci]]; + } + cinfo->Ss = scanptr->Ss; + cinfo->Se = scanptr->Se; + cinfo->Ah = scanptr->Ah; + cinfo->Al = scanptr->Al; + } + else +#endif + { + /* Prepare for single sequential-JPEG scan containing all components */ + if (cinfo->num_components > MAX_COMPS_IN_SCAN) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components, + MAX_COMPS_IN_SCAN); + cinfo->comps_in_scan = cinfo->num_components; + for (ci = 0; ci < cinfo->num_components; ci++) { + cinfo->cur_comp_info[ci] = &cinfo->comp_info[ci]; + } + cinfo->Ss = 0; + cinfo->Se = DCTSIZE2-1; + cinfo->Ah = 0; + cinfo->Al = 0; + } +} + + +LOCAL(void) +per_scan_setup (j_compress_ptr cinfo) +/* Do computations that are needed before processing a JPEG scan */ +/* cinfo->comps_in_scan and cinfo->cur_comp_info[] are already set */ +{ + int ci, mcublks, tmp; + jpeg_component_info *compptr; + + if (cinfo->comps_in_scan == 1) { + + /* Noninterleaved (single-component) scan */ + compptr = cinfo->cur_comp_info[0]; + + /* Overall image size in MCUs */ + cinfo->MCUs_per_row = compptr->width_in_blocks; + cinfo->MCU_rows_in_scan = compptr->height_in_blocks; + + /* For noninterleaved scan, always one block per MCU */ + compptr->MCU_width = 1; + compptr->MCU_height = 1; + compptr->MCU_blocks = 1; + compptr->MCU_sample_width = DCTSIZE; + compptr->last_col_width = 1; + /* For noninterleaved scans, it is convenient to define last_row_height + * as the number of block rows present in the last iMCU row. + */ + tmp = (int) (compptr->height_in_blocks % compptr->v_samp_factor); + if (tmp == 0) tmp = compptr->v_samp_factor; + compptr->last_row_height = tmp; + + /* Prepare array describing MCU composition */ + cinfo->blocks_in_MCU = 1; + cinfo->MCU_membership[0] = 0; + + } else { + + /* Interleaved (multi-component) scan */ + if (cinfo->comps_in_scan <= 0 || cinfo->comps_in_scan > MAX_COMPS_IN_SCAN) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->comps_in_scan, + MAX_COMPS_IN_SCAN); + + /* Overall image size in MCUs */ + cinfo->MCUs_per_row = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width, + (long) (cinfo->max_h_samp_factor*DCTSIZE)); + cinfo->MCU_rows_in_scan = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height, + (long) (cinfo->max_v_samp_factor*DCTSIZE)); + + cinfo->blocks_in_MCU = 0; + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* Sampling factors give # of blocks of component in each MCU */ + compptr->MCU_width = compptr->h_samp_factor; + compptr->MCU_height = compptr->v_samp_factor; + compptr->MCU_blocks = compptr->MCU_width * compptr->MCU_height; + compptr->MCU_sample_width = compptr->MCU_width * DCTSIZE; + /* Figure number of non-dummy blocks in last MCU column & row */ + tmp = (int) (compptr->width_in_blocks % compptr->MCU_width); + if (tmp == 0) tmp = compptr->MCU_width; + compptr->last_col_width = tmp; + tmp = (int) (compptr->height_in_blocks % compptr->MCU_height); + if (tmp == 0) tmp = compptr->MCU_height; + compptr->last_row_height = tmp; + /* Prepare array describing MCU composition */ + mcublks = compptr->MCU_blocks; + if (cinfo->blocks_in_MCU + mcublks > C_MAX_BLOCKS_IN_MCU) + ERREXIT(cinfo, JERR_BAD_MCU_SIZE); + while (mcublks-- > 0) { + cinfo->MCU_membership[cinfo->blocks_in_MCU++] = ci; + } + } + + } + + /* Convert restart specified in rows to actual MCU count. */ + /* Note that count must fit in 16 bits, so we provide limiting. */ + if (cinfo->restart_in_rows > 0) { + long nominal = (long) cinfo->restart_in_rows * (long) cinfo->MCUs_per_row; + cinfo->restart_interval = (unsigned int) MIN(nominal, 65535L); + } +} + + +/* + * Per-pass setup. + * This is called at the beginning of each pass. We determine which modules + * will be active during this pass and give them appropriate start_pass calls. + * We also set is_last_pass to indicate whether any more passes will be + * required. + */ + +METHODDEF(void) +prepare_for_pass (j_compress_ptr cinfo) +{ + my_master_ptr master = (my_master_ptr) cinfo->master; + + switch (master->pass_type) { + case main_pass: + /* Initial pass: will collect input data, and do either Huffman + * optimization or data output for the first scan. + */ + select_scan_parameters(cinfo); + per_scan_setup(cinfo); + if (! cinfo->raw_data_in) { + (*cinfo->cconvert->start_pass) (cinfo); + (*cinfo->downsample->start_pass) (cinfo); + (*cinfo->prep->start_pass) (cinfo, JBUF_PASS_THRU); + } + (*cinfo->fdct->start_pass) (cinfo); + (*cinfo->entropy->start_pass) (cinfo, cinfo->optimize_coding); + (*cinfo->coef->start_pass) (cinfo, + (master->total_passes > 1 ? + JBUF_SAVE_AND_PASS : JBUF_PASS_THRU)); + (*cinfo->main->start_pass) (cinfo, JBUF_PASS_THRU); + if (cinfo->optimize_coding) { + /* No immediate data output; postpone writing frame/scan headers */ + master->pub.call_pass_startup = FALSE; + } else { + /* Will write frame/scan headers at first jpeg_write_scanlines call */ + master->pub.call_pass_startup = TRUE; + } + break; +#ifdef ENTROPY_OPT_SUPPORTED + case huff_opt_pass: + /* Do Huffman optimization for a scan after the first one. */ + select_scan_parameters(cinfo); + per_scan_setup(cinfo); + if (cinfo->Ss != 0 || cinfo->Ah == 0 || cinfo->arith_code) { + (*cinfo->entropy->start_pass) (cinfo, TRUE); + (*cinfo->coef->start_pass) (cinfo, JBUF_CRANK_DEST); + master->pub.call_pass_startup = FALSE; + break; + } + /* Special case: Huffman DC refinement scans need no Huffman table + * and therefore we can skip the optimization pass for them. + */ + master->pass_type = output_pass; + master->pass_number++; + /*FALLTHROUGH*/ +#endif + case output_pass: + /* Do a data-output pass. */ + /* We need not repeat per-scan setup if prior optimization pass did it. */ + if (! cinfo->optimize_coding) { + select_scan_parameters(cinfo); + per_scan_setup(cinfo); + } + (*cinfo->entropy->start_pass) (cinfo, FALSE); + (*cinfo->coef->start_pass) (cinfo, JBUF_CRANK_DEST); + /* We emit frame/scan headers now */ + if (master->scan_number == 0) + (*cinfo->marker->write_frame_header) (cinfo); + (*cinfo->marker->write_scan_header) (cinfo); + master->pub.call_pass_startup = FALSE; + break; + default: + ERREXIT(cinfo, JERR_NOT_COMPILED); + } + + master->pub.is_last_pass = (master->pass_number == master->total_passes-1); + + /* Set up progress monitor's pass info if present */ + if (cinfo->progress != NULL) { + cinfo->progress->completed_passes = master->pass_number; + cinfo->progress->total_passes = master->total_passes; + } +} + + +/* + * Special start-of-pass hook. + * This is called by jpeg_write_scanlines if call_pass_startup is TRUE. + * In single-pass processing, we need this hook because we don't want to + * write frame/scan headers during jpeg_start_compress; we want to let the + * application write COM markers etc. between jpeg_start_compress and the + * jpeg_write_scanlines loop. + * In multi-pass processing, this routine is not used. + */ + +METHODDEF(void) +pass_startup (j_compress_ptr cinfo) +{ + cinfo->master->call_pass_startup = FALSE; /* reset flag so call only once */ + + (*cinfo->marker->write_frame_header) (cinfo); + (*cinfo->marker->write_scan_header) (cinfo); +} + + +/* + * Finish up at end of pass. + */ + +METHODDEF(void) +finish_pass_master (j_compress_ptr cinfo) +{ + my_master_ptr master = (my_master_ptr) cinfo->master; + + /* The entropy coder always needs an end-of-pass call, + * either to analyze statistics or to flush its output buffer. + */ + (*cinfo->entropy->finish_pass) (cinfo); + + /* Update state for next pass */ + switch (master->pass_type) { + case main_pass: + /* next pass is either output of scan 0 (after optimization) + * or output of scan 1 (if no optimization). + */ + master->pass_type = output_pass; + if (! cinfo->optimize_coding) + master->scan_number++; + break; + case huff_opt_pass: + /* next pass is always output of current scan */ + master->pass_type = output_pass; + break; + case output_pass: + /* next pass is either optimization or output of next scan */ + if (cinfo->optimize_coding) + master->pass_type = huff_opt_pass; + master->scan_number++; + break; + } + + master->pass_number++; +} + + +/* + * Initialize master compression control. + */ + +GLOBAL(void) +jinit_c_master_control (j_compress_ptr cinfo, boolean transcode_only) +{ + my_master_ptr master; + + master = (my_master_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_comp_master)); + cinfo->master = (struct jpeg_comp_master *) master; + master->pub.prepare_for_pass = prepare_for_pass; + master->pub.pass_startup = pass_startup; + master->pub.finish_pass = finish_pass_master; + master->pub.is_last_pass = FALSE; + + /* Validate parameters, determine derived values */ + initial_setup(cinfo); + + if (cinfo->scan_info != NULL) { +#ifdef C_MULTISCAN_FILES_SUPPORTED + validate_script(cinfo); +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else { + cinfo->progressive_mode = FALSE; + cinfo->num_scans = 1; + } + + if (cinfo->progressive_mode) /* TEMPORARY HACK ??? */ + cinfo->optimize_coding = TRUE; /* assume default tables no good for progressive mode */ + + /* Initialize my private state */ + if (transcode_only) { + /* no main pass in transcoding */ + if (cinfo->optimize_coding) + master->pass_type = huff_opt_pass; + else + master->pass_type = output_pass; + } else { + /* for normal compression, first pass is always this type: */ + master->pass_type = main_pass; + } + master->scan_number = 0; + master->pass_number = 0; + if (cinfo->optimize_coding) + master->total_passes = cinfo->num_scans * 2; + else + master->total_passes = cinfo->num_scans; +} diff --git a/mk4/modimage/jpeg-6b/jcomapi.c b/mk4/modimage/jpeg-6b/jcomapi.c new file mode 100644 index 0000000..9b1fa75 --- /dev/null +++ b/mk4/modimage/jpeg-6b/jcomapi.c @@ -0,0 +1,106 @@ +/* + * jcomapi.c + * + * Copyright (C) 1994-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains application interface routines that are used for both + * compression and decompression. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * Abort processing of a JPEG compression or decompression operation, + * but don't destroy the object itself. + * + * For this, we merely clean up all the nonpermanent memory pools. + * Note that temp files (virtual arrays) are not allowed to belong to + * the permanent pool, so we will be able to close all temp files here. + * Closing a data source or destination, if necessary, is the application's + * responsibility. + */ + +GLOBAL(void) +jpeg_abort (j_common_ptr cinfo) +{ + int pool; + + /* Do nothing if called on a not-initialized or destroyed JPEG object. */ + if (cinfo->mem == NULL) + return; + + /* Releasing pools in reverse order might help avoid fragmentation + * with some (brain-damaged) malloc libraries. + */ + for (pool = JPOOL_NUMPOOLS-1; pool > JPOOL_PERMANENT; pool--) { + (*cinfo->mem->free_pool) (cinfo, pool); + } + + /* Reset overall state for possible reuse of object */ + if (cinfo->is_decompressor) { + cinfo->global_state = DSTATE_START; + /* Try to keep application from accessing now-deleted marker list. + * A bit kludgy to do it here, but this is the most central place. + */ + ((j_decompress_ptr) cinfo)->marker_list = NULL; + } else { + cinfo->global_state = CSTATE_START; + } +} + + +/* + * Destruction of a JPEG object. + * + * Everything gets deallocated except the master jpeg_compress_struct itself + * and the error manager struct. Both of these are supplied by the application + * and must be freed, if necessary, by the application. (Often they are on + * the stack and so don't need to be freed anyway.) + * Closing a data source or destination, if necessary, is the application's + * responsibility. + */ + +GLOBAL(void) +jpeg_destroy (j_common_ptr cinfo) +{ + /* We need only tell the memory manager to release everything. */ + /* NB: mem pointer is NULL if memory mgr failed to initialize. */ + if (cinfo->mem != NULL) + (*cinfo->mem->self_destruct) (cinfo); + cinfo->mem = NULL; /* be safe if jpeg_destroy is called twice */ + cinfo->global_state = 0; /* mark it destroyed */ +} + + +/* + * Convenience routines for allocating quantization and Huffman tables. + * (Would jutils.c be a more reasonable place to put these?) + */ + +GLOBAL(JQUANT_TBL *) +jpeg_alloc_quant_table (j_common_ptr cinfo) +{ + JQUANT_TBL *tbl; + + tbl = (JQUANT_TBL *) + (*cinfo->mem->alloc_small) (cinfo, JPOOL_PERMANENT, SIZEOF(JQUANT_TBL)); + tbl->sent_table = FALSE; /* make sure this is false in any new table */ + return tbl; +} + + +GLOBAL(JHUFF_TBL *) +jpeg_alloc_huff_table (j_common_ptr cinfo) +{ + JHUFF_TBL *tbl; + + tbl = (JHUFF_TBL *) + (*cinfo->mem->alloc_small) (cinfo, JPOOL_PERMANENT, SIZEOF(JHUFF_TBL)); + tbl->sent_table = FALSE; /* make sure this is false in any new table */ + return tbl; +} diff --git a/mk4/modimage/jpeg-6b/jconfig.bcc b/mk4/modimage/jpeg-6b/jconfig.bcc new file mode 100644 index 0000000..c6c53ff --- /dev/null +++ b/mk4/modimage/jpeg-6b/jconfig.bcc @@ -0,0 +1,48 @@ +/* jconfig.bcc --- jconfig.h for Borland C (Turbo C) on MS-DOS or OS/2. */ +/* see jconfig.doc for explanations */ + +#define HAVE_PROTOTYPES +#define HAVE_UNSIGNED_CHAR +#define HAVE_UNSIGNED_SHORT +/* #define void char */ +/* #define const */ +#undef CHAR_IS_UNSIGNED +#define HAVE_STDDEF_H +#define HAVE_STDLIB_H +#undef NEED_BSD_STRINGS +#undef NEED_SYS_TYPES_H +#ifdef __MSDOS__ +#define NEED_FAR_POINTERS /* for small or medium memory model */ +#endif +#undef NEED_SHORT_EXTERNAL_NAMES +#undef INCOMPLETE_TYPES_BROKEN /* this assumes you have -w-stu in CFLAGS */ + +#ifdef JPEG_INTERNALS + +#undef RIGHT_SHIFT_IS_UNSIGNED + +#ifdef __MSDOS__ +#define USE_MSDOS_MEMMGR /* Define this if you use jmemdos.c */ +#define MAX_ALLOC_CHUNK 65520L /* Maximum request to malloc() */ +#define USE_FMEM /* Borland has _fmemcpy() and _fmemset() */ +#endif + +#endif /* JPEG_INTERNALS */ + +#ifdef JPEG_CJPEG_DJPEG + +#define BMP_SUPPORTED /* BMP image file format */ +#define GIF_SUPPORTED /* GIF image file format */ +#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */ +#undef RLE_SUPPORTED /* Utah RLE image file format */ +#define TARGA_SUPPORTED /* Targa image file format */ + +#define TWO_FILE_COMMANDLINE +#define USE_SETMODE /* Borland has setmode() */ +#ifdef __MSDOS__ +#define NEED_SIGNAL_CATCHER /* Define this if you use jmemdos.c */ +#endif +#undef DONT_USE_B_MODE +#undef PROGRESS_REPORT /* optional */ + +#endif /* JPEG_CJPEG_DJPEG */ diff --git a/mk4/modimage/jpeg-6b/jconfig.cfg b/mk4/modimage/jpeg-6b/jconfig.cfg new file mode 100644 index 0000000..36a04fa --- /dev/null +++ b/mk4/modimage/jpeg-6b/jconfig.cfg @@ -0,0 +1,44 @@ +/* jconfig.cfg --- source file edited by configure script */ +/* see jconfig.doc for explanations */ + +#undef HAVE_PROTOTYPES +#undef HAVE_UNSIGNED_CHAR +#undef HAVE_UNSIGNED_SHORT +#undef void +#undef const +#undef CHAR_IS_UNSIGNED +#undef HAVE_STDDEF_H +#undef HAVE_STDLIB_H +#undef NEED_BSD_STRINGS +#undef NEED_SYS_TYPES_H +#undef NEED_FAR_POINTERS +#undef NEED_SHORT_EXTERNAL_NAMES +/* Define this if you get warnings about undefined structures. */ +#undef INCOMPLETE_TYPES_BROKEN + +#ifdef JPEG_INTERNALS + +#undef RIGHT_SHIFT_IS_UNSIGNED +#undef INLINE +/* These are for configuring the JPEG memory manager. */ +#undef DEFAULT_MAX_MEM +#undef NO_MKTEMP + +#endif /* JPEG_INTERNALS */ + +#ifdef JPEG_CJPEG_DJPEG + +#define BMP_SUPPORTED /* BMP image file format */ +#define GIF_SUPPORTED /* GIF image file format */ +#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */ +#undef RLE_SUPPORTED /* Utah RLE image file format */ +#define TARGA_SUPPORTED /* Targa image file format */ + +#undef TWO_FILE_COMMANDLINE +#undef NEED_SIGNAL_CATCHER +#undef DONT_USE_B_MODE + +/* Define this if you want percent-done progress reports from cjpeg/djpeg. */ +#undef PROGRESS_REPORT + +#endif /* JPEG_CJPEG_DJPEG */ diff --git a/mk4/modimage/jpeg-6b/jconfig.dj b/mk4/modimage/jpeg-6b/jconfig.dj new file mode 100644 index 0000000..f759a9d --- /dev/null +++ b/mk4/modimage/jpeg-6b/jconfig.dj @@ -0,0 +1,38 @@ +/* jconfig.dj --- jconfig.h for DJGPP (Delorie's GNU C port) on MS-DOS. */ +/* see jconfig.doc for explanations */ + +#define HAVE_PROTOTYPES +#define HAVE_UNSIGNED_CHAR +#define HAVE_UNSIGNED_SHORT +/* #define void char */ +/* #define const */ +#undef CHAR_IS_UNSIGNED +#define HAVE_STDDEF_H +#define HAVE_STDLIB_H +#undef NEED_BSD_STRINGS +#undef NEED_SYS_TYPES_H +#undef NEED_FAR_POINTERS /* DJGPP uses flat 32-bit addressing */ +#undef NEED_SHORT_EXTERNAL_NAMES +#undef INCOMPLETE_TYPES_BROKEN + +#ifdef JPEG_INTERNALS + +#undef RIGHT_SHIFT_IS_UNSIGNED + +#endif /* JPEG_INTERNALS */ + +#ifdef JPEG_CJPEG_DJPEG + +#define BMP_SUPPORTED /* BMP image file format */ +#define GIF_SUPPORTED /* GIF image file format */ +#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */ +#undef RLE_SUPPORTED /* Utah RLE image file format */ +#define TARGA_SUPPORTED /* Targa image file format */ + +#undef TWO_FILE_COMMANDLINE /* optional */ +#define USE_SETMODE /* Needed to make one-file style work in DJGPP */ +#undef NEED_SIGNAL_CATCHER /* Define this if you use jmemname.c */ +#undef DONT_USE_B_MODE +#undef PROGRESS_REPORT /* optional */ + +#endif /* JPEG_CJPEG_DJPEG */ diff --git a/mk4/modimage/jpeg-6b/jconfig.doc b/mk4/modimage/jpeg-6b/jconfig.doc new file mode 100644 index 0000000..c18d1c0 --- /dev/null +++ b/mk4/modimage/jpeg-6b/jconfig.doc @@ -0,0 +1,155 @@ +/* + * jconfig.doc + * + * Copyright (C) 1991-1994, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file documents the configuration options that are required to + * customize the JPEG software for a particular system. + * + * The actual configuration options for a particular installation are stored + * in jconfig.h. On many machines, jconfig.h can be generated automatically + * or copied from one of the "canned" jconfig files that we supply. But if + * you need to generate a jconfig.h file by hand, this file tells you how. + * + * DO NOT EDIT THIS FILE --- IT WON'T ACCOMPLISH ANYTHING. + * EDIT A COPY NAMED JCONFIG.H. + */ + + +/* + * These symbols indicate the properties of your machine or compiler. + * #define the symbol if yes, #undef it if no. + */ + +/* Does your compiler support function prototypes? + * (If not, you also need to use ansi2knr, see install.doc) + */ +#define HAVE_PROTOTYPES + +/* Does your compiler support the declaration "unsigned char" ? + * How about "unsigned short" ? + */ +#define HAVE_UNSIGNED_CHAR +#define HAVE_UNSIGNED_SHORT + +/* Define "void" as "char" if your compiler doesn't know about type void. + * NOTE: be sure to define void such that "void *" represents the most general + * pointer type, e.g., that returned by malloc(). + */ +/* #define void char */ + +/* Define "const" as empty if your compiler doesn't know the "const" keyword. + */ +/* #define const */ + +/* Define this if an ordinary "char" type is unsigned. + * If you're not sure, leaving it undefined will work at some cost in speed. + * If you defined HAVE_UNSIGNED_CHAR then the speed difference is minimal. + */ +#undef CHAR_IS_UNSIGNED + +/* Define this if your system has an ANSI-conforming file. + */ +#define HAVE_STDDEF_H + +/* Define this if your system has an ANSI-conforming file. + */ +#define HAVE_STDLIB_H + +/* Define this if your system does not have an ANSI/SysV , + * but does have a BSD-style . + */ +#undef NEED_BSD_STRINGS + +/* Define this if your system does not provide typedef size_t in any of the + * ANSI-standard places (stddef.h, stdlib.h, or stdio.h), but places it in + * instead. + */ +#undef NEED_SYS_TYPES_H + +/* For 80x86 machines, you need to define NEED_FAR_POINTERS, + * unless you are using a large-data memory model or 80386 flat-memory mode. + * On less brain-damaged CPUs this symbol must not be defined. + * (Defining this symbol causes large data structures to be referenced through + * "far" pointers and to be allocated with a special version of malloc.) + */ +#undef NEED_FAR_POINTERS + +/* Define this if your linker needs global names to be unique in less + * than the first 15 characters. + */ +#undef NEED_SHORT_EXTERNAL_NAMES + +/* Although a real ANSI C compiler can deal perfectly well with pointers to + * unspecified structures (see "incomplete types" in the spec), a few pre-ANSI + * and pseudo-ANSI compilers get confused. To keep one of these bozos happy, + * define INCOMPLETE_TYPES_BROKEN. This is not recommended unless you + * actually get "missing structure definition" warnings or errors while + * compiling the JPEG code. + */ +#undef INCOMPLETE_TYPES_BROKEN + + +/* + * The following options affect code selection within the JPEG library, + * but they don't need to be visible to applications using the library. + * To minimize application namespace pollution, the symbols won't be + * defined unless JPEG_INTERNALS has been defined. + */ + +#ifdef JPEG_INTERNALS + +/* Define this if your compiler implements ">>" on signed values as a logical + * (unsigned) shift; leave it undefined if ">>" is a signed (arithmetic) shift, + * which is the normal and rational definition. + */ +#undef RIGHT_SHIFT_IS_UNSIGNED + + +#endif /* JPEG_INTERNALS */ + + +/* + * The remaining options do not affect the JPEG library proper, + * but only the sample applications cjpeg/djpeg (see cjpeg.c, djpeg.c). + * Other applications can ignore these. + */ + +#ifdef JPEG_CJPEG_DJPEG + +/* These defines indicate which image (non-JPEG) file formats are allowed. */ + +#define BMP_SUPPORTED /* BMP image file format */ +#define GIF_SUPPORTED /* GIF image file format */ +#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */ +#undef RLE_SUPPORTED /* Utah RLE image file format */ +#define TARGA_SUPPORTED /* Targa image file format */ + +/* Define this if you want to name both input and output files on the command + * line, rather than using stdout and optionally stdin. You MUST do this if + * your system can't cope with binary I/O to stdin/stdout. See comments at + * head of cjpeg.c or djpeg.c. + */ +#undef TWO_FILE_COMMANDLINE + +/* Define this if your system needs explicit cleanup of temporary files. + * This is crucial under MS-DOS, where the temporary "files" may be areas + * of extended memory; on most other systems it's not as important. + */ +#undef NEED_SIGNAL_CATCHER + +/* By default, we open image files with fopen(...,"rb") or fopen(...,"wb"). + * This is necessary on systems that distinguish text files from binary files, + * and is harmless on most systems that don't. If you have one of the rare + * systems that complains about the "b" spec, define this symbol. + */ +#undef DONT_USE_B_MODE + +/* Define this if you want percent-done progress reports from cjpeg/djpeg. + */ +#undef PROGRESS_REPORT + + +#endif /* JPEG_CJPEG_DJPEG */ diff --git a/mk4/modimage/jpeg-6b/jconfig.mac b/mk4/modimage/jpeg-6b/jconfig.mac new file mode 100644 index 0000000..0de3efe --- /dev/null +++ b/mk4/modimage/jpeg-6b/jconfig.mac @@ -0,0 +1,43 @@ +/* jconfig.mac --- jconfig.h for CodeWarrior on Apple Macintosh */ +/* see jconfig.doc for explanations */ + +#define HAVE_PROTOTYPES +#define HAVE_UNSIGNED_CHAR +#define HAVE_UNSIGNED_SHORT +/* #define void char */ +/* #define const */ +#undef CHAR_IS_UNSIGNED +#define HAVE_STDDEF_H +#define HAVE_STDLIB_H +#undef NEED_BSD_STRINGS +#undef NEED_SYS_TYPES_H +#undef NEED_FAR_POINTERS +#undef NEED_SHORT_EXTERNAL_NAMES +#undef INCOMPLETE_TYPES_BROKEN + +#ifdef JPEG_INTERNALS + +#undef RIGHT_SHIFT_IS_UNSIGNED + +#define USE_MAC_MEMMGR /* Define this if you use jmemmac.c */ + +#define ALIGN_TYPE long /* Needed for 680x0 Macs */ + +#endif /* JPEG_INTERNALS */ + +#ifdef JPEG_CJPEG_DJPEG + +#define BMP_SUPPORTED /* BMP image file format */ +#define GIF_SUPPORTED /* GIF image file format */ +#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */ +#undef RLE_SUPPORTED /* Utah RLE image file format */ +#define TARGA_SUPPORTED /* Targa image file format */ + +#define USE_CCOMMAND /* Command line reader for Macintosh */ +#define TWO_FILE_COMMANDLINE /* Binary I/O thru stdin/stdout doesn't work */ + +#undef NEED_SIGNAL_CATCHER +#undef DONT_USE_B_MODE +#undef PROGRESS_REPORT /* optional */ + +#endif /* JPEG_CJPEG_DJPEG */ diff --git a/mk4/modimage/jpeg-6b/jconfig.manx b/mk4/modimage/jpeg-6b/jconfig.manx new file mode 100644 index 0000000..6dd0d00 --- /dev/null +++ b/mk4/modimage/jpeg-6b/jconfig.manx @@ -0,0 +1,43 @@ +/* jconfig.manx --- jconfig.h for Amiga systems using Manx Aztec C ver 5.x. */ +/* see jconfig.doc for explanations */ + +#define HAVE_PROTOTYPES +#define HAVE_UNSIGNED_CHAR +#define HAVE_UNSIGNED_SHORT +/* #define void char */ +/* #define const */ +#undef CHAR_IS_UNSIGNED +#define HAVE_STDDEF_H +#define HAVE_STDLIB_H +#undef NEED_BSD_STRINGS +#undef NEED_SYS_TYPES_H +#undef NEED_FAR_POINTERS +#undef NEED_SHORT_EXTERNAL_NAMES +#undef INCOMPLETE_TYPES_BROKEN + +#ifdef JPEG_INTERNALS + +#undef RIGHT_SHIFT_IS_UNSIGNED + +#define TEMP_DIRECTORY "JPEGTMP:" /* recommended setting for Amiga */ + +#define SHORTxSHORT_32 /* produces better DCT code with Aztec C */ + +#endif /* JPEG_INTERNALS */ + +#ifdef JPEG_CJPEG_DJPEG + +#define BMP_SUPPORTED /* BMP image file format */ +#define GIF_SUPPORTED /* GIF image file format */ +#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */ +#undef RLE_SUPPORTED /* Utah RLE image file format */ +#define TARGA_SUPPORTED /* Targa image file format */ + +#define TWO_FILE_COMMANDLINE +#define NEED_SIGNAL_CATCHER +#undef DONT_USE_B_MODE +#undef PROGRESS_REPORT /* optional */ + +#define signal_catcher _abort /* hack for Aztec C naming requirements */ + +#endif /* JPEG_CJPEG_DJPEG */ diff --git a/mk4/modimage/jpeg-6b/jconfig.mc6 b/mk4/modimage/jpeg-6b/jconfig.mc6 new file mode 100644 index 0000000..c55082d --- /dev/null +++ b/mk4/modimage/jpeg-6b/jconfig.mc6 @@ -0,0 +1,52 @@ +/* jconfig.mc6 --- jconfig.h for Microsoft C on MS-DOS, version 6.00A & up. */ +/* see jconfig.doc for explanations */ + +#define HAVE_PROTOTYPES +#define HAVE_UNSIGNED_CHAR +#define HAVE_UNSIGNED_SHORT +/* #define void char */ +/* #define const */ +#undef CHAR_IS_UNSIGNED +#define HAVE_STDDEF_H +#define HAVE_STDLIB_H +#undef NEED_BSD_STRINGS +#undef NEED_SYS_TYPES_H +#define NEED_FAR_POINTERS /* for small or medium memory model */ +#undef NEED_SHORT_EXTERNAL_NAMES +#undef INCOMPLETE_TYPES_BROKEN + +#ifdef JPEG_INTERNALS + +#undef RIGHT_SHIFT_IS_UNSIGNED + +#define USE_MSDOS_MEMMGR /* Define this if you use jmemdos.c */ + +#define MAX_ALLOC_CHUNK 65520L /* Maximum request to malloc() */ + +#define USE_FMEM /* Microsoft has _fmemcpy() and _fmemset() */ + +#define NEED_FHEAPMIN /* far heap management routines are broken */ + +#define SHORTxLCONST_32 /* enable compiler-specific DCT optimization */ +/* Note: the above define is known to improve the code with Microsoft C 6.00A. + * I do not know whether it is good for later compiler versions. + * Please report any info on this point to jpeg-info@uunet.uu.net. + */ + +#endif /* JPEG_INTERNALS */ + +#ifdef JPEG_CJPEG_DJPEG + +#define BMP_SUPPORTED /* BMP image file format */ +#define GIF_SUPPORTED /* GIF image file format */ +#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */ +#undef RLE_SUPPORTED /* Utah RLE image file format */ +#define TARGA_SUPPORTED /* Targa image file format */ + +#define TWO_FILE_COMMANDLINE +#define USE_SETMODE /* Microsoft has setmode() */ +#define NEED_SIGNAL_CATCHER /* Define this if you use jmemdos.c */ +#undef DONT_USE_B_MODE +#undef PROGRESS_REPORT /* optional */ + +#endif /* JPEG_CJPEG_DJPEG */ diff --git a/mk4/modimage/jpeg-6b/jconfig.sas b/mk4/modimage/jpeg-6b/jconfig.sas new file mode 100644 index 0000000..efdac22 --- /dev/null +++ b/mk4/modimage/jpeg-6b/jconfig.sas @@ -0,0 +1,43 @@ +/* jconfig.sas --- jconfig.h for Amiga systems using SAS C 6.0 and up. */ +/* see jconfig.doc for explanations */ + +#define HAVE_PROTOTYPES +#define HAVE_UNSIGNED_CHAR +#define HAVE_UNSIGNED_SHORT +/* #define void char */ +/* #define const */ +#undef CHAR_IS_UNSIGNED +#define HAVE_STDDEF_H +#define HAVE_STDLIB_H +#undef NEED_BSD_STRINGS +#undef NEED_SYS_TYPES_H +#undef NEED_FAR_POINTERS +#undef NEED_SHORT_EXTERNAL_NAMES +#undef INCOMPLETE_TYPES_BROKEN + +#ifdef JPEG_INTERNALS + +#undef RIGHT_SHIFT_IS_UNSIGNED + +#define TEMP_DIRECTORY "JPEGTMP:" /* recommended setting for Amiga */ + +#define NO_MKTEMP /* SAS C doesn't have mktemp() */ + +#define SHORTxSHORT_32 /* produces better DCT code with SAS C */ + +#endif /* JPEG_INTERNALS */ + +#ifdef JPEG_CJPEG_DJPEG + +#define BMP_SUPPORTED /* BMP image file format */ +#define GIF_SUPPORTED /* GIF image file format */ +#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */ +#undef RLE_SUPPORTED /* Utah RLE image file format */ +#define TARGA_SUPPORTED /* Targa image file format */ + +#define TWO_FILE_COMMANDLINE +#define NEED_SIGNAL_CATCHER +#undef DONT_USE_B_MODE +#undef PROGRESS_REPORT /* optional */ + +#endif /* JPEG_CJPEG_DJPEG */ diff --git a/mk4/modimage/jpeg-6b/jconfig.st b/mk4/modimage/jpeg-6b/jconfig.st new file mode 100644 index 0000000..4421b7a --- /dev/null +++ b/mk4/modimage/jpeg-6b/jconfig.st @@ -0,0 +1,42 @@ +/* jconfig.st --- jconfig.h for Atari ST/STE/TT using Pure C or Turbo C. */ +/* see jconfig.doc for explanations */ + +#define HAVE_PROTOTYPES +#define HAVE_UNSIGNED_CHAR +#define HAVE_UNSIGNED_SHORT +/* #define void char */ +/* #define const */ +#undef CHAR_IS_UNSIGNED +#define HAVE_STDDEF_H +#define HAVE_STDLIB_H +#undef NEED_BSD_STRINGS +#undef NEED_SYS_TYPES_H +#undef NEED_FAR_POINTERS +#undef NEED_SHORT_EXTERNAL_NAMES +#define INCOMPLETE_TYPES_BROKEN /* suppress undefined-structure warnings */ + +#ifdef JPEG_INTERNALS + +#undef RIGHT_SHIFT_IS_UNSIGNED + +#define ALIGN_TYPE long /* apparently double is a weird size? */ + +#endif /* JPEG_INTERNALS */ + +#ifdef JPEG_CJPEG_DJPEG + +#define BMP_SUPPORTED /* BMP image file format */ +#define GIF_SUPPORTED /* GIF image file format */ +#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */ +#undef RLE_SUPPORTED /* Utah RLE image file format */ +#define TARGA_SUPPORTED /* Targa image file format */ + +#define TWO_FILE_COMMANDLINE /* optional -- undef if you like Unix style */ +/* Note: if you undef TWO_FILE_COMMANDLINE, you may need to define + * USE_SETMODE. Some Atari compilers require it, some do not. + */ +#define NEED_SIGNAL_CATCHER /* needed if you use jmemname.c */ +#undef DONT_USE_B_MODE +#undef PROGRESS_REPORT /* optional */ + +#endif /* JPEG_CJPEG_DJPEG */ diff --git a/mk4/modimage/jpeg-6b/jconfig.vc b/mk4/modimage/jpeg-6b/jconfig.vc new file mode 100644 index 0000000..7e291c7 --- /dev/null +++ b/mk4/modimage/jpeg-6b/jconfig.vc @@ -0,0 +1,45 @@ +/* jconfig.vc --- jconfig.h for Microsoft Visual C++ on Windows 95 or NT. */ +/* see jconfig.doc for explanations */ + +#define HAVE_PROTOTYPES +#define HAVE_UNSIGNED_CHAR +#define HAVE_UNSIGNED_SHORT +/* #define void char */ +/* #define const */ +#undef CHAR_IS_UNSIGNED +#define HAVE_STDDEF_H +#define HAVE_STDLIB_H +#undef NEED_BSD_STRINGS +#undef NEED_SYS_TYPES_H +#undef NEED_FAR_POINTERS /* we presume a 32-bit flat memory model */ +#undef NEED_SHORT_EXTERNAL_NAMES +#undef INCOMPLETE_TYPES_BROKEN + +/* Define "boolean" as unsigned char, not int, per Windows custom */ +#ifndef __RPCNDR_H__ /* don't conflict if rpcndr.h already read */ +typedef unsigned char boolean; +#endif +#define HAVE_BOOLEAN /* prevent jmorecfg.h from redefining it */ + + +#ifdef JPEG_INTERNALS + +#undef RIGHT_SHIFT_IS_UNSIGNED + +#endif /* JPEG_INTERNALS */ + +#ifdef JPEG_CJPEG_DJPEG + +#define BMP_SUPPORTED /* BMP image file format */ +#define GIF_SUPPORTED /* GIF image file format */ +#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */ +#undef RLE_SUPPORTED /* Utah RLE image file format */ +#define TARGA_SUPPORTED /* Targa image file format */ + +#define TWO_FILE_COMMANDLINE /* optional */ +#define USE_SETMODE /* Microsoft has setmode() */ +#undef NEED_SIGNAL_CATCHER +#undef DONT_USE_B_MODE +#undef PROGRESS_REPORT /* optional */ + +#endif /* JPEG_CJPEG_DJPEG */ diff --git a/mk4/modimage/jpeg-6b/jconfig.vms b/mk4/modimage/jpeg-6b/jconfig.vms new file mode 100644 index 0000000..55a6ffb --- /dev/null +++ b/mk4/modimage/jpeg-6b/jconfig.vms @@ -0,0 +1,37 @@ +/* jconfig.vms --- jconfig.h for use on Digital VMS. */ +/* see jconfig.doc for explanations */ + +#define HAVE_PROTOTYPES +#define HAVE_UNSIGNED_CHAR +#define HAVE_UNSIGNED_SHORT +/* #define void char */ +/* #define const */ +#undef CHAR_IS_UNSIGNED +#define HAVE_STDDEF_H +#define HAVE_STDLIB_H +#undef NEED_BSD_STRINGS +#undef NEED_SYS_TYPES_H +#undef NEED_FAR_POINTERS +#undef NEED_SHORT_EXTERNAL_NAMES +#undef INCOMPLETE_TYPES_BROKEN + +#ifdef JPEG_INTERNALS + +#undef RIGHT_SHIFT_IS_UNSIGNED + +#endif /* JPEG_INTERNALS */ + +#ifdef JPEG_CJPEG_DJPEG + +#define BMP_SUPPORTED /* BMP image file format */ +#define GIF_SUPPORTED /* GIF image file format */ +#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */ +#undef RLE_SUPPORTED /* Utah RLE image file format */ +#define TARGA_SUPPORTED /* Targa image file format */ + +#define TWO_FILE_COMMANDLINE /* Needed on VMS */ +#undef NEED_SIGNAL_CATCHER +#undef DONT_USE_B_MODE +#undef PROGRESS_REPORT /* optional */ + +#endif /* JPEG_CJPEG_DJPEG */ diff --git a/mk4/modimage/jpeg-6b/jconfig.wat b/mk4/modimage/jpeg-6b/jconfig.wat new file mode 100644 index 0000000..6cc545b --- /dev/null +++ b/mk4/modimage/jpeg-6b/jconfig.wat @@ -0,0 +1,38 @@ +/* jconfig.wat --- jconfig.h for Watcom C/C++ on MS-DOS or OS/2. */ +/* see jconfig.doc for explanations */ + +#define HAVE_PROTOTYPES +#define HAVE_UNSIGNED_CHAR +#define HAVE_UNSIGNED_SHORT +/* #define void char */ +/* #define const */ +#define CHAR_IS_UNSIGNED +#define HAVE_STDDEF_H +#define HAVE_STDLIB_H +#undef NEED_BSD_STRINGS +#undef NEED_SYS_TYPES_H +#undef NEED_FAR_POINTERS /* Watcom uses flat 32-bit addressing */ +#undef NEED_SHORT_EXTERNAL_NAMES +#undef INCOMPLETE_TYPES_BROKEN + +#ifdef JPEG_INTERNALS + +#undef RIGHT_SHIFT_IS_UNSIGNED + +#endif /* JPEG_INTERNALS */ + +#ifdef JPEG_CJPEG_DJPEG + +#define BMP_SUPPORTED /* BMP image file format */ +#define GIF_SUPPORTED /* GIF image file format */ +#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */ +#undef RLE_SUPPORTED /* Utah RLE image file format */ +#define TARGA_SUPPORTED /* Targa image file format */ + +#undef TWO_FILE_COMMANDLINE /* optional */ +#define USE_SETMODE /* Needed to make one-file style work in Watcom */ +#undef NEED_SIGNAL_CATCHER /* Define this if you use jmemname.c */ +#undef DONT_USE_B_MODE +#undef PROGRESS_REPORT /* optional */ + +#endif /* JPEG_CJPEG_DJPEG */ diff --git a/mk4/modimage/jpeg-6b/jcparam.c b/mk4/modimage/jpeg-6b/jcparam.c new file mode 100644 index 0000000..6fc48f5 --- /dev/null +++ b/mk4/modimage/jpeg-6b/jcparam.c @@ -0,0 +1,610 @@ +/* + * jcparam.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains optional default-setting code for the JPEG compressor. + * Applications do not have to use this file, but those that don't use it + * must know a lot more about the innards of the JPEG code. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * Quantization table setup routines + */ + +GLOBAL(void) +jpeg_add_quant_table (j_compress_ptr cinfo, int which_tbl, + const unsigned int *basic_table, + int scale_factor, boolean force_baseline) +/* Define a quantization table equal to the basic_table times + * a scale factor (given as a percentage). + * If force_baseline is TRUE, the computed quantization table entries + * are limited to 1..255 for JPEG baseline compatibility. + */ +{ + JQUANT_TBL ** qtblptr; + int i; + long temp; + + /* Safety check to ensure start_compress not called yet. */ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + if (which_tbl < 0 || which_tbl >= NUM_QUANT_TBLS) + ERREXIT1(cinfo, JERR_DQT_INDEX, which_tbl); + + qtblptr = & cinfo->quant_tbl_ptrs[which_tbl]; + + if (*qtblptr == NULL) + *qtblptr = jpeg_alloc_quant_table((j_common_ptr) cinfo); + + for (i = 0; i < DCTSIZE2; i++) { + temp = ((long) basic_table[i] * scale_factor + 50L) / 100L; + /* limit the values to the valid range */ + if (temp <= 0L) temp = 1L; + if (temp > 32767L) temp = 32767L; /* max quantizer needed for 12 bits */ + if (force_baseline && temp > 255L) + temp = 255L; /* limit to baseline range if requested */ + (*qtblptr)->quantval[i] = (UINT16) temp; + } + + /* Initialize sent_table FALSE so table will be written to JPEG file. */ + (*qtblptr)->sent_table = FALSE; +} + + +GLOBAL(void) +jpeg_set_linear_quality (j_compress_ptr cinfo, int scale_factor, + boolean force_baseline) +/* Set or change the 'quality' (quantization) setting, using default tables + * and a straight percentage-scaling quality scale. In most cases it's better + * to use jpeg_set_quality (below); this entry point is provided for + * applications that insist on a linear percentage scaling. + */ +{ + /* These are the sample quantization tables given in JPEG spec section K.1. + * The spec says that the values given produce "good" quality, and + * when divided by 2, "very good" quality. + */ + static const unsigned int std_luminance_quant_tbl[DCTSIZE2] = { + 16, 11, 10, 16, 24, 40, 51, 61, + 12, 12, 14, 19, 26, 58, 60, 55, + 14, 13, 16, 24, 40, 57, 69, 56, + 14, 17, 22, 29, 51, 87, 80, 62, + 18, 22, 37, 56, 68, 109, 103, 77, + 24, 35, 55, 64, 81, 104, 113, 92, + 49, 64, 78, 87, 103, 121, 120, 101, + 72, 92, 95, 98, 112, 100, 103, 99 + }; + static const unsigned int std_chrominance_quant_tbl[DCTSIZE2] = { + 17, 18, 24, 47, 99, 99, 99, 99, + 18, 21, 26, 66, 99, 99, 99, 99, + 24, 26, 56, 99, 99, 99, 99, 99, + 47, 66, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99 + }; + + /* Set up two quantization tables using the specified scaling */ + jpeg_add_quant_table(cinfo, 0, std_luminance_quant_tbl, + scale_factor, force_baseline); + jpeg_add_quant_table(cinfo, 1, std_chrominance_quant_tbl, + scale_factor, force_baseline); +} + + +GLOBAL(int) +jpeg_quality_scaling (int quality) +/* Convert a user-specified quality rating to a percentage scaling factor + * for an underlying quantization table, using our recommended scaling curve. + * The input 'quality' factor should be 0 (terrible) to 100 (very good). + */ +{ + /* Safety limit on quality factor. Convert 0 to 1 to avoid zero divide. */ + if (quality <= 0) quality = 1; + if (quality > 100) quality = 100; + + /* The basic table is used as-is (scaling 100) for a quality of 50. + * Qualities 50..100 are converted to scaling percentage 200 - 2*Q; + * note that at Q=100 the scaling is 0, which will cause jpeg_add_quant_table + * to make all the table entries 1 (hence, minimum quantization loss). + * Qualities 1..50 are converted to scaling percentage 5000/Q. + */ + if (quality < 50) + quality = 5000 / quality; + else + quality = 200 - quality*2; + + return quality; +} + + +GLOBAL(void) +jpeg_set_quality (j_compress_ptr cinfo, int quality, boolean force_baseline) +/* Set or change the 'quality' (quantization) setting, using default tables. + * This is the standard quality-adjusting entry point for typical user + * interfaces; only those who want detailed control over quantization tables + * would use the preceding three routines directly. + */ +{ + /* Convert user 0-100 rating to percentage scaling */ + quality = jpeg_quality_scaling(quality); + + /* Set up standard quality tables */ + jpeg_set_linear_quality(cinfo, quality, force_baseline); +} + + +/* + * Huffman table setup routines + */ + +LOCAL(void) +add_huff_table (j_compress_ptr cinfo, + JHUFF_TBL **htblptr, const UINT8 *bits, const UINT8 *val) +/* Define a Huffman table */ +{ + int nsymbols, len; + + if (*htblptr == NULL) + *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo); + + /* Copy the number-of-symbols-of-each-code-length counts */ + MEMCOPY((*htblptr)->bits, bits, SIZEOF((*htblptr)->bits)); + + /* Validate the counts. We do this here mainly so we can copy the right + * number of symbols from the val[] array, without risking marching off + * the end of memory. jchuff.c will do a more thorough test later. + */ + nsymbols = 0; + for (len = 1; len <= 16; len++) + nsymbols += bits[len]; + if (nsymbols < 1 || nsymbols > 256) + ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); + + MEMCOPY((*htblptr)->huffval, val, nsymbols * SIZEOF(UINT8)); + + /* Initialize sent_table FALSE so table will be written to JPEG file. */ + (*htblptr)->sent_table = FALSE; +} + + +LOCAL(void) +std_huff_tables (j_compress_ptr cinfo) +/* Set up the standard Huffman tables (cf. JPEG standard section K.3) */ +/* IMPORTANT: these are only valid for 8-bit data precision! */ +{ + static const UINT8 bits_dc_luminance[17] = + { /* 0-base */ 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 }; + static const UINT8 val_dc_luminance[] = + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; + + static const UINT8 bits_dc_chrominance[17] = + { /* 0-base */ 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 }; + static const UINT8 val_dc_chrominance[] = + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; + + static const UINT8 bits_ac_luminance[17] = + { /* 0-base */ 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d }; + static const UINT8 val_ac_luminance[] = + { 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, + 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, + 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, + 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, + 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, + 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, + 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, + 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, + 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, + 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, + 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, + 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, + 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, + 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, + 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, + 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, + 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa }; + + static const UINT8 bits_ac_chrominance[17] = + { /* 0-base */ 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77 }; + static const UINT8 val_ac_chrominance[] = + { 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, + 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, + 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, + 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, + 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, + 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, + 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, + 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, + 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, + 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, + 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, + 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, + 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, + 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, + 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, + 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, + 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, + 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa }; + + add_huff_table(cinfo, &cinfo->dc_huff_tbl_ptrs[0], + bits_dc_luminance, val_dc_luminance); + add_huff_table(cinfo, &cinfo->ac_huff_tbl_ptrs[0], + bits_ac_luminance, val_ac_luminance); + add_huff_table(cinfo, &cinfo->dc_huff_tbl_ptrs[1], + bits_dc_chrominance, val_dc_chrominance); + add_huff_table(cinfo, &cinfo->ac_huff_tbl_ptrs[1], + bits_ac_chrominance, val_ac_chrominance); +} + + +/* + * Default parameter setup for compression. + * + * Applications that don't choose to use this routine must do their + * own setup of all these parameters. Alternately, you can call this + * to establish defaults and then alter parameters selectively. This + * is the recommended approach since, if we add any new parameters, + * your code will still work (they'll be set to reasonable defaults). + */ + +GLOBAL(void) +jpeg_set_defaults (j_compress_ptr cinfo) +{ + int i; + + /* Safety check to ensure start_compress not called yet. */ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + /* Allocate comp_info array large enough for maximum component count. + * Array is made permanent in case application wants to compress + * multiple images at same param settings. + */ + if (cinfo->comp_info == NULL) + cinfo->comp_info = (jpeg_component_info *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + MAX_COMPONENTS * SIZEOF(jpeg_component_info)); + + /* Initialize everything not dependent on the color space */ + + cinfo->data_precision = BITS_IN_JSAMPLE; + /* Set up two quantization tables using default quality of 75 */ + jpeg_set_quality(cinfo, 75, TRUE); + /* Set up two Huffman tables */ + std_huff_tables(cinfo); + + /* Initialize default arithmetic coding conditioning */ + for (i = 0; i < NUM_ARITH_TBLS; i++) { + cinfo->arith_dc_L[i] = 0; + cinfo->arith_dc_U[i] = 1; + cinfo->arith_ac_K[i] = 5; + } + + /* Default is no multiple-scan output */ + cinfo->scan_info = NULL; + cinfo->num_scans = 0; + + /* Expect normal source image, not raw downsampled data */ + cinfo->raw_data_in = FALSE; + + /* Use Huffman coding, not arithmetic coding, by default */ + cinfo->arith_code = FALSE; + + /* By default, don't do extra passes to optimize entropy coding */ + cinfo->optimize_coding = FALSE; + /* The standard Huffman tables are only valid for 8-bit data precision. + * If the precision is higher, force optimization on so that usable + * tables will be computed. This test can be removed if default tables + * are supplied that are valid for the desired precision. + */ + if (cinfo->data_precision > 8) + cinfo->optimize_coding = TRUE; + + /* By default, use the simpler non-cosited sampling alignment */ + cinfo->CCIR601_sampling = FALSE; + + /* No input smoothing */ + cinfo->smoothing_factor = 0; + + /* DCT algorithm preference */ + cinfo->dct_method = JDCT_DEFAULT; + + /* No restart markers */ + cinfo->restart_interval = 0; + cinfo->restart_in_rows = 0; + + /* Fill in default JFIF marker parameters. Note that whether the marker + * will actually be written is determined by jpeg_set_colorspace. + * + * By default, the library emits JFIF version code 1.01. + * An application that wants to emit JFIF 1.02 extension markers should set + * JFIF_minor_version to 2. We could probably get away with just defaulting + * to 1.02, but there may still be some decoders in use that will complain + * about that; saying 1.01 should minimize compatibility problems. + */ + cinfo->JFIF_major_version = 1; /* Default JFIF version = 1.01 */ + cinfo->JFIF_minor_version = 1; + cinfo->density_unit = 0; /* Pixel size is unknown by default */ + cinfo->X_density = 1; /* Pixel aspect ratio is square by default */ + cinfo->Y_density = 1; + + /* Choose JPEG colorspace based on input space, set defaults accordingly */ + + jpeg_default_colorspace(cinfo); +} + + +/* + * Select an appropriate JPEG colorspace for in_color_space. + */ + +GLOBAL(void) +jpeg_default_colorspace (j_compress_ptr cinfo) +{ + switch (cinfo->in_color_space) { + case JCS_GRAYSCALE: + jpeg_set_colorspace(cinfo, JCS_GRAYSCALE); + break; + case JCS_RGB: + jpeg_set_colorspace(cinfo, JCS_YCbCr); + break; + case JCS_YCbCr: + jpeg_set_colorspace(cinfo, JCS_YCbCr); + break; + case JCS_CMYK: + jpeg_set_colorspace(cinfo, JCS_CMYK); /* By default, no translation */ + break; + case JCS_YCCK: + jpeg_set_colorspace(cinfo, JCS_YCCK); + break; + case JCS_UNKNOWN: + jpeg_set_colorspace(cinfo, JCS_UNKNOWN); + break; + default: + ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE); + } +} + + +/* + * Set the JPEG colorspace, and choose colorspace-dependent default values. + */ + +GLOBAL(void) +jpeg_set_colorspace (j_compress_ptr cinfo, J_COLOR_SPACE colorspace) +{ + jpeg_component_info * compptr; + int ci; + +#define SET_COMP(index,id,hsamp,vsamp,quant,dctbl,actbl) \ + (compptr = &cinfo->comp_info[index], \ + compptr->component_id = (id), \ + compptr->h_samp_factor = (hsamp), \ + compptr->v_samp_factor = (vsamp), \ + compptr->quant_tbl_no = (quant), \ + compptr->dc_tbl_no = (dctbl), \ + compptr->ac_tbl_no = (actbl) ) + + /* Safety check to ensure start_compress not called yet. */ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + /* For all colorspaces, we use Q and Huff tables 0 for luminance components, + * tables 1 for chrominance components. + */ + + cinfo->jpeg_color_space = colorspace; + + cinfo->write_JFIF_header = FALSE; /* No marker for non-JFIF colorspaces */ + cinfo->write_Adobe_marker = FALSE; /* write no Adobe marker by default */ + + switch (colorspace) { + case JCS_GRAYSCALE: + cinfo->write_JFIF_header = TRUE; /* Write a JFIF marker */ + cinfo->num_components = 1; + /* JFIF specifies component ID 1 */ + SET_COMP(0, 1, 1,1, 0, 0,0); + break; + case JCS_RGB: + cinfo->write_Adobe_marker = TRUE; /* write Adobe marker to flag RGB */ + cinfo->num_components = 3; + SET_COMP(0, 0x52 /* 'R' */, 1,1, 0, 0,0); + SET_COMP(1, 0x47 /* 'G' */, 1,1, 0, 0,0); + SET_COMP(2, 0x42 /* 'B' */, 1,1, 0, 0,0); + break; + case JCS_YCbCr: + cinfo->write_JFIF_header = TRUE; /* Write a JFIF marker */ + cinfo->num_components = 3; + /* JFIF specifies component IDs 1,2,3 */ + /* We default to 2x2 subsamples of chrominance */ + SET_COMP(0, 1, 2,2, 0, 0,0); + SET_COMP(1, 2, 1,1, 1, 1,1); + SET_COMP(2, 3, 1,1, 1, 1,1); + break; + case JCS_CMYK: + cinfo->write_Adobe_marker = TRUE; /* write Adobe marker to flag CMYK */ + cinfo->num_components = 4; + SET_COMP(0, 0x43 /* 'C' */, 1,1, 0, 0,0); + SET_COMP(1, 0x4D /* 'M' */, 1,1, 0, 0,0); + SET_COMP(2, 0x59 /* 'Y' */, 1,1, 0, 0,0); + SET_COMP(3, 0x4B /* 'K' */, 1,1, 0, 0,0); + break; + case JCS_YCCK: + cinfo->write_Adobe_marker = TRUE; /* write Adobe marker to flag YCCK */ + cinfo->num_components = 4; + SET_COMP(0, 1, 2,2, 0, 0,0); + SET_COMP(1, 2, 1,1, 1, 1,1); + SET_COMP(2, 3, 1,1, 1, 1,1); + SET_COMP(3, 4, 2,2, 0, 0,0); + break; + case JCS_UNKNOWN: + cinfo->num_components = cinfo->input_components; + if (cinfo->num_components < 1 || cinfo->num_components > MAX_COMPONENTS) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components, + MAX_COMPONENTS); + for (ci = 0; ci < cinfo->num_components; ci++) { + SET_COMP(ci, ci, 1,1, 0, 0,0); + } + break; + default: + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + } +} + + +#ifdef C_PROGRESSIVE_SUPPORTED + +LOCAL(jpeg_scan_info *) +fill_a_scan (jpeg_scan_info * scanptr, int ci, + int Ss, int Se, int Ah, int Al) +/* Support routine: generate one scan for specified component */ +{ + scanptr->comps_in_scan = 1; + scanptr->component_index[0] = ci; + scanptr->Ss = Ss; + scanptr->Se = Se; + scanptr->Ah = Ah; + scanptr->Al = Al; + scanptr++; + return scanptr; +} + +LOCAL(jpeg_scan_info *) +fill_scans (jpeg_scan_info * scanptr, int ncomps, + int Ss, int Se, int Ah, int Al) +/* Support routine: generate one scan for each component */ +{ + int ci; + + for (ci = 0; ci < ncomps; ci++) { + scanptr->comps_in_scan = 1; + scanptr->component_index[0] = ci; + scanptr->Ss = Ss; + scanptr->Se = Se; + scanptr->Ah = Ah; + scanptr->Al = Al; + scanptr++; + } + return scanptr; +} + +LOCAL(jpeg_scan_info *) +fill_dc_scans (jpeg_scan_info * scanptr, int ncomps, int Ah, int Al) +/* Support routine: generate interleaved DC scan if possible, else N scans */ +{ + int ci; + + if (ncomps <= MAX_COMPS_IN_SCAN) { + /* Single interleaved DC scan */ + scanptr->comps_in_scan = ncomps; + for (ci = 0; ci < ncomps; ci++) + scanptr->component_index[ci] = ci; + scanptr->Ss = scanptr->Se = 0; + scanptr->Ah = Ah; + scanptr->Al = Al; + scanptr++; + } else { + /* Noninterleaved DC scan for each component */ + scanptr = fill_scans(scanptr, ncomps, 0, 0, Ah, Al); + } + return scanptr; +} + + +/* + * Create a recommended progressive-JPEG script. + * cinfo->num_components and cinfo->jpeg_color_space must be correct. + */ + +GLOBAL(void) +jpeg_simple_progression (j_compress_ptr cinfo) +{ + int ncomps = cinfo->num_components; + int nscans; + jpeg_scan_info * scanptr; + + /* Safety check to ensure start_compress not called yet. */ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + /* Figure space needed for script. Calculation must match code below! */ + if (ncomps == 3 && cinfo->jpeg_color_space == JCS_YCbCr) { + /* Custom script for YCbCr color images. */ + nscans = 10; + } else { + /* All-purpose script for other color spaces. */ + if (ncomps > MAX_COMPS_IN_SCAN) + nscans = 6 * ncomps; /* 2 DC + 4 AC scans per component */ + else + nscans = 2 + 4 * ncomps; /* 2 DC scans; 4 AC scans per component */ + } + + /* Allocate space for script. + * We need to put it in the permanent pool in case the application performs + * multiple compressions without changing the settings. To avoid a memory + * leak if jpeg_simple_progression is called repeatedly for the same JPEG + * object, we try to re-use previously allocated space, and we allocate + * enough space to handle YCbCr even if initially asked for grayscale. + */ + if (cinfo->script_space == NULL || cinfo->script_space_size < nscans) { + cinfo->script_space_size = MAX(nscans, 10); + cinfo->script_space = (jpeg_scan_info *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + cinfo->script_space_size * SIZEOF(jpeg_scan_info)); + } + scanptr = cinfo->script_space; + cinfo->scan_info = scanptr; + cinfo->num_scans = nscans; + + if (ncomps == 3 && cinfo->jpeg_color_space == JCS_YCbCr) { + /* Custom script for YCbCr color images. */ + /* Initial DC scan */ + scanptr = fill_dc_scans(scanptr, ncomps, 0, 1); + /* Initial AC scan: get some luma data out in a hurry */ + scanptr = fill_a_scan(scanptr, 0, 1, 5, 0, 2); + /* Chroma data is too small to be worth expending many scans on */ + scanptr = fill_a_scan(scanptr, 2, 1, 63, 0, 1); + scanptr = fill_a_scan(scanptr, 1, 1, 63, 0, 1); + /* Complete spectral selection for luma AC */ + scanptr = fill_a_scan(scanptr, 0, 6, 63, 0, 2); + /* Refine next bit of luma AC */ + scanptr = fill_a_scan(scanptr, 0, 1, 63, 2, 1); + /* Finish DC successive approximation */ + scanptr = fill_dc_scans(scanptr, ncomps, 1, 0); + /* Finish AC successive approximation */ + scanptr = fill_a_scan(scanptr, 2, 1, 63, 1, 0); + scanptr = fill_a_scan(scanptr, 1, 1, 63, 1, 0); + /* Luma bottom bit comes last since it's usually largest scan */ + scanptr = fill_a_scan(scanptr, 0, 1, 63, 1, 0); + } else { + /* All-purpose script for other color spaces. */ + /* Successive approximation first pass */ + scanptr = fill_dc_scans(scanptr, ncomps, 0, 1); + scanptr = fill_scans(scanptr, ncomps, 1, 5, 0, 2); + scanptr = fill_scans(scanptr, ncomps, 6, 63, 0, 2); + /* Successive approximation second pass */ + scanptr = fill_scans(scanptr, ncomps, 1, 63, 2, 1); + /* Successive approximation final pass */ + scanptr = fill_dc_scans(scanptr, ncomps, 1, 0); + scanptr = fill_scans(scanptr, ncomps, 1, 63, 1, 0); + } +} + +#endif /* C_PROGRESSIVE_SUPPORTED */ diff --git a/mk4/modimage/jpeg-6b/jcphuff.c b/mk4/modimage/jpeg-6b/jcphuff.c new file mode 100644 index 0000000..07f9178 --- /dev/null +++ b/mk4/modimage/jpeg-6b/jcphuff.c @@ -0,0 +1,833 @@ +/* + * jcphuff.c + * + * Copyright (C) 1995-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains Huffman entropy encoding routines for progressive JPEG. + * + * We do not support output suspension in this module, since the library + * currently does not allow multiple-scan files to be written with output + * suspension. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jchuff.h" /* Declarations shared with jchuff.c */ + +#ifdef C_PROGRESSIVE_SUPPORTED + +/* Expanded entropy encoder object for progressive Huffman encoding. */ + +typedef struct { + struct jpeg_entropy_encoder pub; /* public fields */ + + /* Mode flag: TRUE for optimization, FALSE for actual data output */ + boolean gather_statistics; + + /* Bit-level coding status. + * next_output_byte/free_in_buffer are local copies of cinfo->dest fields. + */ + JOCTET * next_output_byte; /* => next byte to write in buffer */ + size_t free_in_buffer; /* # of byte spaces remaining in buffer */ + INT32 put_buffer; /* current bit-accumulation buffer */ + int put_bits; /* # of bits now in it */ + j_compress_ptr cinfo; /* link to cinfo (needed for dump_buffer) */ + + /* Coding status for DC components */ + int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */ + + /* Coding status for AC components */ + int ac_tbl_no; /* the table number of the single component */ + unsigned int EOBRUN; /* run length of EOBs */ + unsigned int BE; /* # of buffered correction bits before MCU */ + char * bit_buffer; /* buffer for correction bits (1 per char) */ + /* packing correction bits tightly would save some space but cost time... */ + + unsigned int restarts_to_go; /* MCUs left in this restart interval */ + int next_restart_num; /* next restart number to write (0-7) */ + + /* Pointers to derived tables (these workspaces have image lifespan). + * Since any one scan codes only DC or only AC, we only need one set + * of tables, not one for DC and one for AC. + */ + c_derived_tbl * derived_tbls[NUM_HUFF_TBLS]; + + /* Statistics tables for optimization; again, one set is enough */ + long * count_ptrs[NUM_HUFF_TBLS]; +} phuff_entropy_encoder; + +typedef phuff_entropy_encoder * phuff_entropy_ptr; + +/* MAX_CORR_BITS is the number of bits the AC refinement correction-bit + * buffer can hold. Larger sizes may slightly improve compression, but + * 1000 is already well into the realm of overkill. + * The minimum safe size is 64 bits. + */ + +#define MAX_CORR_BITS 1000 /* Max # of correction bits I can buffer */ + +/* IRIGHT_SHIFT is like RIGHT_SHIFT, but works on int rather than INT32. + * We assume that int right shift is unsigned if INT32 right shift is, + * which should be safe. + */ + +#ifdef RIGHT_SHIFT_IS_UNSIGNED +#define ISHIFT_TEMPS int ishift_temp; +#define IRIGHT_SHIFT(x,shft) \ + ((ishift_temp = (x)) < 0 ? \ + (ishift_temp >> (shft)) | ((~0) << (16-(shft))) : \ + (ishift_temp >> (shft))) +#else +#define ISHIFT_TEMPS +#define IRIGHT_SHIFT(x,shft) ((x) >> (shft)) +#endif + +/* Forward declarations */ +METHODDEF(boolean) encode_mcu_DC_first JPP((j_compress_ptr cinfo, + JBLOCKROW *MCU_data)); +METHODDEF(boolean) encode_mcu_AC_first JPP((j_compress_ptr cinfo, + JBLOCKROW *MCU_data)); +METHODDEF(boolean) encode_mcu_DC_refine JPP((j_compress_ptr cinfo, + JBLOCKROW *MCU_data)); +METHODDEF(boolean) encode_mcu_AC_refine JPP((j_compress_ptr cinfo, + JBLOCKROW *MCU_data)); +METHODDEF(void) finish_pass_phuff JPP((j_compress_ptr cinfo)); +METHODDEF(void) finish_pass_gather_phuff JPP((j_compress_ptr cinfo)); + + +/* + * Initialize for a Huffman-compressed scan using progressive JPEG. + */ + +METHODDEF(void) +start_pass_phuff (j_compress_ptr cinfo, boolean gather_statistics) +{ + phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; + boolean is_DC_band; + int ci, tbl; + jpeg_component_info * compptr; + + entropy->cinfo = cinfo; + entropy->gather_statistics = gather_statistics; + + is_DC_band = (cinfo->Ss == 0); + + /* We assume jcmaster.c already validated the scan parameters. */ + + /* Select execution routines */ + if (cinfo->Ah == 0) { + if (is_DC_band) + entropy->pub.encode_mcu = encode_mcu_DC_first; + else + entropy->pub.encode_mcu = encode_mcu_AC_first; + } else { + if (is_DC_band) + entropy->pub.encode_mcu = encode_mcu_DC_refine; + else { + entropy->pub.encode_mcu = encode_mcu_AC_refine; + /* AC refinement needs a correction bit buffer */ + if (entropy->bit_buffer == NULL) + entropy->bit_buffer = (char *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + MAX_CORR_BITS * SIZEOF(char)); + } + } + if (gather_statistics) + entropy->pub.finish_pass = finish_pass_gather_phuff; + else + entropy->pub.finish_pass = finish_pass_phuff; + + /* Only DC coefficients may be interleaved, so cinfo->comps_in_scan = 1 + * for AC coefficients. + */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* Initialize DC predictions to 0 */ + entropy->last_dc_val[ci] = 0; + /* Get table index */ + if (is_DC_band) { + if (cinfo->Ah != 0) /* DC refinement needs no table */ + continue; + tbl = compptr->dc_tbl_no; + } else { + entropy->ac_tbl_no = tbl = compptr->ac_tbl_no; + } + if (gather_statistics) { + /* Check for invalid table index */ + /* (make_c_derived_tbl does this in the other path) */ + if (tbl < 0 || tbl >= NUM_HUFF_TBLS) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tbl); + /* Allocate and zero the statistics tables */ + /* Note that jpeg_gen_optimal_table expects 257 entries in each table! */ + if (entropy->count_ptrs[tbl] == NULL) + entropy->count_ptrs[tbl] = (long *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + 257 * SIZEOF(long)); + MEMZERO(entropy->count_ptrs[tbl], 257 * SIZEOF(long)); + } else { + /* Compute derived values for Huffman table */ + /* We may do this more than once for a table, but it's not expensive */ + jpeg_make_c_derived_tbl(cinfo, is_DC_band, tbl, + & entropy->derived_tbls[tbl]); + } + } + + /* Initialize AC stuff */ + entropy->EOBRUN = 0; + entropy->BE = 0; + + /* Initialize bit buffer to empty */ + entropy->put_buffer = 0; + entropy->put_bits = 0; + + /* Initialize restart stuff */ + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num = 0; +} + + +/* Outputting bytes to the file. + * NB: these must be called only when actually outputting, + * that is, entropy->gather_statistics == FALSE. + */ + +/* Emit a byte */ +#define emit_byte(entropy,val) \ + { *(entropy)->next_output_byte++ = (JOCTET) (val); \ + if (--(entropy)->free_in_buffer == 0) \ + dump_buffer(entropy); } + + +LOCAL(void) +dump_buffer (phuff_entropy_ptr entropy) +/* Empty the output buffer; we do not support suspension in this module. */ +{ + struct jpeg_destination_mgr * dest = entropy->cinfo->dest; + + if (! (*dest->empty_output_buffer) (entropy->cinfo)) + ERREXIT(entropy->cinfo, JERR_CANT_SUSPEND); + /* After a successful buffer dump, must reset buffer pointers */ + entropy->next_output_byte = dest->next_output_byte; + entropy->free_in_buffer = dest->free_in_buffer; +} + + +/* Outputting bits to the file */ + +/* Only the right 24 bits of put_buffer are used; the valid bits are + * left-justified in this part. At most 16 bits can be passed to emit_bits + * in one call, and we never retain more than 7 bits in put_buffer + * between calls, so 24 bits are sufficient. + */ + +INLINE +LOCAL(void) +emit_bits (phuff_entropy_ptr entropy, unsigned int code, int size) +/* Emit some bits, unless we are in gather mode */ +{ + /* This routine is heavily used, so it's worth coding tightly. */ + register INT32 put_buffer = (INT32) code; + register int put_bits = entropy->put_bits; + + /* if size is 0, caller used an invalid Huffman table entry */ + if (size == 0) + ERREXIT(entropy->cinfo, JERR_HUFF_MISSING_CODE); + + if (entropy->gather_statistics) + return; /* do nothing if we're only getting stats */ + + put_buffer &= (((INT32) 1)<put_buffer; /* and merge with old buffer contents */ + + while (put_bits >= 8) { + int c = (int) ((put_buffer >> 16) & 0xFF); + + emit_byte(entropy, c); + if (c == 0xFF) { /* need to stuff a zero byte? */ + emit_byte(entropy, 0); + } + put_buffer <<= 8; + put_bits -= 8; + } + + entropy->put_buffer = put_buffer; /* update variables */ + entropy->put_bits = put_bits; +} + + +LOCAL(void) +flush_bits (phuff_entropy_ptr entropy) +{ + emit_bits(entropy, 0x7F, 7); /* fill any partial byte with ones */ + entropy->put_buffer = 0; /* and reset bit-buffer to empty */ + entropy->put_bits = 0; +} + + +/* + * Emit (or just count) a Huffman symbol. + */ + +INLINE +LOCAL(void) +emit_symbol (phuff_entropy_ptr entropy, int tbl_no, int symbol) +{ + if (entropy->gather_statistics) + entropy->count_ptrs[tbl_no][symbol]++; + else { + c_derived_tbl * tbl = entropy->derived_tbls[tbl_no]; + emit_bits(entropy, tbl->ehufco[symbol], tbl->ehufsi[symbol]); + } +} + + +/* + * Emit bits from a correction bit buffer. + */ + +LOCAL(void) +emit_buffered_bits (phuff_entropy_ptr entropy, char * bufstart, + unsigned int nbits) +{ + if (entropy->gather_statistics) + return; /* no real work */ + + while (nbits > 0) { + emit_bits(entropy, (unsigned int) (*bufstart), 1); + bufstart++; + nbits--; + } +} + + +/* + * Emit any pending EOBRUN symbol. + */ + +LOCAL(void) +emit_eobrun (phuff_entropy_ptr entropy) +{ + register int temp, nbits; + + if (entropy->EOBRUN > 0) { /* if there is any pending EOBRUN */ + temp = entropy->EOBRUN; + nbits = 0; + while ((temp >>= 1)) + nbits++; + /* safety check: shouldn't happen given limited correction-bit buffer */ + if (nbits > 14) + ERREXIT(entropy->cinfo, JERR_HUFF_MISSING_CODE); + + emit_symbol(entropy, entropy->ac_tbl_no, nbits << 4); + if (nbits) + emit_bits(entropy, entropy->EOBRUN, nbits); + + entropy->EOBRUN = 0; + + /* Emit any buffered correction bits */ + emit_buffered_bits(entropy, entropy->bit_buffer, entropy->BE); + entropy->BE = 0; + } +} + + +/* + * Emit a restart marker & resynchronize predictions. + */ + +LOCAL(void) +emit_restart (phuff_entropy_ptr entropy, int restart_num) +{ + int ci; + + emit_eobrun(entropy); + + if (! entropy->gather_statistics) { + flush_bits(entropy); + emit_byte(entropy, 0xFF); + emit_byte(entropy, JPEG_RST0 + restart_num); + } + + if (entropy->cinfo->Ss == 0) { + /* Re-initialize DC predictions to 0 */ + for (ci = 0; ci < entropy->cinfo->comps_in_scan; ci++) + entropy->last_dc_val[ci] = 0; + } else { + /* Re-initialize all AC-related fields to 0 */ + entropy->EOBRUN = 0; + entropy->BE = 0; + } +} + + +/* + * MCU encoding for DC initial scan (either spectral selection, + * or first pass of successive approximation). + */ + +METHODDEF(boolean) +encode_mcu_DC_first (j_compress_ptr cinfo, JBLOCKROW *MCU_data) +{ + phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; + register int temp, temp2; + register int nbits; + int blkn, ci; + int Al = cinfo->Al; + JBLOCKROW block; + jpeg_component_info * compptr; + ISHIFT_TEMPS + + entropy->next_output_byte = cinfo->dest->next_output_byte; + entropy->free_in_buffer = cinfo->dest->free_in_buffer; + + /* Emit restart marker if needed */ + if (cinfo->restart_interval) + if (entropy->restarts_to_go == 0) + emit_restart(entropy, entropy->next_restart_num); + + /* Encode the MCU data blocks */ + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + block = MCU_data[blkn]; + ci = cinfo->MCU_membership[blkn]; + compptr = cinfo->cur_comp_info[ci]; + + /* Compute the DC value after the required point transform by Al. + * This is simply an arithmetic right shift. + */ + temp2 = IRIGHT_SHIFT((int) ((*block)[0]), Al); + + /* DC differences are figured on the point-transformed values. */ + temp = temp2 - entropy->last_dc_val[ci]; + entropy->last_dc_val[ci] = temp2; + + /* Encode the DC coefficient difference per section G.1.2.1 */ + temp2 = temp; + if (temp < 0) { + temp = -temp; /* temp is abs value of input */ + /* For a negative input, want temp2 = bitwise complement of abs(input) */ + /* This code assumes we are on a two's complement machine */ + temp2--; + } + + /* Find the number of bits needed for the magnitude of the coefficient */ + nbits = 0; + while (temp) { + nbits++; + temp >>= 1; + } + /* Check for out-of-range coefficient values. + * Since we're encoding a difference, the range limit is twice as much. + */ + if (nbits > MAX_COEF_BITS+1) + ERREXIT(cinfo, JERR_BAD_DCT_COEF); + + /* Count/emit the Huffman-coded symbol for the number of bits */ + emit_symbol(entropy, compptr->dc_tbl_no, nbits); + + /* Emit that number of bits of the value, if positive, */ + /* or the complement of its magnitude, if negative. */ + if (nbits) /* emit_bits rejects calls with size 0 */ + emit_bits(entropy, (unsigned int) temp2, nbits); + } + + cinfo->dest->next_output_byte = entropy->next_output_byte; + cinfo->dest->free_in_buffer = entropy->free_in_buffer; + + /* Update restart-interval state too */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num++; + entropy->next_restart_num &= 7; + } + entropy->restarts_to_go--; + } + + return TRUE; +} + + +/* + * MCU encoding for AC initial scan (either spectral selection, + * or first pass of successive approximation). + */ + +METHODDEF(boolean) +encode_mcu_AC_first (j_compress_ptr cinfo, JBLOCKROW *MCU_data) +{ + phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; + register int temp, temp2; + register int nbits; + register int r, k; + int Se = cinfo->Se; + int Al = cinfo->Al; + JBLOCKROW block; + + entropy->next_output_byte = cinfo->dest->next_output_byte; + entropy->free_in_buffer = cinfo->dest->free_in_buffer; + + /* Emit restart marker if needed */ + if (cinfo->restart_interval) + if (entropy->restarts_to_go == 0) + emit_restart(entropy, entropy->next_restart_num); + + /* Encode the MCU data block */ + block = MCU_data[0]; + + /* Encode the AC coefficients per section G.1.2.2, fig. G.3 */ + + r = 0; /* r = run length of zeros */ + + for (k = cinfo->Ss; k <= Se; k++) { + if ((temp = (*block)[jpeg_natural_order[k]]) == 0) { + r++; + continue; + } + /* We must apply the point transform by Al. For AC coefficients this + * is an integer division with rounding towards 0. To do this portably + * in C, we shift after obtaining the absolute value; so the code is + * interwoven with finding the abs value (temp) and output bits (temp2). + */ + if (temp < 0) { + temp = -temp; /* temp is abs value of input */ + temp >>= Al; /* apply the point transform */ + /* For a negative coef, want temp2 = bitwise complement of abs(coef) */ + temp2 = ~temp; + } else { + temp >>= Al; /* apply the point transform */ + temp2 = temp; + } + /* Watch out for case that nonzero coef is zero after point transform */ + if (temp == 0) { + r++; + continue; + } + + /* Emit any pending EOBRUN */ + if (entropy->EOBRUN > 0) + emit_eobrun(entropy); + /* if run length > 15, must emit special run-length-16 codes (0xF0) */ + while (r > 15) { + emit_symbol(entropy, entropy->ac_tbl_no, 0xF0); + r -= 16; + } + + /* Find the number of bits needed for the magnitude of the coefficient */ + nbits = 1; /* there must be at least one 1 bit */ + while ((temp >>= 1)) + nbits++; + /* Check for out-of-range coefficient values */ + if (nbits > MAX_COEF_BITS) + ERREXIT(cinfo, JERR_BAD_DCT_COEF); + + /* Count/emit Huffman symbol for run length / number of bits */ + emit_symbol(entropy, entropy->ac_tbl_no, (r << 4) + nbits); + + /* Emit that number of bits of the value, if positive, */ + /* or the complement of its magnitude, if negative. */ + emit_bits(entropy, (unsigned int) temp2, nbits); + + r = 0; /* reset zero run length */ + } + + if (r > 0) { /* If there are trailing zeroes, */ + entropy->EOBRUN++; /* count an EOB */ + if (entropy->EOBRUN == 0x7FFF) + emit_eobrun(entropy); /* force it out to avoid overflow */ + } + + cinfo->dest->next_output_byte = entropy->next_output_byte; + cinfo->dest->free_in_buffer = entropy->free_in_buffer; + + /* Update restart-interval state too */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num++; + entropy->next_restart_num &= 7; + } + entropy->restarts_to_go--; + } + + return TRUE; +} + + +/* + * MCU encoding for DC successive approximation refinement scan. + * Note: we assume such scans can be multi-component, although the spec + * is not very clear on the point. + */ + +METHODDEF(boolean) +encode_mcu_DC_refine (j_compress_ptr cinfo, JBLOCKROW *MCU_data) +{ + phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; + register int temp; + int blkn; + int Al = cinfo->Al; + JBLOCKROW block; + + entropy->next_output_byte = cinfo->dest->next_output_byte; + entropy->free_in_buffer = cinfo->dest->free_in_buffer; + + /* Emit restart marker if needed */ + if (cinfo->restart_interval) + if (entropy->restarts_to_go == 0) + emit_restart(entropy, entropy->next_restart_num); + + /* Encode the MCU data blocks */ + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + block = MCU_data[blkn]; + + /* We simply emit the Al'th bit of the DC coefficient value. */ + temp = (*block)[0]; + emit_bits(entropy, (unsigned int) (temp >> Al), 1); + } + + cinfo->dest->next_output_byte = entropy->next_output_byte; + cinfo->dest->free_in_buffer = entropy->free_in_buffer; + + /* Update restart-interval state too */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num++; + entropy->next_restart_num &= 7; + } + entropy->restarts_to_go--; + } + + return TRUE; +} + + +/* + * MCU encoding for AC successive approximation refinement scan. + */ + +METHODDEF(boolean) +encode_mcu_AC_refine (j_compress_ptr cinfo, JBLOCKROW *MCU_data) +{ + phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; + register int temp; + register int r, k; + int EOB; + char *BR_buffer; + unsigned int BR; + int Se = cinfo->Se; + int Al = cinfo->Al; + JBLOCKROW block; + int absvalues[DCTSIZE2]; + + entropy->next_output_byte = cinfo->dest->next_output_byte; + entropy->free_in_buffer = cinfo->dest->free_in_buffer; + + /* Emit restart marker if needed */ + if (cinfo->restart_interval) + if (entropy->restarts_to_go == 0) + emit_restart(entropy, entropy->next_restart_num); + + /* Encode the MCU data block */ + block = MCU_data[0]; + + /* It is convenient to make a pre-pass to determine the transformed + * coefficients' absolute values and the EOB position. + */ + EOB = 0; + for (k = cinfo->Ss; k <= Se; k++) { + temp = (*block)[jpeg_natural_order[k]]; + /* We must apply the point transform by Al. For AC coefficients this + * is an integer division with rounding towards 0. To do this portably + * in C, we shift after obtaining the absolute value. + */ + if (temp < 0) + temp = -temp; /* temp is abs value of input */ + temp >>= Al; /* apply the point transform */ + absvalues[k] = temp; /* save abs value for main pass */ + if (temp == 1) + EOB = k; /* EOB = index of last newly-nonzero coef */ + } + + /* Encode the AC coefficients per section G.1.2.3, fig. G.7 */ + + r = 0; /* r = run length of zeros */ + BR = 0; /* BR = count of buffered bits added now */ + BR_buffer = entropy->bit_buffer + entropy->BE; /* Append bits to buffer */ + + for (k = cinfo->Ss; k <= Se; k++) { + if ((temp = absvalues[k]) == 0) { + r++; + continue; + } + + /* Emit any required ZRLs, but not if they can be folded into EOB */ + while (r > 15 && k <= EOB) { + /* emit any pending EOBRUN and the BE correction bits */ + emit_eobrun(entropy); + /* Emit ZRL */ + emit_symbol(entropy, entropy->ac_tbl_no, 0xF0); + r -= 16; + /* Emit buffered correction bits that must be associated with ZRL */ + emit_buffered_bits(entropy, BR_buffer, BR); + BR_buffer = entropy->bit_buffer; /* BE bits are gone now */ + BR = 0; + } + + /* If the coef was previously nonzero, it only needs a correction bit. + * NOTE: a straight translation of the spec's figure G.7 would suggest + * that we also need to test r > 15. But if r > 15, we can only get here + * if k > EOB, which implies that this coefficient is not 1. + */ + if (temp > 1) { + /* The correction bit is the next bit of the absolute value. */ + BR_buffer[BR++] = (char) (temp & 1); + continue; + } + + /* Emit any pending EOBRUN and the BE correction bits */ + emit_eobrun(entropy); + + /* Count/emit Huffman symbol for run length / number of bits */ + emit_symbol(entropy, entropy->ac_tbl_no, (r << 4) + 1); + + /* Emit output bit for newly-nonzero coef */ + temp = ((*block)[jpeg_natural_order[k]] < 0) ? 0 : 1; + emit_bits(entropy, (unsigned int) temp, 1); + + /* Emit buffered correction bits that must be associated with this code */ + emit_buffered_bits(entropy, BR_buffer, BR); + BR_buffer = entropy->bit_buffer; /* BE bits are gone now */ + BR = 0; + r = 0; /* reset zero run length */ + } + + if (r > 0 || BR > 0) { /* If there are trailing zeroes, */ + entropy->EOBRUN++; /* count an EOB */ + entropy->BE += BR; /* concat my correction bits to older ones */ + /* We force out the EOB if we risk either: + * 1. overflow of the EOB counter; + * 2. overflow of the correction bit buffer during the next MCU. + */ + if (entropy->EOBRUN == 0x7FFF || entropy->BE > (MAX_CORR_BITS-DCTSIZE2+1)) + emit_eobrun(entropy); + } + + cinfo->dest->next_output_byte = entropy->next_output_byte; + cinfo->dest->free_in_buffer = entropy->free_in_buffer; + + /* Update restart-interval state too */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num++; + entropy->next_restart_num &= 7; + } + entropy->restarts_to_go--; + } + + return TRUE; +} + + +/* + * Finish up at the end of a Huffman-compressed progressive scan. + */ + +METHODDEF(void) +finish_pass_phuff (j_compress_ptr cinfo) +{ + phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; + + entropy->next_output_byte = cinfo->dest->next_output_byte; + entropy->free_in_buffer = cinfo->dest->free_in_buffer; + + /* Flush out any buffered data */ + emit_eobrun(entropy); + flush_bits(entropy); + + cinfo->dest->next_output_byte = entropy->next_output_byte; + cinfo->dest->free_in_buffer = entropy->free_in_buffer; +} + + +/* + * Finish up a statistics-gathering pass and create the new Huffman tables. + */ + +METHODDEF(void) +finish_pass_gather_phuff (j_compress_ptr cinfo) +{ + phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; + boolean is_DC_band; + int ci, tbl; + jpeg_component_info * compptr; + JHUFF_TBL **htblptr; + boolean did[NUM_HUFF_TBLS]; + + /* Flush out buffered data (all we care about is counting the EOB symbol) */ + emit_eobrun(entropy); + + is_DC_band = (cinfo->Ss == 0); + + /* It's important not to apply jpeg_gen_optimal_table more than once + * per table, because it clobbers the input frequency counts! + */ + MEMZERO(did, SIZEOF(did)); + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + if (is_DC_band) { + if (cinfo->Ah != 0) /* DC refinement needs no table */ + continue; + tbl = compptr->dc_tbl_no; + } else { + tbl = compptr->ac_tbl_no; + } + if (! did[tbl]) { + if (is_DC_band) + htblptr = & cinfo->dc_huff_tbl_ptrs[tbl]; + else + htblptr = & cinfo->ac_huff_tbl_ptrs[tbl]; + if (*htblptr == NULL) + *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo); + jpeg_gen_optimal_table(cinfo, *htblptr, entropy->count_ptrs[tbl]); + did[tbl] = TRUE; + } + } +} + + +/* + * Module initialization routine for progressive Huffman entropy encoding. + */ + +GLOBAL(void) +jinit_phuff_encoder (j_compress_ptr cinfo) +{ + phuff_entropy_ptr entropy; + int i; + + entropy = (phuff_entropy_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(phuff_entropy_encoder)); + cinfo->entropy = (struct jpeg_entropy_encoder *) entropy; + entropy->pub.start_pass = start_pass_phuff; + + /* Mark tables unallocated */ + for (i = 0; i < NUM_HUFF_TBLS; i++) { + entropy->derived_tbls[i] = NULL; + entropy->count_ptrs[i] = NULL; + } + entropy->bit_buffer = NULL; /* needed only in AC refinement scan */ +} + +#endif /* C_PROGRESSIVE_SUPPORTED */ diff --git a/mk4/modimage/jpeg-6b/jcprepct.c b/mk4/modimage/jpeg-6b/jcprepct.c new file mode 100644 index 0000000..fa93333 --- /dev/null +++ b/mk4/modimage/jpeg-6b/jcprepct.c @@ -0,0 +1,354 @@ +/* + * jcprepct.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the compression preprocessing controller. + * This controller manages the color conversion, downsampling, + * and edge expansion steps. + * + * Most of the complexity here is associated with buffering input rows + * as required by the downsampler. See the comments at the head of + * jcsample.c for the downsampler's needs. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* At present, jcsample.c can request context rows only for smoothing. + * In the future, we might also need context rows for CCIR601 sampling + * or other more-complex downsampling procedures. The code to support + * context rows should be compiled only if needed. + */ +#ifdef INPUT_SMOOTHING_SUPPORTED +#define CONTEXT_ROWS_SUPPORTED +#endif + + +/* + * For the simple (no-context-row) case, we just need to buffer one + * row group's worth of pixels for the downsampling step. At the bottom of + * the image, we pad to a full row group by replicating the last pixel row. + * The downsampler's last output row is then replicated if needed to pad + * out to a full iMCU row. + * + * When providing context rows, we must buffer three row groups' worth of + * pixels. Three row groups are physically allocated, but the row pointer + * arrays are made five row groups high, with the extra pointers above and + * below "wrapping around" to point to the last and first real row groups. + * This allows the downsampler to access the proper context rows. + * At the top and bottom of the image, we create dummy context rows by + * copying the first or last real pixel row. This copying could be avoided + * by pointer hacking as is done in jdmainct.c, but it doesn't seem worth the + * trouble on the compression side. + */ + + +/* Private buffer controller object */ + +typedef struct { + struct jpeg_c_prep_controller pub; /* public fields */ + + /* Downsampling input buffer. This buffer holds color-converted data + * until we have enough to do a downsample step. + */ + JSAMPARRAY color_buf[MAX_COMPONENTS]; + + JDIMENSION rows_to_go; /* counts rows remaining in source image */ + int next_buf_row; /* index of next row to store in color_buf */ + +#ifdef CONTEXT_ROWS_SUPPORTED /* only needed for context case */ + int this_row_group; /* starting row index of group to process */ + int next_buf_stop; /* downsample when we reach this index */ +#endif +} my_prep_controller; + +typedef my_prep_controller * my_prep_ptr; + + +/* + * Initialize for a processing pass. + */ + +METHODDEF(void) +start_pass_prep (j_compress_ptr cinfo, J_BUF_MODE pass_mode) +{ + my_prep_ptr prep = (my_prep_ptr) cinfo->prep; + + if (pass_mode != JBUF_PASS_THRU) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + + /* Initialize total-height counter for detecting bottom of image */ + prep->rows_to_go = cinfo->image_height; + /* Mark the conversion buffer empty */ + prep->next_buf_row = 0; +#ifdef CONTEXT_ROWS_SUPPORTED + /* Preset additional state variables for context mode. + * These aren't used in non-context mode, so we needn't test which mode. + */ + prep->this_row_group = 0; + /* Set next_buf_stop to stop after two row groups have been read in. */ + prep->next_buf_stop = 2 * cinfo->max_v_samp_factor; +#endif +} + + +/* + * Expand an image vertically from height input_rows to height output_rows, + * by duplicating the bottom row. + */ + +LOCAL(void) +expand_bottom_edge (JSAMPARRAY image_data, JDIMENSION num_cols, + int input_rows, int output_rows) +{ + register int row; + + for (row = input_rows; row < output_rows; row++) { + jcopy_sample_rows(image_data, input_rows-1, image_data, row, + 1, num_cols); + } +} + + +/* + * Process some data in the simple no-context case. + * + * Preprocessor output data is counted in "row groups". A row group + * is defined to be v_samp_factor sample rows of each component. + * Downsampling will produce this much data from each max_v_samp_factor + * input rows. + */ + +METHODDEF(void) +pre_process_data (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail, + JSAMPIMAGE output_buf, JDIMENSION *out_row_group_ctr, + JDIMENSION out_row_groups_avail) +{ + my_prep_ptr prep = (my_prep_ptr) cinfo->prep; + int numrows, ci; + JDIMENSION inrows; + jpeg_component_info * compptr; + + while (*in_row_ctr < in_rows_avail && + *out_row_group_ctr < out_row_groups_avail) { + /* Do color conversion to fill the conversion buffer. */ + inrows = in_rows_avail - *in_row_ctr; + numrows = cinfo->max_v_samp_factor - prep->next_buf_row; + numrows = (int) MIN((JDIMENSION) numrows, inrows); + (*cinfo->cconvert->color_convert) (cinfo, input_buf + *in_row_ctr, + prep->color_buf, + (JDIMENSION) prep->next_buf_row, + numrows); + *in_row_ctr += numrows; + prep->next_buf_row += numrows; + prep->rows_to_go -= numrows; + /* If at bottom of image, pad to fill the conversion buffer. */ + if (prep->rows_to_go == 0 && + prep->next_buf_row < cinfo->max_v_samp_factor) { + for (ci = 0; ci < cinfo->num_components; ci++) { + expand_bottom_edge(prep->color_buf[ci], cinfo->image_width, + prep->next_buf_row, cinfo->max_v_samp_factor); + } + prep->next_buf_row = cinfo->max_v_samp_factor; + } + /* If we've filled the conversion buffer, empty it. */ + if (prep->next_buf_row == cinfo->max_v_samp_factor) { + (*cinfo->downsample->downsample) (cinfo, + prep->color_buf, (JDIMENSION) 0, + output_buf, *out_row_group_ctr); + prep->next_buf_row = 0; + (*out_row_group_ctr)++; + } + /* If at bottom of image, pad the output to a full iMCU height. + * Note we assume the caller is providing a one-iMCU-height output buffer! + */ + if (prep->rows_to_go == 0 && + *out_row_group_ctr < out_row_groups_avail) { + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + expand_bottom_edge(output_buf[ci], + compptr->width_in_blocks * DCTSIZE, + (int) (*out_row_group_ctr * compptr->v_samp_factor), + (int) (out_row_groups_avail * compptr->v_samp_factor)); + } + *out_row_group_ctr = out_row_groups_avail; + break; /* can exit outer loop without test */ + } + } +} + + +#ifdef CONTEXT_ROWS_SUPPORTED + +/* + * Process some data in the context case. + */ + +METHODDEF(void) +pre_process_context (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail, + JSAMPIMAGE output_buf, JDIMENSION *out_row_group_ctr, + JDIMENSION out_row_groups_avail) +{ + my_prep_ptr prep = (my_prep_ptr) cinfo->prep; + int numrows, ci; + int buf_height = cinfo->max_v_samp_factor * 3; + JDIMENSION inrows; + + while (*out_row_group_ctr < out_row_groups_avail) { + if (*in_row_ctr < in_rows_avail) { + /* Do color conversion to fill the conversion buffer. */ + inrows = in_rows_avail - *in_row_ctr; + numrows = prep->next_buf_stop - prep->next_buf_row; + numrows = (int) MIN((JDIMENSION) numrows, inrows); + (*cinfo->cconvert->color_convert) (cinfo, input_buf + *in_row_ctr, + prep->color_buf, + (JDIMENSION) prep->next_buf_row, + numrows); + /* Pad at top of image, if first time through */ + if (prep->rows_to_go == cinfo->image_height) { + for (ci = 0; ci < cinfo->num_components; ci++) { + int row; + for (row = 1; row <= cinfo->max_v_samp_factor; row++) { + jcopy_sample_rows(prep->color_buf[ci], 0, + prep->color_buf[ci], -row, + 1, cinfo->image_width); + } + } + } + *in_row_ctr += numrows; + prep->next_buf_row += numrows; + prep->rows_to_go -= numrows; + } else { + /* Return for more data, unless we are at the bottom of the image. */ + if (prep->rows_to_go != 0) + break; + /* When at bottom of image, pad to fill the conversion buffer. */ + if (prep->next_buf_row < prep->next_buf_stop) { + for (ci = 0; ci < cinfo->num_components; ci++) { + expand_bottom_edge(prep->color_buf[ci], cinfo->image_width, + prep->next_buf_row, prep->next_buf_stop); + } + prep->next_buf_row = prep->next_buf_stop; + } + } + /* If we've gotten enough data, downsample a row group. */ + if (prep->next_buf_row == prep->next_buf_stop) { + (*cinfo->downsample->downsample) (cinfo, + prep->color_buf, + (JDIMENSION) prep->this_row_group, + output_buf, *out_row_group_ctr); + (*out_row_group_ctr)++; + /* Advance pointers with wraparound as necessary. */ + prep->this_row_group += cinfo->max_v_samp_factor; + if (prep->this_row_group >= buf_height) + prep->this_row_group = 0; + if (prep->next_buf_row >= buf_height) + prep->next_buf_row = 0; + prep->next_buf_stop = prep->next_buf_row + cinfo->max_v_samp_factor; + } + } +} + + +/* + * Create the wrapped-around downsampling input buffer needed for context mode. + */ + +LOCAL(void) +create_context_buffer (j_compress_ptr cinfo) +{ + my_prep_ptr prep = (my_prep_ptr) cinfo->prep; + int rgroup_height = cinfo->max_v_samp_factor; + int ci, i; + jpeg_component_info * compptr; + JSAMPARRAY true_buffer, fake_buffer; + + /* Grab enough space for fake row pointers for all the components; + * we need five row groups' worth of pointers for each component. + */ + fake_buffer = (JSAMPARRAY) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (cinfo->num_components * 5 * rgroup_height) * + SIZEOF(JSAMPROW)); + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Allocate the actual buffer space (3 row groups) for this component. + * We make the buffer wide enough to allow the downsampler to edge-expand + * horizontally within the buffer, if it so chooses. + */ + true_buffer = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) (((long) compptr->width_in_blocks * DCTSIZE * + cinfo->max_h_samp_factor) / compptr->h_samp_factor), + (JDIMENSION) (3 * rgroup_height)); + /* Copy true buffer row pointers into the middle of the fake row array */ + MEMCOPY(fake_buffer + rgroup_height, true_buffer, + 3 * rgroup_height * SIZEOF(JSAMPROW)); + /* Fill in the above and below wraparound pointers */ + for (i = 0; i < rgroup_height; i++) { + fake_buffer[i] = true_buffer[2 * rgroup_height + i]; + fake_buffer[4 * rgroup_height + i] = true_buffer[i]; + } + prep->color_buf[ci] = fake_buffer + rgroup_height; + fake_buffer += 5 * rgroup_height; /* point to space for next component */ + } +} + +#endif /* CONTEXT_ROWS_SUPPORTED */ + + +/* + * Initialize preprocessing controller. + */ + +GLOBAL(void) +jinit_c_prep_controller (j_compress_ptr cinfo, boolean need_full_buffer) +{ + my_prep_ptr prep; + int ci; + jpeg_component_info * compptr; + + if (need_full_buffer) /* safety check */ + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + + prep = (my_prep_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_prep_controller)); + cinfo->prep = (struct jpeg_c_prep_controller *) prep; + prep->pub.start_pass = start_pass_prep; + + /* Allocate the color conversion buffer. + * We make the buffer wide enough to allow the downsampler to edge-expand + * horizontally within the buffer, if it so chooses. + */ + if (cinfo->downsample->need_context_rows) { + /* Set up to provide context rows */ +#ifdef CONTEXT_ROWS_SUPPORTED + prep->pub.pre_process_data = pre_process_context; + create_context_buffer(cinfo); +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else { + /* No context, just make it tall enough for one row group */ + prep->pub.pre_process_data = pre_process_data; + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + prep->color_buf[ci] = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) (((long) compptr->width_in_blocks * DCTSIZE * + cinfo->max_h_samp_factor) / compptr->h_samp_factor), + (JDIMENSION) cinfo->max_v_samp_factor); + } + } +} diff --git a/mk4/modimage/jpeg-6b/jcsample.c b/mk4/modimage/jpeg-6b/jcsample.c new file mode 100644 index 0000000..212ec87 --- /dev/null +++ b/mk4/modimage/jpeg-6b/jcsample.c @@ -0,0 +1,519 @@ +/* + * jcsample.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains downsampling routines. + * + * Downsampling input data is counted in "row groups". A row group + * is defined to be max_v_samp_factor pixel rows of each component, + * from which the downsampler produces v_samp_factor sample rows. + * A single row group is processed in each call to the downsampler module. + * + * The downsampler is responsible for edge-expansion of its output data + * to fill an integral number of DCT blocks horizontally. The source buffer + * may be modified if it is helpful for this purpose (the source buffer is + * allocated wide enough to correspond to the desired output width). + * The caller (the prep controller) is responsible for vertical padding. + * + * The downsampler may request "context rows" by setting need_context_rows + * during startup. In this case, the input arrays will contain at least + * one row group's worth of pixels above and below the passed-in data; + * the caller will create dummy rows at image top and bottom by replicating + * the first or last real pixel row. + * + * An excellent reference for image resampling is + * Digital Image Warping, George Wolberg, 1990. + * Pub. by IEEE Computer Society Press, Los Alamitos, CA. ISBN 0-8186-8944-7. + * + * The downsampling algorithm used here is a simple average of the source + * pixels covered by the output pixel. The hi-falutin sampling literature + * refers to this as a "box filter". In general the characteristics of a box + * filter are not very good, but for the specific cases we normally use (1:1 + * and 2:1 ratios) the box is equivalent to a "triangle filter" which is not + * nearly so bad. If you intend to use other sampling ratios, you'd be well + * advised to improve this code. + * + * A simple input-smoothing capability is provided. This is mainly intended + * for cleaning up color-dithered GIF input files (if you find it inadequate, + * we suggest using an external filtering program such as pnmconvol). When + * enabled, each input pixel P is replaced by a weighted sum of itself and its + * eight neighbors. P's weight is 1-8*SF and each neighbor's weight is SF, + * where SF = (smoothing_factor / 1024). + * Currently, smoothing is only supported for 2h2v sampling factors. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Pointer to routine to downsample a single component */ +typedef JMETHOD(void, downsample1_ptr, + (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY output_data)); + +/* Private subobject */ + +typedef struct { + struct jpeg_downsampler pub; /* public fields */ + + /* Downsampling method pointers, one per component */ + downsample1_ptr methods[MAX_COMPONENTS]; +} my_downsampler; + +typedef my_downsampler * my_downsample_ptr; + + +/* + * Initialize for a downsampling pass. + */ + +METHODDEF(void) +start_pass_downsample (j_compress_ptr cinfo) +{ + /* no work for now */ +} + + +/* + * Expand a component horizontally from width input_cols to width output_cols, + * by duplicating the rightmost samples. + */ + +LOCAL(void) +expand_right_edge (JSAMPARRAY image_data, int num_rows, + JDIMENSION input_cols, JDIMENSION output_cols) +{ + register JSAMPROW ptr; + register JSAMPLE pixval; + register int count; + int row; + int numcols = (int) (output_cols - input_cols); + + if (numcols > 0) { + for (row = 0; row < num_rows; row++) { + ptr = image_data[row] + input_cols; + pixval = ptr[-1]; /* don't need GETJSAMPLE() here */ + for (count = numcols; count > 0; count--) + *ptr++ = pixval; + } + } +} + + +/* + * Do downsampling for a whole row group (all components). + * + * In this version we simply downsample each component independently. + */ + +METHODDEF(void) +sep_downsample (j_compress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION in_row_index, + JSAMPIMAGE output_buf, JDIMENSION out_row_group_index) +{ + my_downsample_ptr downsample = (my_downsample_ptr) cinfo->downsample; + int ci; + jpeg_component_info * compptr; + JSAMPARRAY in_ptr, out_ptr; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + in_ptr = input_buf[ci] + in_row_index; + out_ptr = output_buf[ci] + (out_row_group_index * compptr->v_samp_factor); + (*downsample->methods[ci]) (cinfo, compptr, in_ptr, out_ptr); + } +} + + +/* + * Downsample pixel values of a single component. + * One row group is processed per call. + * This version handles arbitrary integral sampling ratios, without smoothing. + * Note that this version is not actually used for customary sampling ratios. + */ + +METHODDEF(void) +int_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY output_data) +{ + int inrow, outrow, h_expand, v_expand, numpix, numpix2, h, v; + JDIMENSION outcol, outcol_h; /* outcol_h == outcol*h_expand */ + JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE; + JSAMPROW inptr, outptr; + INT32 outvalue; + + h_expand = cinfo->max_h_samp_factor / compptr->h_samp_factor; + v_expand = cinfo->max_v_samp_factor / compptr->v_samp_factor; + numpix = h_expand * v_expand; + numpix2 = numpix/2; + + /* Expand input data enough to let all the output samples be generated + * by the standard loop. Special-casing padded output would be more + * efficient. + */ + expand_right_edge(input_data, cinfo->max_v_samp_factor, + cinfo->image_width, output_cols * h_expand); + + inrow = 0; + for (outrow = 0; outrow < compptr->v_samp_factor; outrow++) { + outptr = output_data[outrow]; + for (outcol = 0, outcol_h = 0; outcol < output_cols; + outcol++, outcol_h += h_expand) { + outvalue = 0; + for (v = 0; v < v_expand; v++) { + inptr = input_data[inrow+v] + outcol_h; + for (h = 0; h < h_expand; h++) { + outvalue += (INT32) GETJSAMPLE(*inptr++); + } + } + *outptr++ = (JSAMPLE) ((outvalue + numpix2) / numpix); + } + inrow += v_expand; + } +} + + +/* + * Downsample pixel values of a single component. + * This version handles the special case of a full-size component, + * without smoothing. + */ + +METHODDEF(void) +fullsize_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY output_data) +{ + /* Copy the data */ + jcopy_sample_rows(input_data, 0, output_data, 0, + cinfo->max_v_samp_factor, cinfo->image_width); + /* Edge-expand */ + expand_right_edge(output_data, cinfo->max_v_samp_factor, + cinfo->image_width, compptr->width_in_blocks * DCTSIZE); +} + + +/* + * Downsample pixel values of a single component. + * This version handles the common case of 2:1 horizontal and 1:1 vertical, + * without smoothing. + * + * A note about the "bias" calculations: when rounding fractional values to + * integer, we do not want to always round 0.5 up to the next integer. + * If we did that, we'd introduce a noticeable bias towards larger values. + * Instead, this code is arranged so that 0.5 will be rounded up or down at + * alternate pixel locations (a simple ordered dither pattern). + */ + +METHODDEF(void) +h2v1_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY output_data) +{ + int outrow; + JDIMENSION outcol; + JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE; + register JSAMPROW inptr, outptr; + register int bias; + + /* Expand input data enough to let all the output samples be generated + * by the standard loop. Special-casing padded output would be more + * efficient. + */ + expand_right_edge(input_data, cinfo->max_v_samp_factor, + cinfo->image_width, output_cols * 2); + + for (outrow = 0; outrow < compptr->v_samp_factor; outrow++) { + outptr = output_data[outrow]; + inptr = input_data[outrow]; + bias = 0; /* bias = 0,1,0,1,... for successive samples */ + for (outcol = 0; outcol < output_cols; outcol++) { + *outptr++ = (JSAMPLE) ((GETJSAMPLE(*inptr) + GETJSAMPLE(inptr[1]) + + bias) >> 1); + bias ^= 1; /* 0=>1, 1=>0 */ + inptr += 2; + } + } +} + + +/* + * Downsample pixel values of a single component. + * This version handles the standard case of 2:1 horizontal and 2:1 vertical, + * without smoothing. + */ + +METHODDEF(void) +h2v2_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY output_data) +{ + int inrow, outrow; + JDIMENSION outcol; + JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE; + register JSAMPROW inptr0, inptr1, outptr; + register int bias; + + /* Expand input data enough to let all the output samples be generated + * by the standard loop. Special-casing padded output would be more + * efficient. + */ + expand_right_edge(input_data, cinfo->max_v_samp_factor, + cinfo->image_width, output_cols * 2); + + inrow = 0; + for (outrow = 0; outrow < compptr->v_samp_factor; outrow++) { + outptr = output_data[outrow]; + inptr0 = input_data[inrow]; + inptr1 = input_data[inrow+1]; + bias = 1; /* bias = 1,2,1,2,... for successive samples */ + for (outcol = 0; outcol < output_cols; outcol++) { + *outptr++ = (JSAMPLE) ((GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) + + GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]) + + bias) >> 2); + bias ^= 3; /* 1=>2, 2=>1 */ + inptr0 += 2; inptr1 += 2; + } + inrow += 2; + } +} + + +#ifdef INPUT_SMOOTHING_SUPPORTED + +/* + * Downsample pixel values of a single component. + * This version handles the standard case of 2:1 horizontal and 2:1 vertical, + * with smoothing. One row of context is required. + */ + +METHODDEF(void) +h2v2_smooth_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY output_data) +{ + int inrow, outrow; + JDIMENSION colctr; + JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE; + register JSAMPROW inptr0, inptr1, above_ptr, below_ptr, outptr; + INT32 membersum, neighsum, memberscale, neighscale; + + /* Expand input data enough to let all the output samples be generated + * by the standard loop. Special-casing padded output would be more + * efficient. + */ + expand_right_edge(input_data - 1, cinfo->max_v_samp_factor + 2, + cinfo->image_width, output_cols * 2); + + /* We don't bother to form the individual "smoothed" input pixel values; + * we can directly compute the output which is the average of the four + * smoothed values. Each of the four member pixels contributes a fraction + * (1-8*SF) to its own smoothed image and a fraction SF to each of the three + * other smoothed pixels, therefore a total fraction (1-5*SF)/4 to the final + * output. The four corner-adjacent neighbor pixels contribute a fraction + * SF to just one smoothed pixel, or SF/4 to the final output; while the + * eight edge-adjacent neighbors contribute SF to each of two smoothed + * pixels, or SF/2 overall. In order to use integer arithmetic, these + * factors are scaled by 2^16 = 65536. + * Also recall that SF = smoothing_factor / 1024. + */ + + memberscale = 16384 - cinfo->smoothing_factor * 80; /* scaled (1-5*SF)/4 */ + neighscale = cinfo->smoothing_factor * 16; /* scaled SF/4 */ + + inrow = 0; + for (outrow = 0; outrow < compptr->v_samp_factor; outrow++) { + outptr = output_data[outrow]; + inptr0 = input_data[inrow]; + inptr1 = input_data[inrow+1]; + above_ptr = input_data[inrow-1]; + below_ptr = input_data[inrow+2]; + + /* Special case for first column: pretend column -1 is same as column 0 */ + membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) + + GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]); + neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) + + GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) + + GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[2]) + + GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[2]); + neighsum += neighsum; + neighsum += GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[2]) + + GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[2]); + membersum = membersum * memberscale + neighsum * neighscale; + *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16); + inptr0 += 2; inptr1 += 2; above_ptr += 2; below_ptr += 2; + + for (colctr = output_cols - 2; colctr > 0; colctr--) { + /* sum of pixels directly mapped to this output element */ + membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) + + GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]); + /* sum of edge-neighbor pixels */ + neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) + + GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) + + GETJSAMPLE(inptr0[-1]) + GETJSAMPLE(inptr0[2]) + + GETJSAMPLE(inptr1[-1]) + GETJSAMPLE(inptr1[2]); + /* The edge-neighbors count twice as much as corner-neighbors */ + neighsum += neighsum; + /* Add in the corner-neighbors */ + neighsum += GETJSAMPLE(above_ptr[-1]) + GETJSAMPLE(above_ptr[2]) + + GETJSAMPLE(below_ptr[-1]) + GETJSAMPLE(below_ptr[2]); + /* form final output scaled up by 2^16 */ + membersum = membersum * memberscale + neighsum * neighscale; + /* round, descale and output it */ + *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16); + inptr0 += 2; inptr1 += 2; above_ptr += 2; below_ptr += 2; + } + + /* Special case for last column */ + membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) + + GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]); + neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) + + GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) + + GETJSAMPLE(inptr0[-1]) + GETJSAMPLE(inptr0[1]) + + GETJSAMPLE(inptr1[-1]) + GETJSAMPLE(inptr1[1]); + neighsum += neighsum; + neighsum += GETJSAMPLE(above_ptr[-1]) + GETJSAMPLE(above_ptr[1]) + + GETJSAMPLE(below_ptr[-1]) + GETJSAMPLE(below_ptr[1]); + membersum = membersum * memberscale + neighsum * neighscale; + *outptr = (JSAMPLE) ((membersum + 32768) >> 16); + + inrow += 2; + } +} + + +/* + * Downsample pixel values of a single component. + * This version handles the special case of a full-size component, + * with smoothing. One row of context is required. + */ + +METHODDEF(void) +fullsize_smooth_downsample (j_compress_ptr cinfo, jpeg_component_info *compptr, + JSAMPARRAY input_data, JSAMPARRAY output_data) +{ + int outrow; + JDIMENSION colctr; + JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE; + register JSAMPROW inptr, above_ptr, below_ptr, outptr; + INT32 membersum, neighsum, memberscale, neighscale; + int colsum, lastcolsum, nextcolsum; + + /* Expand input data enough to let all the output samples be generated + * by the standard loop. Special-casing padded output would be more + * efficient. + */ + expand_right_edge(input_data - 1, cinfo->max_v_samp_factor + 2, + cinfo->image_width, output_cols); + + /* Each of the eight neighbor pixels contributes a fraction SF to the + * smoothed pixel, while the main pixel contributes (1-8*SF). In order + * to use integer arithmetic, these factors are multiplied by 2^16 = 65536. + * Also recall that SF = smoothing_factor / 1024. + */ + + memberscale = 65536L - cinfo->smoothing_factor * 512L; /* scaled 1-8*SF */ + neighscale = cinfo->smoothing_factor * 64; /* scaled SF */ + + for (outrow = 0; outrow < compptr->v_samp_factor; outrow++) { + outptr = output_data[outrow]; + inptr = input_data[outrow]; + above_ptr = input_data[outrow-1]; + below_ptr = input_data[outrow+1]; + + /* Special case for first column */ + colsum = GETJSAMPLE(*above_ptr++) + GETJSAMPLE(*below_ptr++) + + GETJSAMPLE(*inptr); + membersum = GETJSAMPLE(*inptr++); + nextcolsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(*below_ptr) + + GETJSAMPLE(*inptr); + neighsum = colsum + (colsum - membersum) + nextcolsum; + membersum = membersum * memberscale + neighsum * neighscale; + *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16); + lastcolsum = colsum; colsum = nextcolsum; + + for (colctr = output_cols - 2; colctr > 0; colctr--) { + membersum = GETJSAMPLE(*inptr++); + above_ptr++; below_ptr++; + nextcolsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(*below_ptr) + + GETJSAMPLE(*inptr); + neighsum = lastcolsum + (colsum - membersum) + nextcolsum; + membersum = membersum * memberscale + neighsum * neighscale; + *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16); + lastcolsum = colsum; colsum = nextcolsum; + } + + /* Special case for last column */ + membersum = GETJSAMPLE(*inptr); + neighsum = lastcolsum + (colsum - membersum) + colsum; + membersum = membersum * memberscale + neighsum * neighscale; + *outptr = (JSAMPLE) ((membersum + 32768) >> 16); + + } +} + +#endif /* INPUT_SMOOTHING_SUPPORTED */ + + +/* + * Module initialization routine for downsampling. + * Note that we must select a routine for each component. + */ + +GLOBAL(void) +jinit_downsampler (j_compress_ptr cinfo) +{ + my_downsample_ptr downsample; + int ci; + jpeg_component_info * compptr; + boolean smoothok = TRUE; + + downsample = (my_downsample_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_downsampler)); + cinfo->downsample = (struct jpeg_downsampler *) downsample; + downsample->pub.start_pass = start_pass_downsample; + downsample->pub.downsample = sep_downsample; + downsample->pub.need_context_rows = FALSE; + + if (cinfo->CCIR601_sampling) + ERREXIT(cinfo, JERR_CCIR601_NOTIMPL); + + /* Verify we can handle the sampling factors, and set up method pointers */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + if (compptr->h_samp_factor == cinfo->max_h_samp_factor && + compptr->v_samp_factor == cinfo->max_v_samp_factor) { +#ifdef INPUT_SMOOTHING_SUPPORTED + if (cinfo->smoothing_factor) { + downsample->methods[ci] = fullsize_smooth_downsample; + downsample->pub.need_context_rows = TRUE; + } else +#endif + downsample->methods[ci] = fullsize_downsample; + } else if (compptr->h_samp_factor * 2 == cinfo->max_h_samp_factor && + compptr->v_samp_factor == cinfo->max_v_samp_factor) { + smoothok = FALSE; + downsample->methods[ci] = h2v1_downsample; + } else if (compptr->h_samp_factor * 2 == cinfo->max_h_samp_factor && + compptr->v_samp_factor * 2 == cinfo->max_v_samp_factor) { +#ifdef INPUT_SMOOTHING_SUPPORTED + if (cinfo->smoothing_factor) { + downsample->methods[ci] = h2v2_smooth_downsample; + downsample->pub.need_context_rows = TRUE; + } else +#endif + downsample->methods[ci] = h2v2_downsample; + } else if ((cinfo->max_h_samp_factor % compptr->h_samp_factor) == 0 && + (cinfo->max_v_samp_factor % compptr->v_samp_factor) == 0) { + smoothok = FALSE; + downsample->methods[ci] = int_downsample; + } else + ERREXIT(cinfo, JERR_FRACT_SAMPLE_NOTIMPL); + } + +#ifdef INPUT_SMOOTHING_SUPPORTED + if (cinfo->smoothing_factor && !smoothok) + TRACEMS(cinfo, 0, JTRC_SMOOTH_NOTIMPL); +#endif +} diff --git a/mk4/modimage/jpeg-6b/jctrans.c b/mk4/modimage/jpeg-6b/jctrans.c new file mode 100644 index 0000000..0e6d707 --- /dev/null +++ b/mk4/modimage/jpeg-6b/jctrans.c @@ -0,0 +1,388 @@ +/* + * jctrans.c + * + * Copyright (C) 1995-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains library routines for transcoding compression, + * that is, writing raw DCT coefficient arrays to an output JPEG file. + * The routines in jcapimin.c will also be needed by a transcoder. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Forward declarations */ +LOCAL(void) transencode_master_selection + JPP((j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays)); +LOCAL(void) transencode_coef_controller + JPP((j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays)); + + +/* + * Compression initialization for writing raw-coefficient data. + * Before calling this, all parameters and a data destination must be set up. + * Call jpeg_finish_compress() to actually write the data. + * + * The number of passed virtual arrays must match cinfo->num_components. + * Note that the virtual arrays need not be filled or even realized at + * the time write_coefficients is called; indeed, if the virtual arrays + * were requested from this compression object's memory manager, they + * typically will be realized during this routine and filled afterwards. + */ + +GLOBAL(void) +jpeg_write_coefficients (j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays) +{ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + /* Mark all tables to be written */ + jpeg_suppress_tables(cinfo, FALSE); + /* (Re)initialize error mgr and destination modules */ + (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo); + (*cinfo->dest->init_destination) (cinfo); + /* Perform master selection of active modules */ + transencode_master_selection(cinfo, coef_arrays); + /* Wait for jpeg_finish_compress() call */ + cinfo->next_scanline = 0; /* so jpeg_write_marker works */ + cinfo->global_state = CSTATE_WRCOEFS; +} + + +/* + * Initialize the compression object with default parameters, + * then copy from the source object all parameters needed for lossless + * transcoding. Parameters that can be varied without loss (such as + * scan script and Huffman optimization) are left in their default states. + */ + +GLOBAL(void) +jpeg_copy_critical_parameters (j_decompress_ptr srcinfo, + j_compress_ptr dstinfo) +{ + JQUANT_TBL ** qtblptr; + jpeg_component_info *incomp, *outcomp; + JQUANT_TBL *c_quant, *slot_quant; + int tblno, ci, coefi; + + /* Safety check to ensure start_compress not called yet. */ + if (dstinfo->global_state != CSTATE_START) + ERREXIT1(dstinfo, JERR_BAD_STATE, dstinfo->global_state); + /* Copy fundamental image dimensions */ + dstinfo->image_width = srcinfo->image_width; + dstinfo->image_height = srcinfo->image_height; + dstinfo->input_components = srcinfo->num_components; + dstinfo->in_color_space = srcinfo->jpeg_color_space; + /* Initialize all parameters to default values */ + jpeg_set_defaults(dstinfo); + /* jpeg_set_defaults may choose wrong colorspace, eg YCbCr if input is RGB. + * Fix it to get the right header markers for the image colorspace. + */ + jpeg_set_colorspace(dstinfo, srcinfo->jpeg_color_space); + dstinfo->data_precision = srcinfo->data_precision; + dstinfo->CCIR601_sampling = srcinfo->CCIR601_sampling; + /* Copy the source's quantization tables. */ + for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) { + if (srcinfo->quant_tbl_ptrs[tblno] != NULL) { + qtblptr = & dstinfo->quant_tbl_ptrs[tblno]; + if (*qtblptr == NULL) + *qtblptr = jpeg_alloc_quant_table((j_common_ptr) dstinfo); + MEMCOPY((*qtblptr)->quantval, + srcinfo->quant_tbl_ptrs[tblno]->quantval, + SIZEOF((*qtblptr)->quantval)); + (*qtblptr)->sent_table = FALSE; + } + } + /* Copy the source's per-component info. + * Note we assume jpeg_set_defaults has allocated the dest comp_info array. + */ + dstinfo->num_components = srcinfo->num_components; + if (dstinfo->num_components < 1 || dstinfo->num_components > MAX_COMPONENTS) + ERREXIT2(dstinfo, JERR_COMPONENT_COUNT, dstinfo->num_components, + MAX_COMPONENTS); + for (ci = 0, incomp = srcinfo->comp_info, outcomp = dstinfo->comp_info; + ci < dstinfo->num_components; ci++, incomp++, outcomp++) { + outcomp->component_id = incomp->component_id; + outcomp->h_samp_factor = incomp->h_samp_factor; + outcomp->v_samp_factor = incomp->v_samp_factor; + outcomp->quant_tbl_no = incomp->quant_tbl_no; + /* Make sure saved quantization table for component matches the qtable + * slot. If not, the input file re-used this qtable slot. + * IJG encoder currently cannot duplicate this. + */ + tblno = outcomp->quant_tbl_no; + if (tblno < 0 || tblno >= NUM_QUANT_TBLS || + srcinfo->quant_tbl_ptrs[tblno] == NULL) + ERREXIT1(dstinfo, JERR_NO_QUANT_TABLE, tblno); + slot_quant = srcinfo->quant_tbl_ptrs[tblno]; + c_quant = incomp->quant_table; + if (c_quant != NULL) { + for (coefi = 0; coefi < DCTSIZE2; coefi++) { + if (c_quant->quantval[coefi] != slot_quant->quantval[coefi]) + ERREXIT1(dstinfo, JERR_MISMATCHED_QUANT_TABLE, tblno); + } + } + /* Note: we do not copy the source's Huffman table assignments; + * instead we rely on jpeg_set_colorspace to have made a suitable choice. + */ + } + /* Also copy JFIF version and resolution information, if available. + * Strictly speaking this isn't "critical" info, but it's nearly + * always appropriate to copy it if available. In particular, + * if the application chooses to copy JFIF 1.02 extension markers from + * the source file, we need to copy the version to make sure we don't + * emit a file that has 1.02 extensions but a claimed version of 1.01. + * We will *not*, however, copy version info from mislabeled "2.01" files. + */ + if (srcinfo->saw_JFIF_marker) { + if (srcinfo->JFIF_major_version == 1) { + dstinfo->JFIF_major_version = srcinfo->JFIF_major_version; + dstinfo->JFIF_minor_version = srcinfo->JFIF_minor_version; + } + dstinfo->density_unit = srcinfo->density_unit; + dstinfo->X_density = srcinfo->X_density; + dstinfo->Y_density = srcinfo->Y_density; + } +} + + +/* + * Master selection of compression modules for transcoding. + * This substitutes for jcinit.c's initialization of the full compressor. + */ + +LOCAL(void) +transencode_master_selection (j_compress_ptr cinfo, + jvirt_barray_ptr * coef_arrays) +{ + /* Although we don't actually use input_components for transcoding, + * jcmaster.c's initial_setup will complain if input_components is 0. + */ + cinfo->input_components = 1; + /* Initialize master control (includes parameter checking/processing) */ + jinit_c_master_control(cinfo, TRUE /* transcode only */); + + /* Entropy encoding: either Huffman or arithmetic coding. */ + if (cinfo->arith_code) { + ERREXIT(cinfo, JERR_ARITH_NOTIMPL); + } else { + if (cinfo->progressive_mode) { +#ifdef C_PROGRESSIVE_SUPPORTED + jinit_phuff_encoder(cinfo); +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else + jinit_huff_encoder(cinfo); + } + + /* We need a special coefficient buffer controller. */ + transencode_coef_controller(cinfo, coef_arrays); + + jinit_marker_writer(cinfo); + + /* We can now tell the memory manager to allocate virtual arrays. */ + (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo); + + /* Write the datastream header (SOI, JFIF) immediately. + * Frame and scan headers are postponed till later. + * This lets application insert special markers after the SOI. + */ + (*cinfo->marker->write_file_header) (cinfo); +} + + +/* + * The rest of this file is a special implementation of the coefficient + * buffer controller. This is similar to jccoefct.c, but it handles only + * output from presupplied virtual arrays. Furthermore, we generate any + * dummy padding blocks on-the-fly rather than expecting them to be present + * in the arrays. + */ + +/* Private buffer controller object */ + +typedef struct { + struct jpeg_c_coef_controller pub; /* public fields */ + + JDIMENSION iMCU_row_num; /* iMCU row # within image */ + JDIMENSION mcu_ctr; /* counts MCUs processed in current row */ + int MCU_vert_offset; /* counts MCU rows within iMCU row */ + int MCU_rows_per_iMCU_row; /* number of such rows needed */ + + /* Virtual block array for each component. */ + jvirt_barray_ptr * whole_image; + + /* Workspace for constructing dummy blocks at right/bottom edges. */ + JBLOCKROW dummy_buffer[C_MAX_BLOCKS_IN_MCU]; +} my_coef_controller; + +typedef my_coef_controller * my_coef_ptr; + + +LOCAL(void) +start_iMCU_row (j_compress_ptr cinfo) +/* Reset within-iMCU-row counters for a new row */ +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + + /* In an interleaved scan, an MCU row is the same as an iMCU row. + * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows. + * But at the bottom of the image, process only what's left. + */ + if (cinfo->comps_in_scan > 1) { + coef->MCU_rows_per_iMCU_row = 1; + } else { + if (coef->iMCU_row_num < (cinfo->total_iMCU_rows-1)) + coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor; + else + coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height; + } + + coef->mcu_ctr = 0; + coef->MCU_vert_offset = 0; +} + + +/* + * Initialize for a processing pass. + */ + +METHODDEF(void) +start_pass_coef (j_compress_ptr cinfo, J_BUF_MODE pass_mode) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + + if (pass_mode != JBUF_CRANK_DEST) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + + coef->iMCU_row_num = 0; + start_iMCU_row(cinfo); +} + + +/* + * Process some data. + * We process the equivalent of one fully interleaved MCU row ("iMCU" row) + * per call, ie, v_samp_factor block rows for each component in the scan. + * The data is obtained from the virtual arrays and fed to the entropy coder. + * Returns TRUE if the iMCU row is completed, FALSE if suspended. + * + * NB: input_buf is ignored; it is likely to be a NULL pointer. + */ + +METHODDEF(boolean) +compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + JDIMENSION MCU_col_num; /* index of current MCU within row */ + JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1; + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + int blkn, ci, xindex, yindex, yoffset, blockcnt; + JDIMENSION start_col; + JBLOCKARRAY buffer[MAX_COMPS_IN_SCAN]; + JBLOCKROW MCU_buffer[C_MAX_BLOCKS_IN_MCU]; + JBLOCKROW buffer_ptr; + jpeg_component_info *compptr; + + /* Align the virtual buffers for the components used in this scan. */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + buffer[ci] = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef->whole_image[compptr->component_index], + coef->iMCU_row_num * compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } + + /* Loop to process one whole iMCU row */ + for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row; + yoffset++) { + for (MCU_col_num = coef->mcu_ctr; MCU_col_num < cinfo->MCUs_per_row; + MCU_col_num++) { + /* Construct list of pointers to DCT blocks belonging to this MCU */ + blkn = 0; /* index of current DCT block within MCU */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + start_col = MCU_col_num * compptr->MCU_width; + blockcnt = (MCU_col_num < last_MCU_col) ? compptr->MCU_width + : compptr->last_col_width; + for (yindex = 0; yindex < compptr->MCU_height; yindex++) { + if (coef->iMCU_row_num < last_iMCU_row || + yindex+yoffset < compptr->last_row_height) { + /* Fill in pointers to real blocks in this row */ + buffer_ptr = buffer[ci][yindex+yoffset] + start_col; + for (xindex = 0; xindex < blockcnt; xindex++) + MCU_buffer[blkn++] = buffer_ptr++; + } else { + /* At bottom of image, need a whole row of dummy blocks */ + xindex = 0; + } + /* Fill in any dummy blocks needed in this row. + * Dummy blocks are filled in the same way as in jccoefct.c: + * all zeroes in the AC entries, DC entries equal to previous + * block's DC value. The init routine has already zeroed the + * AC entries, so we need only set the DC entries correctly. + */ + for (; xindex < compptr->MCU_width; xindex++) { + MCU_buffer[blkn] = coef->dummy_buffer[blkn]; + MCU_buffer[blkn][0][0] = MCU_buffer[blkn-1][0][0]; + blkn++; + } + } + } + /* Try to write the MCU. */ + if (! (*cinfo->entropy->encode_mcu) (cinfo, MCU_buffer)) { + /* Suspension forced; update state counters and exit */ + coef->MCU_vert_offset = yoffset; + coef->mcu_ctr = MCU_col_num; + return FALSE; + } + } + /* Completed an MCU row, but perhaps not an iMCU row */ + coef->mcu_ctr = 0; + } + /* Completed the iMCU row, advance counters for next one */ + coef->iMCU_row_num++; + start_iMCU_row(cinfo); + return TRUE; +} + + +/* + * Initialize coefficient buffer controller. + * + * Each passed coefficient array must be the right size for that + * coefficient: width_in_blocks wide and height_in_blocks high, + * with unitheight at least v_samp_factor. + */ + +LOCAL(void) +transencode_coef_controller (j_compress_ptr cinfo, + jvirt_barray_ptr * coef_arrays) +{ + my_coef_ptr coef; + JBLOCKROW buffer; + int i; + + coef = (my_coef_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_coef_controller)); + cinfo->coef = (struct jpeg_c_coef_controller *) coef; + coef->pub.start_pass = start_pass_coef; + coef->pub.compress_data = compress_output; + + /* Save pointer to virtual arrays */ + coef->whole_image = coef_arrays; + + /* Allocate and pre-zero space for dummy DCT blocks. */ + buffer = (JBLOCKROW) + (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE, + C_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK)); + jzero_far((void FAR *) buffer, C_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK)); + for (i = 0; i < C_MAX_BLOCKS_IN_MCU; i++) { + coef->dummy_buffer[i] = buffer + i; + } +} diff --git a/mk4/modimage/jpeg-6b/jdapimin.c b/mk4/modimage/jpeg-6b/jdapimin.c new file mode 100644 index 0000000..cadb59f --- /dev/null +++ b/mk4/modimage/jpeg-6b/jdapimin.c @@ -0,0 +1,395 @@ +/* + * jdapimin.c + * + * Copyright (C) 1994-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains application interface code for the decompression half + * of the JPEG library. These are the "minimum" API routines that may be + * needed in either the normal full-decompression case or the + * transcoding-only case. + * + * Most of the routines intended to be called directly by an application + * are in this file or in jdapistd.c. But also see jcomapi.c for routines + * shared by compression and decompression, and jdtrans.c for the transcoding + * case. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * Initialization of a JPEG decompression object. + * The error manager must already be set up (in case memory manager fails). + */ + +GLOBAL(void) +jpeg_CreateDecompress (j_decompress_ptr cinfo, int version, size_t structsize) +{ + int i; + + /* Guard against version mismatches between library and caller. */ + cinfo->mem = NULL; /* so jpeg_destroy knows mem mgr not called */ + if (version != JPEG_LIB_VERSION) + ERREXIT2(cinfo, JERR_BAD_LIB_VERSION, JPEG_LIB_VERSION, version); + if (structsize != SIZEOF(struct jpeg_decompress_struct)) + ERREXIT2(cinfo, JERR_BAD_STRUCT_SIZE, + (int) SIZEOF(struct jpeg_decompress_struct), (int) structsize); + + /* For debugging purposes, we zero the whole master structure. + * But the application has already set the err pointer, and may have set + * client_data, so we have to save and restore those fields. + * Note: if application hasn't set client_data, tools like Purify may + * complain here. + */ + { + struct jpeg_error_mgr * err = cinfo->err; + void * client_data = cinfo->client_data; /* ignore Purify complaint here */ + MEMZERO(cinfo, SIZEOF(struct jpeg_decompress_struct)); + cinfo->err = err; + cinfo->client_data = client_data; + } + cinfo->is_decompressor = TRUE; + + /* Initialize a memory manager instance for this object */ + jinit_memory_mgr((j_common_ptr) cinfo); + + /* Zero out pointers to permanent structures. */ + cinfo->progress = NULL; + cinfo->src = NULL; + + for (i = 0; i < NUM_QUANT_TBLS; i++) + cinfo->quant_tbl_ptrs[i] = NULL; + + for (i = 0; i < NUM_HUFF_TBLS; i++) { + cinfo->dc_huff_tbl_ptrs[i] = NULL; + cinfo->ac_huff_tbl_ptrs[i] = NULL; + } + + /* Initialize marker processor so application can override methods + * for COM, APPn markers before calling jpeg_read_header. + */ + cinfo->marker_list = NULL; + jinit_marker_reader(cinfo); + + /* And initialize the overall input controller. */ + jinit_input_controller(cinfo); + + /* OK, I'm ready */ + cinfo->global_state = DSTATE_START; +} + + +/* + * Destruction of a JPEG decompression object + */ + +GLOBAL(void) +jpeg_destroy_decompress (j_decompress_ptr cinfo) +{ + jpeg_destroy((j_common_ptr) cinfo); /* use common routine */ +} + + +/* + * Abort processing of a JPEG decompression operation, + * but don't destroy the object itself. + */ + +GLOBAL(void) +jpeg_abort_decompress (j_decompress_ptr cinfo) +{ + jpeg_abort((j_common_ptr) cinfo); /* use common routine */ +} + + +/* + * Set default decompression parameters. + */ + +LOCAL(void) +default_decompress_parms (j_decompress_ptr cinfo) +{ + /* Guess the input colorspace, and set output colorspace accordingly. */ + /* (Wish JPEG committee had provided a real way to specify this...) */ + /* Note application may override our guesses. */ + switch (cinfo->num_components) { + case 1: + cinfo->jpeg_color_space = JCS_GRAYSCALE; + cinfo->out_color_space = JCS_GRAYSCALE; + break; + + case 3: + if (cinfo->saw_JFIF_marker) { + cinfo->jpeg_color_space = JCS_YCbCr; /* JFIF implies YCbCr */ + } else if (cinfo->saw_Adobe_marker) { + switch (cinfo->Adobe_transform) { + case 0: + cinfo->jpeg_color_space = JCS_RGB; + break; + case 1: + cinfo->jpeg_color_space = JCS_YCbCr; + break; + default: + WARNMS1(cinfo, JWRN_ADOBE_XFORM, cinfo->Adobe_transform); + cinfo->jpeg_color_space = JCS_YCbCr; /* assume it's YCbCr */ + break; + } + } else { + /* Saw no special markers, try to guess from the component IDs */ + int cid0 = cinfo->comp_info[0].component_id; + int cid1 = cinfo->comp_info[1].component_id; + int cid2 = cinfo->comp_info[2].component_id; + + if (cid0 == 1 && cid1 == 2 && cid2 == 3) + cinfo->jpeg_color_space = JCS_YCbCr; /* assume JFIF w/out marker */ + else if (cid0 == 82 && cid1 == 71 && cid2 == 66) + cinfo->jpeg_color_space = JCS_RGB; /* ASCII 'R', 'G', 'B' */ + else { + TRACEMS3(cinfo, 1, JTRC_UNKNOWN_IDS, cid0, cid1, cid2); + cinfo->jpeg_color_space = JCS_YCbCr; /* assume it's YCbCr */ + } + } + /* Always guess RGB is proper output colorspace. */ + cinfo->out_color_space = JCS_RGB; + break; + + case 4: + if (cinfo->saw_Adobe_marker) { + switch (cinfo->Adobe_transform) { + case 0: + cinfo->jpeg_color_space = JCS_CMYK; + break; + case 2: + cinfo->jpeg_color_space = JCS_YCCK; + break; + default: + WARNMS1(cinfo, JWRN_ADOBE_XFORM, cinfo->Adobe_transform); + cinfo->jpeg_color_space = JCS_YCCK; /* assume it's YCCK */ + break; + } + } else { + /* No special markers, assume straight CMYK. */ + cinfo->jpeg_color_space = JCS_CMYK; + } + cinfo->out_color_space = JCS_CMYK; + break; + + default: + cinfo->jpeg_color_space = JCS_UNKNOWN; + cinfo->out_color_space = JCS_UNKNOWN; + break; + } + + /* Set defaults for other decompression parameters. */ + cinfo->scale_num = 1; /* 1:1 scaling */ + cinfo->scale_denom = 1; + cinfo->output_gamma = 1.0; + cinfo->buffered_image = FALSE; + cinfo->raw_data_out = FALSE; + cinfo->dct_method = JDCT_DEFAULT; + cinfo->do_fancy_upsampling = TRUE; + cinfo->do_block_smoothing = TRUE; + cinfo->quantize_colors = FALSE; + /* We set these in case application only sets quantize_colors. */ + cinfo->dither_mode = JDITHER_FS; +#ifdef QUANT_2PASS_SUPPORTED + cinfo->two_pass_quantize = TRUE; +#else + cinfo->two_pass_quantize = FALSE; +#endif + cinfo->desired_number_of_colors = 256; + cinfo->colormap = NULL; + /* Initialize for no mode change in buffered-image mode. */ + cinfo->enable_1pass_quant = FALSE; + cinfo->enable_external_quant = FALSE; + cinfo->enable_2pass_quant = FALSE; +} + + +/* + * Decompression startup: read start of JPEG datastream to see what's there. + * Need only initialize JPEG object and supply a data source before calling. + * + * This routine will read as far as the first SOS marker (ie, actual start of + * compressed data), and will save all tables and parameters in the JPEG + * object. It will also initialize the decompression parameters to default + * values, and finally return JPEG_HEADER_OK. On return, the application may + * adjust the decompression parameters and then call jpeg_start_decompress. + * (Or, if the application only wanted to determine the image parameters, + * the data need not be decompressed. In that case, call jpeg_abort or + * jpeg_destroy to release any temporary space.) + * If an abbreviated (tables only) datastream is presented, the routine will + * return JPEG_HEADER_TABLES_ONLY upon reaching EOI. The application may then + * re-use the JPEG object to read the abbreviated image datastream(s). + * It is unnecessary (but OK) to call jpeg_abort in this case. + * The JPEG_SUSPENDED return code only occurs if the data source module + * requests suspension of the decompressor. In this case the application + * should load more source data and then re-call jpeg_read_header to resume + * processing. + * If a non-suspending data source is used and require_image is TRUE, then the + * return code need not be inspected since only JPEG_HEADER_OK is possible. + * + * This routine is now just a front end to jpeg_consume_input, with some + * extra error checking. + */ + +GLOBAL(int) +jpeg_read_header (j_decompress_ptr cinfo, boolean require_image) +{ + int retcode; + + if (cinfo->global_state != DSTATE_START && + cinfo->global_state != DSTATE_INHEADER) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + retcode = jpeg_consume_input(cinfo); + + switch (retcode) { + case JPEG_REACHED_SOS: + retcode = JPEG_HEADER_OK; + break; + case JPEG_REACHED_EOI: + if (require_image) /* Complain if application wanted an image */ + ERREXIT(cinfo, JERR_NO_IMAGE); + /* Reset to start state; it would be safer to require the application to + * call jpeg_abort, but we can't change it now for compatibility reasons. + * A side effect is to free any temporary memory (there shouldn't be any). + */ + jpeg_abort((j_common_ptr) cinfo); /* sets state = DSTATE_START */ + retcode = JPEG_HEADER_TABLES_ONLY; + break; + case JPEG_SUSPENDED: + /* no work */ + break; + } + + return retcode; +} + + +/* + * Consume data in advance of what the decompressor requires. + * This can be called at any time once the decompressor object has + * been created and a data source has been set up. + * + * This routine is essentially a state machine that handles a couple + * of critical state-transition actions, namely initial setup and + * transition from header scanning to ready-for-start_decompress. + * All the actual input is done via the input controller's consume_input + * method. + */ + +GLOBAL(int) +jpeg_consume_input (j_decompress_ptr cinfo) +{ + int retcode = JPEG_SUSPENDED; + + /* NB: every possible DSTATE value should be listed in this switch */ + switch (cinfo->global_state) { + case DSTATE_START: + /* Start-of-datastream actions: reset appropriate modules */ + (*cinfo->inputctl->reset_input_controller) (cinfo); + /* Initialize application's data source module */ + (*cinfo->src->init_source) (cinfo); + cinfo->global_state = DSTATE_INHEADER; + /*FALLTHROUGH*/ + case DSTATE_INHEADER: + retcode = (*cinfo->inputctl->consume_input) (cinfo); + if (retcode == JPEG_REACHED_SOS) { /* Found SOS, prepare to decompress */ + /* Set up default parameters based on header data */ + default_decompress_parms(cinfo); + /* Set global state: ready for start_decompress */ + cinfo->global_state = DSTATE_READY; + } + break; + case DSTATE_READY: + /* Can't advance past first SOS until start_decompress is called */ + retcode = JPEG_REACHED_SOS; + break; + case DSTATE_PRELOAD: + case DSTATE_PRESCAN: + case DSTATE_SCANNING: + case DSTATE_RAW_OK: + case DSTATE_BUFIMAGE: + case DSTATE_BUFPOST: + case DSTATE_STOPPING: + retcode = (*cinfo->inputctl->consume_input) (cinfo); + break; + default: + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + } + return retcode; +} + + +/* + * Have we finished reading the input file? + */ + +GLOBAL(boolean) +jpeg_input_complete (j_decompress_ptr cinfo) +{ + /* Check for valid jpeg object */ + if (cinfo->global_state < DSTATE_START || + cinfo->global_state > DSTATE_STOPPING) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + return cinfo->inputctl->eoi_reached; +} + + +/* + * Is there more than one scan? + */ + +GLOBAL(boolean) +jpeg_has_multiple_scans (j_decompress_ptr cinfo) +{ + /* Only valid after jpeg_read_header completes */ + if (cinfo->global_state < DSTATE_READY || + cinfo->global_state > DSTATE_STOPPING) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + return cinfo->inputctl->has_multiple_scans; +} + + +/* + * Finish JPEG decompression. + * + * This will normally just verify the file trailer and release temp storage. + * + * Returns FALSE if suspended. The return value need be inspected only if + * a suspending data source is used. + */ + +GLOBAL(boolean) +jpeg_finish_decompress (j_decompress_ptr cinfo) +{ + if ((cinfo->global_state == DSTATE_SCANNING || + cinfo->global_state == DSTATE_RAW_OK) && ! cinfo->buffered_image) { + /* Terminate final pass of non-buffered mode */ + if (cinfo->output_scanline < cinfo->output_height) + ERREXIT(cinfo, JERR_TOO_LITTLE_DATA); + (*cinfo->master->finish_output_pass) (cinfo); + cinfo->global_state = DSTATE_STOPPING; + } else if (cinfo->global_state == DSTATE_BUFIMAGE) { + /* Finishing after a buffered-image operation */ + cinfo->global_state = DSTATE_STOPPING; + } else if (cinfo->global_state != DSTATE_STOPPING) { + /* STOPPING = repeat call after a suspension, anything else is error */ + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + } + /* Read until EOI */ + while (! cinfo->inputctl->eoi_reached) { + if ((*cinfo->inputctl->consume_input) (cinfo) == JPEG_SUSPENDED) + return FALSE; /* Suspend, come back later */ + } + /* Do final cleanup */ + (*cinfo->src->term_source) (cinfo); + /* We can use jpeg_abort to release memory and reset global_state */ + jpeg_abort((j_common_ptr) cinfo); + return TRUE; +} diff --git a/mk4/modimage/jpeg-6b/jdapistd.c b/mk4/modimage/jpeg-6b/jdapistd.c new file mode 100644 index 0000000..c8e3fa0 --- /dev/null +++ b/mk4/modimage/jpeg-6b/jdapistd.c @@ -0,0 +1,275 @@ +/* + * jdapistd.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains application interface code for the decompression half + * of the JPEG library. These are the "standard" API routines that are + * used in the normal full-decompression case. They are not used by a + * transcoding-only application. Note that if an application links in + * jpeg_start_decompress, it will end up linking in the entire decompressor. + * We thus must separate this file from jdapimin.c to avoid linking the + * whole decompression library into a transcoder. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Forward declarations */ +LOCAL(boolean) output_pass_setup JPP((j_decompress_ptr cinfo)); + + +/* + * Decompression initialization. + * jpeg_read_header must be completed before calling this. + * + * If a multipass operating mode was selected, this will do all but the + * last pass, and thus may take a great deal of time. + * + * Returns FALSE if suspended. The return value need be inspected only if + * a suspending data source is used. + */ + +GLOBAL(boolean) +jpeg_start_decompress (j_decompress_ptr cinfo) +{ + if (cinfo->global_state == DSTATE_READY) { + /* First call: initialize master control, select active modules */ + jinit_master_decompress(cinfo); + if (cinfo->buffered_image) { + /* No more work here; expecting jpeg_start_output next */ + cinfo->global_state = DSTATE_BUFIMAGE; + return TRUE; + } + cinfo->global_state = DSTATE_PRELOAD; + } + if (cinfo->global_state == DSTATE_PRELOAD) { + /* If file has multiple scans, absorb them all into the coef buffer */ + if (cinfo->inputctl->has_multiple_scans) { +#ifdef D_MULTISCAN_FILES_SUPPORTED + for (;;) { + int retcode; + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + /* Absorb some more input */ + retcode = (*cinfo->inputctl->consume_input) (cinfo); + if (retcode == JPEG_SUSPENDED) + return FALSE; + if (retcode == JPEG_REACHED_EOI) + break; + /* Advance progress counter if appropriate */ + if (cinfo->progress != NULL && + (retcode == JPEG_ROW_COMPLETED || retcode == JPEG_REACHED_SOS)) { + if (++cinfo->progress->pass_counter >= cinfo->progress->pass_limit) { + /* jdmaster underestimated number of scans; ratchet up one scan */ + cinfo->progress->pass_limit += (long) cinfo->total_iMCU_rows; + } + } + } +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif /* D_MULTISCAN_FILES_SUPPORTED */ + } + cinfo->output_scan_number = cinfo->input_scan_number; + } else if (cinfo->global_state != DSTATE_PRESCAN) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + /* Perform any dummy output passes, and set up for the final pass */ + return output_pass_setup(cinfo); +} + + +/* + * Set up for an output pass, and perform any dummy pass(es) needed. + * Common subroutine for jpeg_start_decompress and jpeg_start_output. + * Entry: global_state = DSTATE_PRESCAN only if previously suspended. + * Exit: If done, returns TRUE and sets global_state for proper output mode. + * If suspended, returns FALSE and sets global_state = DSTATE_PRESCAN. + */ + +LOCAL(boolean) +output_pass_setup (j_decompress_ptr cinfo) +{ + if (cinfo->global_state != DSTATE_PRESCAN) { + /* First call: do pass setup */ + (*cinfo->master->prepare_for_output_pass) (cinfo); + cinfo->output_scanline = 0; + cinfo->global_state = DSTATE_PRESCAN; + } + /* Loop over any required dummy passes */ + while (cinfo->master->is_dummy_pass) { +#ifdef QUANT_2PASS_SUPPORTED + /* Crank through the dummy pass */ + while (cinfo->output_scanline < cinfo->output_height) { + JDIMENSION last_scanline; + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) { + cinfo->progress->pass_counter = (long) cinfo->output_scanline; + cinfo->progress->pass_limit = (long) cinfo->output_height; + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + } + /* Process some data */ + last_scanline = cinfo->output_scanline; + (*cinfo->main->process_data) (cinfo, (JSAMPARRAY) NULL, + &cinfo->output_scanline, (JDIMENSION) 0); + if (cinfo->output_scanline == last_scanline) + return FALSE; /* No progress made, must suspend */ + } + /* Finish up dummy pass, and set up for another one */ + (*cinfo->master->finish_output_pass) (cinfo); + (*cinfo->master->prepare_for_output_pass) (cinfo); + cinfo->output_scanline = 0; +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif /* QUANT_2PASS_SUPPORTED */ + } + /* Ready for application to drive output pass through + * jpeg_read_scanlines or jpeg_read_raw_data. + */ + cinfo->global_state = cinfo->raw_data_out ? DSTATE_RAW_OK : DSTATE_SCANNING; + return TRUE; +} + + +/* + * Read some scanlines of data from the JPEG decompressor. + * + * The return value will be the number of lines actually read. + * This may be less than the number requested in several cases, + * including bottom of image, data source suspension, and operating + * modes that emit multiple scanlines at a time. + * + * Note: we warn about excess calls to jpeg_read_scanlines() since + * this likely signals an application programmer error. However, + * an oversize buffer (max_lines > scanlines remaining) is not an error. + */ + +GLOBAL(JDIMENSION) +jpeg_read_scanlines (j_decompress_ptr cinfo, JSAMPARRAY scanlines, + JDIMENSION max_lines) +{ + JDIMENSION row_ctr; + + if (cinfo->global_state != DSTATE_SCANNING) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + if (cinfo->output_scanline >= cinfo->output_height) { + WARNMS(cinfo, JWRN_TOO_MUCH_DATA); + return 0; + } + + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) { + cinfo->progress->pass_counter = (long) cinfo->output_scanline; + cinfo->progress->pass_limit = (long) cinfo->output_height; + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + } + + /* Process some data */ + row_ctr = 0; + (*cinfo->main->process_data) (cinfo, scanlines, &row_ctr, max_lines); + cinfo->output_scanline += row_ctr; + return row_ctr; +} + + +/* + * Alternate entry point to read raw data. + * Processes exactly one iMCU row per call, unless suspended. + */ + +GLOBAL(JDIMENSION) +jpeg_read_raw_data (j_decompress_ptr cinfo, JSAMPIMAGE data, + JDIMENSION max_lines) +{ + JDIMENSION lines_per_iMCU_row; + + if (cinfo->global_state != DSTATE_RAW_OK) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + if (cinfo->output_scanline >= cinfo->output_height) { + WARNMS(cinfo, JWRN_TOO_MUCH_DATA); + return 0; + } + + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) { + cinfo->progress->pass_counter = (long) cinfo->output_scanline; + cinfo->progress->pass_limit = (long) cinfo->output_height; + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + } + + /* Verify that at least one iMCU row can be returned. */ + lines_per_iMCU_row = cinfo->max_v_samp_factor * cinfo->min_DCT_scaled_size; + if (max_lines < lines_per_iMCU_row) + ERREXIT(cinfo, JERR_BUFFER_SIZE); + + /* Decompress directly into user's buffer. */ + if (! (*cinfo->coef->decompress_data) (cinfo, data)) + return 0; /* suspension forced, can do nothing more */ + + /* OK, we processed one iMCU row. */ + cinfo->output_scanline += lines_per_iMCU_row; + return lines_per_iMCU_row; +} + + +/* Additional entry points for buffered-image mode. */ + +#ifdef D_MULTISCAN_FILES_SUPPORTED + +/* + * Initialize for an output pass in buffered-image mode. + */ + +GLOBAL(boolean) +jpeg_start_output (j_decompress_ptr cinfo, int scan_number) +{ + if (cinfo->global_state != DSTATE_BUFIMAGE && + cinfo->global_state != DSTATE_PRESCAN) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + /* Limit scan number to valid range */ + if (scan_number <= 0) + scan_number = 1; + if (cinfo->inputctl->eoi_reached && + scan_number > cinfo->input_scan_number) + scan_number = cinfo->input_scan_number; + cinfo->output_scan_number = scan_number; + /* Perform any dummy output passes, and set up for the real pass */ + return output_pass_setup(cinfo); +} + + +/* + * Finish up after an output pass in buffered-image mode. + * + * Returns FALSE if suspended. The return value need be inspected only if + * a suspending data source is used. + */ + +GLOBAL(boolean) +jpeg_finish_output (j_decompress_ptr cinfo) +{ + if ((cinfo->global_state == DSTATE_SCANNING || + cinfo->global_state == DSTATE_RAW_OK) && cinfo->buffered_image) { + /* Terminate this pass. */ + /* We do not require the whole pass to have been completed. */ + (*cinfo->master->finish_output_pass) (cinfo); + cinfo->global_state = DSTATE_BUFPOST; + } else if (cinfo->global_state != DSTATE_BUFPOST) { + /* BUFPOST = repeat call after a suspension, anything else is error */ + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + } + /* Read markers looking for SOS or EOI */ + while (cinfo->input_scan_number <= cinfo->output_scan_number && + ! cinfo->inputctl->eoi_reached) { + if ((*cinfo->inputctl->consume_input) (cinfo) == JPEG_SUSPENDED) + return FALSE; /* Suspend, come back later */ + } + cinfo->global_state = DSTATE_BUFIMAGE; + return TRUE; +} + +#endif /* D_MULTISCAN_FILES_SUPPORTED */ diff --git a/mk4/modimage/jpeg-6b/jdatadst.c b/mk4/modimage/jpeg-6b/jdatadst.c new file mode 100644 index 0000000..a8f6fb0 --- /dev/null +++ b/mk4/modimage/jpeg-6b/jdatadst.c @@ -0,0 +1,151 @@ +/* + * jdatadst.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains compression data destination routines for the case of + * emitting JPEG data to a file (or any stdio stream). While these routines + * are sufficient for most applications, some will want to use a different + * destination manager. + * IMPORTANT: we assume that fwrite() will correctly transcribe an array of + * JOCTETs into 8-bit-wide elements on external storage. If char is wider + * than 8 bits on your machine, you may need to do some tweaking. + */ + +/* this is not a core library module, so it doesn't define JPEG_INTERNALS */ +#include "jinclude.h" +#include "jpeglib.h" +#include "jerror.h" + + +/* Expanded data destination object for stdio output */ + +typedef struct { + struct jpeg_destination_mgr pub; /* public fields */ + + FILE * outfile; /* target stream */ + JOCTET * buffer; /* start of buffer */ +} my_destination_mgr; + +typedef my_destination_mgr * my_dest_ptr; + +#define OUTPUT_BUF_SIZE 4096 /* choose an efficiently fwrite'able size */ + + +/* + * Initialize destination --- called by jpeg_start_compress + * before any data is actually written. + */ + +METHODDEF(void) +init_destination (j_compress_ptr cinfo) +{ + my_dest_ptr dest = (my_dest_ptr) cinfo->dest; + + /* Allocate the output buffer --- it will be released when done with image */ + dest->buffer = (JOCTET *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + OUTPUT_BUF_SIZE * SIZEOF(JOCTET)); + + dest->pub.next_output_byte = dest->buffer; + dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; +} + + +/* + * Empty the output buffer --- called whenever buffer fills up. + * + * In typical applications, this should write the entire output buffer + * (ignoring the current state of next_output_byte & free_in_buffer), + * reset the pointer & count to the start of the buffer, and return TRUE + * indicating that the buffer has been dumped. + * + * In applications that need to be able to suspend compression due to output + * overrun, a FALSE return indicates that the buffer cannot be emptied now. + * In this situation, the compressor will return to its caller (possibly with + * an indication that it has not accepted all the supplied scanlines). The + * application should resume compression after it has made more room in the + * output buffer. Note that there are substantial restrictions on the use of + * suspension --- see the documentation. + * + * When suspending, the compressor will back up to a convenient restart point + * (typically the start of the current MCU). next_output_byte & free_in_buffer + * indicate where the restart point will be if the current call returns FALSE. + * Data beyond this point will be regenerated after resumption, so do not + * write it out when emptying the buffer externally. + */ + +METHODDEF(boolean) +empty_output_buffer (j_compress_ptr cinfo) +{ + my_dest_ptr dest = (my_dest_ptr) cinfo->dest; + + if (JFWRITE(dest->outfile, dest->buffer, OUTPUT_BUF_SIZE) != + (size_t) OUTPUT_BUF_SIZE) + ERREXIT(cinfo, JERR_FILE_WRITE); + + dest->pub.next_output_byte = dest->buffer; + dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; + + return TRUE; +} + + +/* + * Terminate destination --- called by jpeg_finish_compress + * after all data has been written. Usually needs to flush buffer. + * + * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding + * application must deal with any cleanup that should happen even + * for error exit. + */ + +METHODDEF(void) +term_destination (j_compress_ptr cinfo) +{ + my_dest_ptr dest = (my_dest_ptr) cinfo->dest; + size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer; + + /* Write any data remaining in the buffer */ + if (datacount > 0) { + if (JFWRITE(dest->outfile, dest->buffer, datacount) != datacount) + ERREXIT(cinfo, JERR_FILE_WRITE); + } + fflush(dest->outfile); + /* Make sure we wrote the output file OK */ + if (ferror(dest->outfile)) + ERREXIT(cinfo, JERR_FILE_WRITE); +} + + +/* + * Prepare for output to a stdio stream. + * The caller must have already opened the stream, and is responsible + * for closing it after finishing compression. + */ + +GLOBAL(void) +jpeg_stdio_dest (j_compress_ptr cinfo, FILE * outfile) +{ + my_dest_ptr dest; + + /* The destination object is made permanent so that multiple JPEG images + * can be written to the same file without re-executing jpeg_stdio_dest. + * This makes it dangerous to use this manager and a different destination + * manager serially with the same JPEG object, because their private object + * sizes may be different. Caveat programmer. + */ + if (cinfo->dest == NULL) { /* first time for this JPEG object? */ + cinfo->dest = (struct jpeg_destination_mgr *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + SIZEOF(my_destination_mgr)); + } + + dest = (my_dest_ptr) cinfo->dest; + dest->pub.init_destination = init_destination; + dest->pub.empty_output_buffer = empty_output_buffer; + dest->pub.term_destination = term_destination; + dest->outfile = outfile; +} diff --git a/mk4/modimage/jpeg-6b/jdatasrc.c b/mk4/modimage/jpeg-6b/jdatasrc.c new file mode 100644 index 0000000..edc752b --- /dev/null +++ b/mk4/modimage/jpeg-6b/jdatasrc.c @@ -0,0 +1,212 @@ +/* + * jdatasrc.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains decompression data source routines for the case of + * reading JPEG data from a file (or any stdio stream). While these routines + * are sufficient for most applications, some will want to use a different + * source manager. + * IMPORTANT: we assume that fread() will correctly transcribe an array of + * JOCTETs from 8-bit-wide elements on external storage. If char is wider + * than 8 bits on your machine, you may need to do some tweaking. + */ + +/* this is not a core library module, so it doesn't define JPEG_INTERNALS */ +#include "jinclude.h" +#include "jpeglib.h" +#include "jerror.h" + + +/* Expanded data source object for stdio input */ + +typedef struct { + struct jpeg_source_mgr pub; /* public fields */ + + FILE * infile; /* source stream */ + JOCTET * buffer; /* start of buffer */ + boolean start_of_file; /* have we gotten any data yet? */ +} my_source_mgr; + +typedef my_source_mgr * my_src_ptr; + +#define INPUT_BUF_SIZE 4096 /* choose an efficiently fread'able size */ + + +/* + * Initialize source --- called by jpeg_read_header + * before any data is actually read. + */ + +METHODDEF(void) +init_source (j_decompress_ptr cinfo) +{ + my_src_ptr src = (my_src_ptr) cinfo->src; + + /* We reset the empty-input-file flag for each image, + * but we don't clear the input buffer. + * This is correct behavior for reading a series of images from one source. + */ + src->start_of_file = TRUE; +} + + +/* + * Fill the input buffer --- called whenever buffer is emptied. + * + * In typical applications, this should read fresh data into the buffer + * (ignoring the current state of next_input_byte & bytes_in_buffer), + * reset the pointer & count to the start of the buffer, and return TRUE + * indicating that the buffer has been reloaded. It is not necessary to + * fill the buffer entirely, only to obtain at least one more byte. + * + * There is no such thing as an EOF return. If the end of the file has been + * reached, the routine has a choice of ERREXIT() or inserting fake data into + * the buffer. In most cases, generating a warning message and inserting a + * fake EOI marker is the best course of action --- this will allow the + * decompressor to output however much of the image is there. However, + * the resulting error message is misleading if the real problem is an empty + * input file, so we handle that case specially. + * + * In applications that need to be able to suspend compression due to input + * not being available yet, a FALSE return indicates that no more data can be + * obtained right now, but more may be forthcoming later. In this situation, + * the decompressor will return to its caller (with an indication of the + * number of scanlines it has read, if any). The application should resume + * decompression after it has loaded more data into the input buffer. Note + * that there are substantial restrictions on the use of suspension --- see + * the documentation. + * + * When suspending, the decompressor will back up to a convenient restart point + * (typically the start of the current MCU). next_input_byte & bytes_in_buffer + * indicate where the restart point will be if the current call returns FALSE. + * Data beyond this point must be rescanned after resumption, so move it to + * the front of the buffer rather than discarding it. + */ + +METHODDEF(boolean) +fill_input_buffer (j_decompress_ptr cinfo) +{ + my_src_ptr src = (my_src_ptr) cinfo->src; + size_t nbytes; + + nbytes = JFREAD(src->infile, src->buffer, INPUT_BUF_SIZE); + + if (nbytes <= 0) { + if (src->start_of_file) /* Treat empty input file as fatal error */ + ERREXIT(cinfo, JERR_INPUT_EMPTY); + WARNMS(cinfo, JWRN_JPEG_EOF); + /* Insert a fake EOI marker */ + src->buffer[0] = (JOCTET) 0xFF; + src->buffer[1] = (JOCTET) JPEG_EOI; + nbytes = 2; + } + + src->pub.next_input_byte = src->buffer; + src->pub.bytes_in_buffer = nbytes; + src->start_of_file = FALSE; + + return TRUE; +} + + +/* + * Skip data --- used to skip over a potentially large amount of + * uninteresting data (such as an APPn marker). + * + * Writers of suspendable-input applications must note that skip_input_data + * is not granted the right to give a suspension return. If the skip extends + * beyond the data currently in the buffer, the buffer can be marked empty so + * that the next read will cause a fill_input_buffer call that can suspend. + * Arranging for additional bytes to be discarded before reloading the input + * buffer is the application writer's problem. + */ + +METHODDEF(void) +skip_input_data (j_decompress_ptr cinfo, long num_bytes) +{ + my_src_ptr src = (my_src_ptr) cinfo->src; + + /* Just a dumb implementation for now. Could use fseek() except + * it doesn't work on pipes. Not clear that being smart is worth + * any trouble anyway --- large skips are infrequent. + */ + if (num_bytes > 0) { + while (num_bytes > (long) src->pub.bytes_in_buffer) { + num_bytes -= (long) src->pub.bytes_in_buffer; + (void) fill_input_buffer(cinfo); + /* note we assume that fill_input_buffer will never return FALSE, + * so suspension need not be handled. + */ + } + src->pub.next_input_byte += (size_t) num_bytes; + src->pub.bytes_in_buffer -= (size_t) num_bytes; + } +} + + +/* + * An additional method that can be provided by data source modules is the + * resync_to_restart method for error recovery in the presence of RST markers. + * For the moment, this source module just uses the default resync method + * provided by the JPEG library. That method assumes that no backtracking + * is possible. + */ + + +/* + * Terminate source --- called by jpeg_finish_decompress + * after all data has been read. Often a no-op. + * + * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding + * application must deal with any cleanup that should happen even + * for error exit. + */ + +METHODDEF(void) +term_source (j_decompress_ptr cinfo) +{ + /* no work necessary here */ +} + + +/* + * Prepare for input from a stdio stream. + * The caller must have already opened the stream, and is responsible + * for closing it after finishing decompression. + */ + +GLOBAL(void) +jpeg_stdio_src (j_decompress_ptr cinfo, FILE * infile) +{ + my_src_ptr src; + + /* The source object and input buffer are made permanent so that a series + * of JPEG images can be read from the same file by calling jpeg_stdio_src + * only before the first one. (If we discarded the buffer at the end of + * one image, we'd likely lose the start of the next one.) + * This makes it unsafe to use this manager and a different source + * manager serially with the same JPEG object. Caveat programmer. + */ + if (cinfo->src == NULL) { /* first time for this JPEG object? */ + cinfo->src = (struct jpeg_source_mgr *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + SIZEOF(my_source_mgr)); + src = (my_src_ptr) cinfo->src; + src->buffer = (JOCTET *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + INPUT_BUF_SIZE * SIZEOF(JOCTET)); + } + + src = (my_src_ptr) cinfo->src; + src->pub.init_source = init_source; + src->pub.fill_input_buffer = fill_input_buffer; + src->pub.skip_input_data = skip_input_data; + src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ + src->pub.term_source = term_source; + src->infile = infile; + src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ + src->pub.next_input_byte = NULL; /* until buffer loaded */ +} diff --git a/mk4/modimage/jpeg-6b/jdcoefct.c b/mk4/modimage/jpeg-6b/jdcoefct.c new file mode 100644 index 0000000..4938d20 --- /dev/null +++ b/mk4/modimage/jpeg-6b/jdcoefct.c @@ -0,0 +1,736 @@ +/* + * jdcoefct.c + * + * Copyright (C) 1994-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the coefficient buffer controller for decompression. + * This controller is the top level of the JPEG decompressor proper. + * The coefficient buffer lies between entropy decoding and inverse-DCT steps. + * + * In buffered-image mode, this controller is the interface between + * input-oriented processing and output-oriented processing. + * Also, the input side (only) is used when reading a file for transcoding. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + +/* Block smoothing is only applicable for progressive JPEG, so: */ +#ifndef D_PROGRESSIVE_SUPPORTED +#undef BLOCK_SMOOTHING_SUPPORTED +#endif + +/* Private buffer controller object */ + +typedef struct { + struct jpeg_d_coef_controller pub; /* public fields */ + + /* These variables keep track of the current location of the input side. */ + /* cinfo->input_iMCU_row is also used for this. */ + JDIMENSION MCU_ctr; /* counts MCUs processed in current row */ + int MCU_vert_offset; /* counts MCU rows within iMCU row */ + int MCU_rows_per_iMCU_row; /* number of such rows needed */ + + /* The output side's location is represented by cinfo->output_iMCU_row. */ + + /* In single-pass modes, it's sufficient to buffer just one MCU. + * We allocate a workspace of D_MAX_BLOCKS_IN_MCU coefficient blocks, + * and let the entropy decoder write into that workspace each time. + * (On 80x86, the workspace is FAR even though it's not really very big; + * this is to keep the module interfaces unchanged when a large coefficient + * buffer is necessary.) + * In multi-pass modes, this array points to the current MCU's blocks + * within the virtual arrays; it is used only by the input side. + */ + JBLOCKROW MCU_buffer[D_MAX_BLOCKS_IN_MCU]; + +#ifdef D_MULTISCAN_FILES_SUPPORTED + /* In multi-pass modes, we need a virtual block array for each component. */ + jvirt_barray_ptr whole_image[MAX_COMPONENTS]; +#endif + +#ifdef BLOCK_SMOOTHING_SUPPORTED + /* When doing block smoothing, we latch coefficient Al values here */ + int * coef_bits_latch; +#define SAVED_COEFS 6 /* we save coef_bits[0..5] */ +#endif +} my_coef_controller; + +typedef my_coef_controller * my_coef_ptr; + +/* Forward declarations */ +METHODDEF(int) decompress_onepass + JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf)); +#ifdef D_MULTISCAN_FILES_SUPPORTED +METHODDEF(int) decompress_data + JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf)); +#endif +#ifdef BLOCK_SMOOTHING_SUPPORTED +LOCAL(boolean) smoothing_ok JPP((j_decompress_ptr cinfo)); +METHODDEF(int) decompress_smooth_data + JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf)); +#endif + + +LOCAL(void) +start_iMCU_row (j_decompress_ptr cinfo) +/* Reset within-iMCU-row counters for a new row (input side) */ +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + + /* In an interleaved scan, an MCU row is the same as an iMCU row. + * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows. + * But at the bottom of the image, process only what's left. + */ + if (cinfo->comps_in_scan > 1) { + coef->MCU_rows_per_iMCU_row = 1; + } else { + if (cinfo->input_iMCU_row < (cinfo->total_iMCU_rows-1)) + coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor; + else + coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height; + } + + coef->MCU_ctr = 0; + coef->MCU_vert_offset = 0; +} + + +/* + * Initialize for an input processing pass. + */ + +METHODDEF(void) +start_input_pass (j_decompress_ptr cinfo) +{ + cinfo->input_iMCU_row = 0; + start_iMCU_row(cinfo); +} + + +/* + * Initialize for an output processing pass. + */ + +METHODDEF(void) +start_output_pass (j_decompress_ptr cinfo) +{ +#ifdef BLOCK_SMOOTHING_SUPPORTED + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + + /* If multipass, check to see whether to use block smoothing on this pass */ + if (coef->pub.coef_arrays != NULL) { + if (cinfo->do_block_smoothing && smoothing_ok(cinfo)) + coef->pub.decompress_data = decompress_smooth_data; + else + coef->pub.decompress_data = decompress_data; + } +#endif + cinfo->output_iMCU_row = 0; +} + + +/* + * Decompress and return some data in the single-pass case. + * Always attempts to emit one fully interleaved MCU row ("iMCU" row). + * Input and output must run in lockstep since we have only a one-MCU buffer. + * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED. + * + * NB: output_buf contains a plane for each component in image, + * which we index according to the component's SOF position. + */ + +METHODDEF(int) +decompress_onepass (j_decompress_ptr cinfo, JSAMPIMAGE output_buf) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + JDIMENSION MCU_col_num; /* index of current MCU within row */ + JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1; + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + int blkn, ci, xindex, yindex, yoffset, useful_width; + JSAMPARRAY output_ptr; + JDIMENSION start_col, output_col; + jpeg_component_info *compptr; + inverse_DCT_method_ptr inverse_DCT; + + /* Loop to process as much as one whole iMCU row */ + for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row; + yoffset++) { + for (MCU_col_num = coef->MCU_ctr; MCU_col_num <= last_MCU_col; + MCU_col_num++) { + /* Try to fetch an MCU. Entropy decoder expects buffer to be zeroed. */ + jzero_far((void FAR *) coef->MCU_buffer[0], + (size_t) (cinfo->blocks_in_MCU * SIZEOF(JBLOCK))); + if (! (*cinfo->entropy->decode_mcu) (cinfo, coef->MCU_buffer)) { + /* Suspension forced; update state counters and exit */ + coef->MCU_vert_offset = yoffset; + coef->MCU_ctr = MCU_col_num; + return JPEG_SUSPENDED; + } + /* Determine where data should go in output_buf and do the IDCT thing. + * We skip dummy blocks at the right and bottom edges (but blkn gets + * incremented past them!). Note the inner loop relies on having + * allocated the MCU_buffer[] blocks sequentially. + */ + blkn = 0; /* index of current DCT block within MCU */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* Don't bother to IDCT an uninteresting component. */ + if (! compptr->component_needed) { + blkn += compptr->MCU_blocks; + continue; + } + inverse_DCT = cinfo->idct->inverse_DCT[compptr->component_index]; + useful_width = (MCU_col_num < last_MCU_col) ? compptr->MCU_width + : compptr->last_col_width; + output_ptr = output_buf[compptr->component_index] + + yoffset * compptr->DCT_scaled_size; + start_col = MCU_col_num * compptr->MCU_sample_width; + for (yindex = 0; yindex < compptr->MCU_height; yindex++) { + if (cinfo->input_iMCU_row < last_iMCU_row || + yoffset+yindex < compptr->last_row_height) { + output_col = start_col; + for (xindex = 0; xindex < useful_width; xindex++) { + (*inverse_DCT) (cinfo, compptr, + (JCOEFPTR) coef->MCU_buffer[blkn+xindex], + output_ptr, output_col); + output_col += compptr->DCT_scaled_size; + } + } + blkn += compptr->MCU_width; + output_ptr += compptr->DCT_scaled_size; + } + } + } + /* Completed an MCU row, but perhaps not an iMCU row */ + coef->MCU_ctr = 0; + } + /* Completed the iMCU row, advance counters for next one */ + cinfo->output_iMCU_row++; + if (++(cinfo->input_iMCU_row) < cinfo->total_iMCU_rows) { + start_iMCU_row(cinfo); + return JPEG_ROW_COMPLETED; + } + /* Completed the scan */ + (*cinfo->inputctl->finish_input_pass) (cinfo); + return JPEG_SCAN_COMPLETED; +} + + +/* + * Dummy consume-input routine for single-pass operation. + */ + +METHODDEF(int) +dummy_consume_data (j_decompress_ptr cinfo) +{ + return JPEG_SUSPENDED; /* Always indicate nothing was done */ +} + + +#ifdef D_MULTISCAN_FILES_SUPPORTED + +/* + * Consume input data and store it in the full-image coefficient buffer. + * We read as much as one fully interleaved MCU row ("iMCU" row) per call, + * ie, v_samp_factor block rows for each component in the scan. + * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED. + */ + +METHODDEF(int) +consume_data (j_decompress_ptr cinfo) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + JDIMENSION MCU_col_num; /* index of current MCU within row */ + int blkn, ci, xindex, yindex, yoffset; + JDIMENSION start_col; + JBLOCKARRAY buffer[MAX_COMPS_IN_SCAN]; + JBLOCKROW buffer_ptr; + jpeg_component_info *compptr; + + /* Align the virtual buffers for the components used in this scan. */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + buffer[ci] = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef->whole_image[compptr->component_index], + cinfo->input_iMCU_row * compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, TRUE); + /* Note: entropy decoder expects buffer to be zeroed, + * but this is handled automatically by the memory manager + * because we requested a pre-zeroed array. + */ + } + + /* Loop to process one whole iMCU row */ + for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row; + yoffset++) { + for (MCU_col_num = coef->MCU_ctr; MCU_col_num < cinfo->MCUs_per_row; + MCU_col_num++) { + /* Construct list of pointers to DCT blocks belonging to this MCU */ + blkn = 0; /* index of current DCT block within MCU */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + start_col = MCU_col_num * compptr->MCU_width; + for (yindex = 0; yindex < compptr->MCU_height; yindex++) { + buffer_ptr = buffer[ci][yindex+yoffset] + start_col; + for (xindex = 0; xindex < compptr->MCU_width; xindex++) { + coef->MCU_buffer[blkn++] = buffer_ptr++; + } + } + } + /* Try to fetch the MCU. */ + if (! (*cinfo->entropy->decode_mcu) (cinfo, coef->MCU_buffer)) { + /* Suspension forced; update state counters and exit */ + coef->MCU_vert_offset = yoffset; + coef->MCU_ctr = MCU_col_num; + return JPEG_SUSPENDED; + } + } + /* Completed an MCU row, but perhaps not an iMCU row */ + coef->MCU_ctr = 0; + } + /* Completed the iMCU row, advance counters for next one */ + if (++(cinfo->input_iMCU_row) < cinfo->total_iMCU_rows) { + start_iMCU_row(cinfo); + return JPEG_ROW_COMPLETED; + } + /* Completed the scan */ + (*cinfo->inputctl->finish_input_pass) (cinfo); + return JPEG_SCAN_COMPLETED; +} + + +/* + * Decompress and return some data in the multi-pass case. + * Always attempts to emit one fully interleaved MCU row ("iMCU" row). + * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED. + * + * NB: output_buf contains a plane for each component in image. + */ + +METHODDEF(int) +decompress_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + JDIMENSION block_num; + int ci, block_row, block_rows; + JBLOCKARRAY buffer; + JBLOCKROW buffer_ptr; + JSAMPARRAY output_ptr; + JDIMENSION output_col; + jpeg_component_info *compptr; + inverse_DCT_method_ptr inverse_DCT; + + /* Force some input to be done if we are getting ahead of the input. */ + while (cinfo->input_scan_number < cinfo->output_scan_number || + (cinfo->input_scan_number == cinfo->output_scan_number && + cinfo->input_iMCU_row <= cinfo->output_iMCU_row)) { + if ((*cinfo->inputctl->consume_input)(cinfo) == JPEG_SUSPENDED) + return JPEG_SUSPENDED; + } + + /* OK, output from the virtual arrays. */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Don't bother to IDCT an uninteresting component. */ + if (! compptr->component_needed) + continue; + /* Align the virtual buffer for this component. */ + buffer = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef->whole_image[ci], + cinfo->output_iMCU_row * compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, FALSE); + /* Count non-dummy DCT block rows in this iMCU row. */ + if (cinfo->output_iMCU_row < last_iMCU_row) + block_rows = compptr->v_samp_factor; + else { + /* NB: can't use last_row_height here; it is input-side-dependent! */ + block_rows = (int) (compptr->height_in_blocks % compptr->v_samp_factor); + if (block_rows == 0) block_rows = compptr->v_samp_factor; + } + inverse_DCT = cinfo->idct->inverse_DCT[ci]; + output_ptr = output_buf[ci]; + /* Loop over all DCT blocks to be processed. */ + for (block_row = 0; block_row < block_rows; block_row++) { + buffer_ptr = buffer[block_row]; + output_col = 0; + for (block_num = 0; block_num < compptr->width_in_blocks; block_num++) { + (*inverse_DCT) (cinfo, compptr, (JCOEFPTR) buffer_ptr, + output_ptr, output_col); + buffer_ptr++; + output_col += compptr->DCT_scaled_size; + } + output_ptr += compptr->DCT_scaled_size; + } + } + + if (++(cinfo->output_iMCU_row) < cinfo->total_iMCU_rows) + return JPEG_ROW_COMPLETED; + return JPEG_SCAN_COMPLETED; +} + +#endif /* D_MULTISCAN_FILES_SUPPORTED */ + + +#ifdef BLOCK_SMOOTHING_SUPPORTED + +/* + * This code applies interblock smoothing as described by section K.8 + * of the JPEG standard: the first 5 AC coefficients are estimated from + * the DC values of a DCT block and its 8 neighboring blocks. + * We apply smoothing only for progressive JPEG decoding, and only if + * the coefficients it can estimate are not yet known to full precision. + */ + +/* Natural-order array positions of the first 5 zigzag-order coefficients */ +#define Q01_POS 1 +#define Q10_POS 8 +#define Q20_POS 16 +#define Q11_POS 9 +#define Q02_POS 2 + +/* + * Determine whether block smoothing is applicable and safe. + * We also latch the current states of the coef_bits[] entries for the + * AC coefficients; otherwise, if the input side of the decompressor + * advances into a new scan, we might think the coefficients are known + * more accurately than they really are. + */ + +LOCAL(boolean) +smoothing_ok (j_decompress_ptr cinfo) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + boolean smoothing_useful = FALSE; + int ci, coefi; + jpeg_component_info *compptr; + JQUANT_TBL * qtable; + int * coef_bits; + int * coef_bits_latch; + + if (! cinfo->progressive_mode || cinfo->coef_bits == NULL) + return FALSE; + + /* Allocate latch area if not already done */ + if (coef->coef_bits_latch == NULL) + coef->coef_bits_latch = (int *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + cinfo->num_components * + (SAVED_COEFS * SIZEOF(int))); + coef_bits_latch = coef->coef_bits_latch; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* All components' quantization values must already be latched. */ + if ((qtable = compptr->quant_table) == NULL) + return FALSE; + /* Verify DC & first 5 AC quantizers are nonzero to avoid zero-divide. */ + if (qtable->quantval[0] == 0 || + qtable->quantval[Q01_POS] == 0 || + qtable->quantval[Q10_POS] == 0 || + qtable->quantval[Q20_POS] == 0 || + qtable->quantval[Q11_POS] == 0 || + qtable->quantval[Q02_POS] == 0) + return FALSE; + /* DC values must be at least partly known for all components. */ + coef_bits = cinfo->coef_bits[ci]; + if (coef_bits[0] < 0) + return FALSE; + /* Block smoothing is helpful if some AC coefficients remain inaccurate. */ + for (coefi = 1; coefi <= 5; coefi++) { + coef_bits_latch[coefi] = coef_bits[coefi]; + if (coef_bits[coefi] != 0) + smoothing_useful = TRUE; + } + coef_bits_latch += SAVED_COEFS; + } + + return smoothing_useful; +} + + +/* + * Variant of decompress_data for use when doing block smoothing. + */ + +METHODDEF(int) +decompress_smooth_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + JDIMENSION block_num, last_block_column; + int ci, block_row, block_rows, access_rows; + JBLOCKARRAY buffer; + JBLOCKROW buffer_ptr, prev_block_row, next_block_row; + JSAMPARRAY output_ptr; + JDIMENSION output_col; + jpeg_component_info *compptr; + inverse_DCT_method_ptr inverse_DCT; + boolean first_row, last_row; + JBLOCK workspace; + int *coef_bits; + JQUANT_TBL *quanttbl; + INT32 Q00,Q01,Q02,Q10,Q11,Q20, num; + int DC1,DC2,DC3,DC4,DC5,DC6,DC7,DC8,DC9; + int Al, pred; + + /* Force some input to be done if we are getting ahead of the input. */ + while (cinfo->input_scan_number <= cinfo->output_scan_number && + ! cinfo->inputctl->eoi_reached) { + if (cinfo->input_scan_number == cinfo->output_scan_number) { + /* If input is working on current scan, we ordinarily want it to + * have completed the current row. But if input scan is DC, + * we want it to keep one row ahead so that next block row's DC + * values are up to date. + */ + JDIMENSION delta = (cinfo->Ss == 0) ? 1 : 0; + if (cinfo->input_iMCU_row > cinfo->output_iMCU_row+delta) + break; + } + if ((*cinfo->inputctl->consume_input)(cinfo) == JPEG_SUSPENDED) + return JPEG_SUSPENDED; + } + + /* OK, output from the virtual arrays. */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Don't bother to IDCT an uninteresting component. */ + if (! compptr->component_needed) + continue; + /* Count non-dummy DCT block rows in this iMCU row. */ + if (cinfo->output_iMCU_row < last_iMCU_row) { + block_rows = compptr->v_samp_factor; + access_rows = block_rows * 2; /* this and next iMCU row */ + last_row = FALSE; + } else { + /* NB: can't use last_row_height here; it is input-side-dependent! */ + block_rows = (int) (compptr->height_in_blocks % compptr->v_samp_factor); + if (block_rows == 0) block_rows = compptr->v_samp_factor; + access_rows = block_rows; /* this iMCU row only */ + last_row = TRUE; + } + /* Align the virtual buffer for this component. */ + if (cinfo->output_iMCU_row > 0) { + access_rows += compptr->v_samp_factor; /* prior iMCU row too */ + buffer = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef->whole_image[ci], + (cinfo->output_iMCU_row - 1) * compptr->v_samp_factor, + (JDIMENSION) access_rows, FALSE); + buffer += compptr->v_samp_factor; /* point to current iMCU row */ + first_row = FALSE; + } else { + buffer = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef->whole_image[ci], + (JDIMENSION) 0, (JDIMENSION) access_rows, FALSE); + first_row = TRUE; + } + /* Fetch component-dependent info */ + coef_bits = coef->coef_bits_latch + (ci * SAVED_COEFS); + quanttbl = compptr->quant_table; + Q00 = quanttbl->quantval[0]; + Q01 = quanttbl->quantval[Q01_POS]; + Q10 = quanttbl->quantval[Q10_POS]; + Q20 = quanttbl->quantval[Q20_POS]; + Q11 = quanttbl->quantval[Q11_POS]; + Q02 = quanttbl->quantval[Q02_POS]; + inverse_DCT = cinfo->idct->inverse_DCT[ci]; + output_ptr = output_buf[ci]; + /* Loop over all DCT blocks to be processed. */ + for (block_row = 0; block_row < block_rows; block_row++) { + buffer_ptr = buffer[block_row]; + if (first_row && block_row == 0) + prev_block_row = buffer_ptr; + else + prev_block_row = buffer[block_row-1]; + if (last_row && block_row == block_rows-1) + next_block_row = buffer_ptr; + else + next_block_row = buffer[block_row+1]; + /* We fetch the surrounding DC values using a sliding-register approach. + * Initialize all nine here so as to do the right thing on narrow pics. + */ + DC1 = DC2 = DC3 = (int) prev_block_row[0][0]; + DC4 = DC5 = DC6 = (int) buffer_ptr[0][0]; + DC7 = DC8 = DC9 = (int) next_block_row[0][0]; + output_col = 0; + last_block_column = compptr->width_in_blocks - 1; + for (block_num = 0; block_num <= last_block_column; block_num++) { + /* Fetch current DCT block into workspace so we can modify it. */ + jcopy_block_row(buffer_ptr, (JBLOCKROW) workspace, (JDIMENSION) 1); + /* Update DC values */ + if (block_num < last_block_column) { + DC3 = (int) prev_block_row[1][0]; + DC6 = (int) buffer_ptr[1][0]; + DC9 = (int) next_block_row[1][0]; + } + /* Compute coefficient estimates per K.8. + * An estimate is applied only if coefficient is still zero, + * and is not known to be fully accurate. + */ + /* AC01 */ + if ((Al=coef_bits[1]) != 0 && workspace[1] == 0) { + num = 36 * Q00 * (DC4 - DC6); + if (num >= 0) { + pred = (int) (((Q01<<7) + num) / (Q01<<8)); + if (Al > 0 && pred >= (1< 0 && pred >= (1<= 0) { + pred = (int) (((Q10<<7) + num) / (Q10<<8)); + if (Al > 0 && pred >= (1< 0 && pred >= (1<= 0) { + pred = (int) (((Q20<<7) + num) / (Q20<<8)); + if (Al > 0 && pred >= (1< 0 && pred >= (1<= 0) { + pred = (int) (((Q11<<7) + num) / (Q11<<8)); + if (Al > 0 && pred >= (1< 0 && pred >= (1<= 0) { + pred = (int) (((Q02<<7) + num) / (Q02<<8)); + if (Al > 0 && pred >= (1< 0 && pred >= (1<DCT_scaled_size; + } + output_ptr += compptr->DCT_scaled_size; + } + } + + if (++(cinfo->output_iMCU_row) < cinfo->total_iMCU_rows) + return JPEG_ROW_COMPLETED; + return JPEG_SCAN_COMPLETED; +} + +#endif /* BLOCK_SMOOTHING_SUPPORTED */ + + +/* + * Initialize coefficient buffer controller. + */ + +GLOBAL(void) +jinit_d_coef_controller (j_decompress_ptr cinfo, boolean need_full_buffer) +{ + my_coef_ptr coef; + + coef = (my_coef_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_coef_controller)); + cinfo->coef = (struct jpeg_d_coef_controller *) coef; + coef->pub.start_input_pass = start_input_pass; + coef->pub.start_output_pass = start_output_pass; +#ifdef BLOCK_SMOOTHING_SUPPORTED + coef->coef_bits_latch = NULL; +#endif + + /* Create the coefficient buffer. */ + if (need_full_buffer) { +#ifdef D_MULTISCAN_FILES_SUPPORTED + /* Allocate a full-image virtual array for each component, */ + /* padded to a multiple of samp_factor DCT blocks in each direction. */ + /* Note we ask for a pre-zeroed array. */ + int ci, access_rows; + jpeg_component_info *compptr; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + access_rows = compptr->v_samp_factor; +#ifdef BLOCK_SMOOTHING_SUPPORTED + /* If block smoothing could be used, need a bigger window */ + if (cinfo->progressive_mode) + access_rows *= 3; +#endif + coef->whole_image[ci] = (*cinfo->mem->request_virt_barray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, TRUE, + (JDIMENSION) jround_up((long) compptr->width_in_blocks, + (long) compptr->h_samp_factor), + (JDIMENSION) jround_up((long) compptr->height_in_blocks, + (long) compptr->v_samp_factor), + (JDIMENSION) access_rows); + } + coef->pub.consume_data = consume_data; + coef->pub.decompress_data = decompress_data; + coef->pub.coef_arrays = coef->whole_image; /* link to virtual arrays */ +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else { + /* We only need a single-MCU buffer. */ + JBLOCKROW buffer; + int i; + + buffer = (JBLOCKROW) + (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE, + D_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK)); + for (i = 0; i < D_MAX_BLOCKS_IN_MCU; i++) { + coef->MCU_buffer[i] = buffer + i; + } + coef->pub.consume_data = dummy_consume_data; + coef->pub.decompress_data = decompress_onepass; + coef->pub.coef_arrays = NULL; /* flag for no virtual arrays */ + } +} diff --git a/mk4/modimage/jpeg-6b/jdcolor.c b/mk4/modimage/jpeg-6b/jdcolor.c new file mode 100644 index 0000000..6c04dfe --- /dev/null +++ b/mk4/modimage/jpeg-6b/jdcolor.c @@ -0,0 +1,396 @@ +/* + * jdcolor.c + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains output colorspace conversion routines. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Private subobject */ + +typedef struct { + struct jpeg_color_deconverter pub; /* public fields */ + + /* Private state for YCC->RGB conversion */ + int * Cr_r_tab; /* => table for Cr to R conversion */ + int * Cb_b_tab; /* => table for Cb to B conversion */ + INT32 * Cr_g_tab; /* => table for Cr to G conversion */ + INT32 * Cb_g_tab; /* => table for Cb to G conversion */ +} my_color_deconverter; + +typedef my_color_deconverter * my_cconvert_ptr; + + +/**************** YCbCr -> RGB conversion: most common case **************/ + +/* + * YCbCr is defined per CCIR 601-1, except that Cb and Cr are + * normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5. + * The conversion equations to be implemented are therefore + * R = Y + 1.40200 * Cr + * G = Y - 0.34414 * Cb - 0.71414 * Cr + * B = Y + 1.77200 * Cb + * where Cb and Cr represent the incoming values less CENTERJSAMPLE. + * (These numbers are derived from TIFF 6.0 section 21, dated 3-June-92.) + * + * To avoid floating-point arithmetic, we represent the fractional constants + * as integers scaled up by 2^16 (about 4 digits precision); we have to divide + * the products by 2^16, with appropriate rounding, to get the correct answer. + * Notice that Y, being an integral input, does not contribute any fraction + * so it need not participate in the rounding. + * + * For even more speed, we avoid doing any multiplications in the inner loop + * by precalculating the constants times Cb and Cr for all possible values. + * For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table); + * for 12-bit samples it is still acceptable. It's not very reasonable for + * 16-bit samples, but if you want lossless storage you shouldn't be changing + * colorspace anyway. + * The Cr=>R and Cb=>B values can be rounded to integers in advance; the + * values for the G calculation are left scaled up, since we must add them + * together before rounding. + */ + +#define SCALEBITS 16 /* speediest right-shift on some machines */ +#define ONE_HALF ((INT32) 1 << (SCALEBITS-1)) +#define FIX(x) ((INT32) ((x) * (1L<RGB colorspace conversion. + */ + +LOCAL(void) +build_ycc_rgb_table (j_decompress_ptr cinfo) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + int i; + INT32 x; + SHIFT_TEMPS + + cconvert->Cr_r_tab = (int *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (MAXJSAMPLE+1) * SIZEOF(int)); + cconvert->Cb_b_tab = (int *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (MAXJSAMPLE+1) * SIZEOF(int)); + cconvert->Cr_g_tab = (INT32 *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (MAXJSAMPLE+1) * SIZEOF(INT32)); + cconvert->Cb_g_tab = (INT32 *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (MAXJSAMPLE+1) * SIZEOF(INT32)); + + for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) { + /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */ + /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */ + /* Cr=>R value is nearest int to 1.40200 * x */ + cconvert->Cr_r_tab[i] = (int) + RIGHT_SHIFT(FIX(1.40200) * x + ONE_HALF, SCALEBITS); + /* Cb=>B value is nearest int to 1.77200 * x */ + cconvert->Cb_b_tab[i] = (int) + RIGHT_SHIFT(FIX(1.77200) * x + ONE_HALF, SCALEBITS); + /* Cr=>G value is scaled-up -0.71414 * x */ + cconvert->Cr_g_tab[i] = (- FIX(0.71414)) * x; + /* Cb=>G value is scaled-up -0.34414 * x */ + /* We also add in ONE_HALF so that need not do it in inner loop */ + cconvert->Cb_g_tab[i] = (- FIX(0.34414)) * x + ONE_HALF; + } +} + + +/* + * Convert some rows of samples to the output colorspace. + * + * Note that we change from noninterleaved, one-plane-per-component format + * to interleaved-pixel format. The output buffer is therefore three times + * as wide as the input buffer. + * A starting row offset is provided only for the input buffer. The caller + * can easily adjust the passed output_buf value to accommodate any row + * offset required on that side. + */ + +METHODDEF(void) +ycc_rgb_convert (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + register int y, cb, cr; + register JSAMPROW outptr; + register JSAMPROW inptr0, inptr1, inptr2; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->output_width; + /* copy these pointers into registers if possible */ + register JSAMPLE * range_limit = cinfo->sample_range_limit; + register int * Crrtab = cconvert->Cr_r_tab; + register int * Cbbtab = cconvert->Cb_b_tab; + register INT32 * Crgtab = cconvert->Cr_g_tab; + register INT32 * Cbgtab = cconvert->Cb_g_tab; + SHIFT_TEMPS + + while (--num_rows >= 0) { + inptr0 = input_buf[0][input_row]; + inptr1 = input_buf[1][input_row]; + inptr2 = input_buf[2][input_row]; + input_row++; + outptr = *output_buf++; + for (col = 0; col < num_cols; col++) { + y = GETJSAMPLE(inptr0[col]); + cb = GETJSAMPLE(inptr1[col]); + cr = GETJSAMPLE(inptr2[col]); + /* Range-limiting is essential due to noise introduced by DCT losses. */ + outptr[RGB_RED] = range_limit[y + Crrtab[cr]]; + outptr[RGB_GREEN] = range_limit[y + + ((int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], + SCALEBITS))]; + outptr[RGB_BLUE] = range_limit[y + Cbbtab[cb]]; + outptr += RGB_PIXELSIZE; + } + } +} + + +/**************** Cases other than YCbCr -> RGB **************/ + + +/* + * Color conversion for no colorspace change: just copy the data, + * converting from separate-planes to interleaved representation. + */ + +METHODDEF(void) +null_convert (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows) +{ + register JSAMPROW inptr, outptr; + register JDIMENSION count; + register int num_components = cinfo->num_components; + JDIMENSION num_cols = cinfo->output_width; + int ci; + + while (--num_rows >= 0) { + for (ci = 0; ci < num_components; ci++) { + inptr = input_buf[ci][input_row]; + outptr = output_buf[0] + ci; + for (count = num_cols; count > 0; count--) { + *outptr = *inptr++; /* needn't bother with GETJSAMPLE() here */ + outptr += num_components; + } + } + input_row++; + output_buf++; + } +} + + +/* + * Color conversion for grayscale: just copy the data. + * This also works for YCbCr -> grayscale conversion, in which + * we just copy the Y (luminance) component and ignore chrominance. + */ + +METHODDEF(void) +grayscale_convert (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows) +{ + jcopy_sample_rows(input_buf[0], (int) input_row, output_buf, 0, + num_rows, cinfo->output_width); +} + + +/* + * Convert grayscale to RGB: just duplicate the graylevel three times. + * This is provided to support applications that don't want to cope + * with grayscale as a separate case. + */ + +METHODDEF(void) +gray_rgb_convert (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows) +{ + register JSAMPROW inptr, outptr; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->output_width; + + while (--num_rows >= 0) { + inptr = input_buf[0][input_row++]; + outptr = *output_buf++; + for (col = 0; col < num_cols; col++) { + /* We can dispense with GETJSAMPLE() here */ + outptr[RGB_RED] = outptr[RGB_GREEN] = outptr[RGB_BLUE] = inptr[col]; + outptr += RGB_PIXELSIZE; + } + } +} + + +/* + * Adobe-style YCCK->CMYK conversion. + * We convert YCbCr to R=1-C, G=1-M, and B=1-Y using the same + * conversion as above, while passing K (black) unchanged. + * We assume build_ycc_rgb_table has been called. + */ + +METHODDEF(void) +ycck_cmyk_convert (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + register int y, cb, cr; + register JSAMPROW outptr; + register JSAMPROW inptr0, inptr1, inptr2, inptr3; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->output_width; + /* copy these pointers into registers if possible */ + register JSAMPLE * range_limit = cinfo->sample_range_limit; + register int * Crrtab = cconvert->Cr_r_tab; + register int * Cbbtab = cconvert->Cb_b_tab; + register INT32 * Crgtab = cconvert->Cr_g_tab; + register INT32 * Cbgtab = cconvert->Cb_g_tab; + SHIFT_TEMPS + + while (--num_rows >= 0) { + inptr0 = input_buf[0][input_row]; + inptr1 = input_buf[1][input_row]; + inptr2 = input_buf[2][input_row]; + inptr3 = input_buf[3][input_row]; + input_row++; + outptr = *output_buf++; + for (col = 0; col < num_cols; col++) { + y = GETJSAMPLE(inptr0[col]); + cb = GETJSAMPLE(inptr1[col]); + cr = GETJSAMPLE(inptr2[col]); + /* Range-limiting is essential due to noise introduced by DCT losses. */ + outptr[0] = range_limit[MAXJSAMPLE - (y + Crrtab[cr])]; /* red */ + outptr[1] = range_limit[MAXJSAMPLE - (y + /* green */ + ((int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], + SCALEBITS)))]; + outptr[2] = range_limit[MAXJSAMPLE - (y + Cbbtab[cb])]; /* blue */ + /* K passes through unchanged */ + outptr[3] = inptr3[col]; /* don't need GETJSAMPLE here */ + outptr += 4; + } + } +} + + +/* + * Empty method for start_pass. + */ + +METHODDEF(void) +start_pass_dcolor (j_decompress_ptr cinfo) +{ + /* no work needed */ +} + + +/* + * Module initialization routine for output colorspace conversion. + */ + +GLOBAL(void) +jinit_color_deconverter (j_decompress_ptr cinfo) +{ + my_cconvert_ptr cconvert; + int ci; + + cconvert = (my_cconvert_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_color_deconverter)); + cinfo->cconvert = (struct jpeg_color_deconverter *) cconvert; + cconvert->pub.start_pass = start_pass_dcolor; + + /* Make sure num_components agrees with jpeg_color_space */ + switch (cinfo->jpeg_color_space) { + case JCS_GRAYSCALE: + if (cinfo->num_components != 1) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + break; + + case JCS_RGB: + case JCS_YCbCr: + if (cinfo->num_components != 3) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + break; + + case JCS_CMYK: + case JCS_YCCK: + if (cinfo->num_components != 4) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + break; + + default: /* JCS_UNKNOWN can be anything */ + if (cinfo->num_components < 1) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + break; + } + + /* Set out_color_components and conversion method based on requested space. + * Also clear the component_needed flags for any unused components, + * so that earlier pipeline stages can avoid useless computation. + */ + + switch (cinfo->out_color_space) { + case JCS_GRAYSCALE: + cinfo->out_color_components = 1; + if (cinfo->jpeg_color_space == JCS_GRAYSCALE || + cinfo->jpeg_color_space == JCS_YCbCr) { + cconvert->pub.color_convert = grayscale_convert; + /* For color->grayscale conversion, only the Y (0) component is needed */ + for (ci = 1; ci < cinfo->num_components; ci++) + cinfo->comp_info[ci].component_needed = FALSE; + } else + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + + case JCS_RGB: + cinfo->out_color_components = RGB_PIXELSIZE; + if (cinfo->jpeg_color_space == JCS_YCbCr) { + cconvert->pub.color_convert = ycc_rgb_convert; + build_ycc_rgb_table(cinfo); + } else if (cinfo->jpeg_color_space == JCS_GRAYSCALE) { + cconvert->pub.color_convert = gray_rgb_convert; + } else if (cinfo->jpeg_color_space == JCS_RGB && RGB_PIXELSIZE == 3) { + cconvert->pub.color_convert = null_convert; + } else + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + + case JCS_CMYK: + cinfo->out_color_components = 4; + if (cinfo->jpeg_color_space == JCS_YCCK) { + cconvert->pub.color_convert = ycck_cmyk_convert; + build_ycc_rgb_table(cinfo); + } else if (cinfo->jpeg_color_space == JCS_CMYK) { + cconvert->pub.color_convert = null_convert; + } else + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + + default: + /* Permit null conversion to same output space */ + if (cinfo->out_color_space == cinfo->jpeg_color_space) { + cinfo->out_color_components = cinfo->num_components; + cconvert->pub.color_convert = null_convert; + } else /* unsupported non-null conversion */ + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + } + + if (cinfo->quantize_colors) + cinfo->output_components = 1; /* single colormapped output component */ + else + cinfo->output_components = cinfo->out_color_components; +} diff --git a/mk4/modimage/jpeg-6b/jdct.h b/mk4/modimage/jpeg-6b/jdct.h new file mode 100644 index 0000000..04192a2 --- /dev/null +++ b/mk4/modimage/jpeg-6b/jdct.h @@ -0,0 +1,176 @@ +/* + * jdct.h + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This include file contains common declarations for the forward and + * inverse DCT modules. These declarations are private to the DCT managers + * (jcdctmgr.c, jddctmgr.c) and the individual DCT algorithms. + * The individual DCT algorithms are kept in separate files to ease + * machine-dependent tuning (e.g., assembly coding). + */ + + +/* + * A forward DCT routine is given a pointer to a work area of type DCTELEM[]; + * the DCT is to be performed in-place in that buffer. Type DCTELEM is int + * for 8-bit samples, INT32 for 12-bit samples. (NOTE: Floating-point DCT + * implementations use an array of type FAST_FLOAT, instead.) + * The DCT inputs are expected to be signed (range +-CENTERJSAMPLE). + * The DCT outputs are returned scaled up by a factor of 8; they therefore + * have a range of +-8K for 8-bit data, +-128K for 12-bit data. This + * convention improves accuracy in integer implementations and saves some + * work in floating-point ones. + * Quantization of the output coefficients is done by jcdctmgr.c. + */ + +#if BITS_IN_JSAMPLE == 8 +typedef int DCTELEM; /* 16 or 32 bits is fine */ +#else +typedef INT32 DCTELEM; /* must have 32 bits */ +#endif + +typedef JMETHOD(void, forward_DCT_method_ptr, (DCTELEM * data)); +typedef JMETHOD(void, float_DCT_method_ptr, (FAST_FLOAT * data)); + + +/* + * An inverse DCT routine is given a pointer to the input JBLOCK and a pointer + * to an output sample array. The routine must dequantize the input data as + * well as perform the IDCT; for dequantization, it uses the multiplier table + * pointed to by compptr->dct_table. The output data is to be placed into the + * sample array starting at a specified column. (Any row offset needed will + * be applied to the array pointer before it is passed to the IDCT code.) + * Note that the number of samples emitted by the IDCT routine is + * DCT_scaled_size * DCT_scaled_size. + */ + +/* typedef inverse_DCT_method_ptr is declared in jpegint.h */ + +/* + * Each IDCT routine has its own ideas about the best dct_table element type. + */ + +typedef MULTIPLIER ISLOW_MULT_TYPE; /* short or int, whichever is faster */ +#if BITS_IN_JSAMPLE == 8 +typedef MULTIPLIER IFAST_MULT_TYPE; /* 16 bits is OK, use short if faster */ +#define IFAST_SCALE_BITS 2 /* fractional bits in scale factors */ +#else +typedef INT32 IFAST_MULT_TYPE; /* need 32 bits for scaled quantizers */ +#define IFAST_SCALE_BITS 13 /* fractional bits in scale factors */ +#endif +typedef FAST_FLOAT FLOAT_MULT_TYPE; /* preferred floating type */ + + +/* + * Each IDCT routine is responsible for range-limiting its results and + * converting them to unsigned form (0..MAXJSAMPLE). The raw outputs could + * be quite far out of range if the input data is corrupt, so a bulletproof + * range-limiting step is required. We use a mask-and-table-lookup method + * to do the combined operations quickly. See the comments with + * prepare_range_limit_table (in jdmaster.c) for more info. + */ + +#define IDCT_range_limit(cinfo) ((cinfo)->sample_range_limit + CENTERJSAMPLE) + +#define RANGE_MASK (MAXJSAMPLE * 4 + 3) /* 2 bits wider than legal samples */ + + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_fdct_islow jFDislow +#define jpeg_fdct_ifast jFDifast +#define jpeg_fdct_float jFDfloat +#define jpeg_idct_islow jRDislow +#define jpeg_idct_ifast jRDifast +#define jpeg_idct_float jRDfloat +#define jpeg_idct_4x4 jRD4x4 +#define jpeg_idct_2x2 jRD2x2 +#define jpeg_idct_1x1 jRD1x1 +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + +/* Extern declarations for the forward and inverse DCT routines. */ + +EXTERN(void) jpeg_fdct_islow JPP((DCTELEM * data)); +EXTERN(void) jpeg_fdct_ifast JPP((DCTELEM * data)); +EXTERN(void) jpeg_fdct_float JPP((FAST_FLOAT * data)); + +EXTERN(void) jpeg_idct_islow + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_ifast + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_float + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_4x4 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_2x2 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_1x1 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); + + +/* + * Macros for handling fixed-point arithmetic; these are used by many + * but not all of the DCT/IDCT modules. + * + * All values are expected to be of type INT32. + * Fractional constants are scaled left by CONST_BITS bits. + * CONST_BITS is defined within each module using these macros, + * and may differ from one module to the next. + */ + +#define ONE ((INT32) 1) +#define CONST_SCALE (ONE << CONST_BITS) + +/* Convert a positive real constant to an integer scaled by CONST_SCALE. + * Caution: some C compilers fail to reduce "FIX(constant)" at compile time, + * thus causing a lot of useless floating-point operations at run time. + */ + +#define FIX(x) ((INT32) ((x) * CONST_SCALE + 0.5)) + +/* Descale and correctly round an INT32 value that's scaled by N bits. + * We assume RIGHT_SHIFT rounds towards minus infinity, so adding + * the fudge factor is correct for either sign of X. + */ + +#define DESCALE(x,n) RIGHT_SHIFT((x) + (ONE << ((n)-1)), n) + +/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result. + * This macro is used only when the two inputs will actually be no more than + * 16 bits wide, so that a 16x16->32 bit multiply can be used instead of a + * full 32x32 multiply. This provides a useful speedup on many machines. + * Unfortunately there is no way to specify a 16x16->32 multiply portably + * in C, but some C compilers will do the right thing if you provide the + * correct combination of casts. + */ + +#ifdef SHORTxSHORT_32 /* may work if 'int' is 32 bits */ +#define MULTIPLY16C16(var,const) (((INT16) (var)) * ((INT16) (const))) +#endif +#ifdef SHORTxLCONST_32 /* known to work with Microsoft C 6.0 */ +#define MULTIPLY16C16(var,const) (((INT16) (var)) * ((INT32) (const))) +#endif + +#ifndef MULTIPLY16C16 /* default definition */ +#define MULTIPLY16C16(var,const) ((var) * (const)) +#endif + +/* Same except both inputs are variables. */ + +#ifdef SHORTxSHORT_32 /* may work if 'int' is 32 bits */ +#define MULTIPLY16V16(var1,var2) (((INT16) (var1)) * ((INT16) (var2))) +#endif + +#ifndef MULTIPLY16V16 /* default definition */ +#define MULTIPLY16V16(var1,var2) ((var1) * (var2)) +#endif diff --git a/mk4/modimage/jpeg-6b/jddctmgr.c b/mk4/modimage/jpeg-6b/jddctmgr.c new file mode 100644 index 0000000..bbf8d0e --- /dev/null +++ b/mk4/modimage/jpeg-6b/jddctmgr.c @@ -0,0 +1,269 @@ +/* + * jddctmgr.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the inverse-DCT management logic. + * This code selects a particular IDCT implementation to be used, + * and it performs related housekeeping chores. No code in this file + * is executed per IDCT step, only during output pass setup. + * + * Note that the IDCT routines are responsible for performing coefficient + * dequantization as well as the IDCT proper. This module sets up the + * dequantization multiplier table needed by the IDCT routine. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + + +/* + * The decompressor input side (jdinput.c) saves away the appropriate + * quantization table for each component at the start of the first scan + * involving that component. (This is necessary in order to correctly + * decode files that reuse Q-table slots.) + * When we are ready to make an output pass, the saved Q-table is converted + * to a multiplier table that will actually be used by the IDCT routine. + * The multiplier table contents are IDCT-method-dependent. To support + * application changes in IDCT method between scans, we can remake the + * multiplier tables if necessary. + * In buffered-image mode, the first output pass may occur before any data + * has been seen for some components, and thus before their Q-tables have + * been saved away. To handle this case, multiplier tables are preset + * to zeroes; the result of the IDCT will be a neutral gray level. + */ + + +/* Private subobject for this module */ + +typedef struct { + struct jpeg_inverse_dct pub; /* public fields */ + + /* This array contains the IDCT method code that each multiplier table + * is currently set up for, or -1 if it's not yet set up. + * The actual multiplier tables are pointed to by dct_table in the + * per-component comp_info structures. + */ + int cur_method[MAX_COMPONENTS]; +} my_idct_controller; + +typedef my_idct_controller * my_idct_ptr; + + +/* Allocated multiplier tables: big enough for any supported variant */ + +typedef union { + ISLOW_MULT_TYPE islow_array[DCTSIZE2]; +#ifdef DCT_IFAST_SUPPORTED + IFAST_MULT_TYPE ifast_array[DCTSIZE2]; +#endif +#ifdef DCT_FLOAT_SUPPORTED + FLOAT_MULT_TYPE float_array[DCTSIZE2]; +#endif +} multiplier_table; + + +/* The current scaled-IDCT routines require ISLOW-style multiplier tables, + * so be sure to compile that code if either ISLOW or SCALING is requested. + */ +#ifdef DCT_ISLOW_SUPPORTED +#define PROVIDE_ISLOW_TABLES +#else +#ifdef IDCT_SCALING_SUPPORTED +#define PROVIDE_ISLOW_TABLES +#endif +#endif + + +/* + * Prepare for an output pass. + * Here we select the proper IDCT routine for each component and build + * a matching multiplier table. + */ + +METHODDEF(void) +start_pass (j_decompress_ptr cinfo) +{ + my_idct_ptr idct = (my_idct_ptr) cinfo->idct; + int ci, i; + jpeg_component_info *compptr; + int method = 0; + inverse_DCT_method_ptr method_ptr = NULL; + JQUANT_TBL * qtbl; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Select the proper IDCT routine for this component's scaling */ + switch (compptr->DCT_scaled_size) { +#ifdef IDCT_SCALING_SUPPORTED + case 1: + method_ptr = jpeg_idct_1x1; + method = JDCT_ISLOW; /* jidctred uses islow-style table */ + break; + case 2: + method_ptr = jpeg_idct_2x2; + method = JDCT_ISLOW; /* jidctred uses islow-style table */ + break; + case 4: + method_ptr = jpeg_idct_4x4; + method = JDCT_ISLOW; /* jidctred uses islow-style table */ + break; +#endif + case DCTSIZE: + switch (cinfo->dct_method) { +#ifdef DCT_ISLOW_SUPPORTED + case JDCT_ISLOW: + method_ptr = jpeg_idct_islow; + method = JDCT_ISLOW; + break; +#endif +#ifdef DCT_IFAST_SUPPORTED + case JDCT_IFAST: + method_ptr = jpeg_idct_ifast; + method = JDCT_IFAST; + break; +#endif +#ifdef DCT_FLOAT_SUPPORTED + case JDCT_FLOAT: + method_ptr = jpeg_idct_float; + method = JDCT_FLOAT; + break; +#endif + default: + ERREXIT(cinfo, JERR_NOT_COMPILED); + break; + } + break; + default: + ERREXIT1(cinfo, JERR_BAD_DCTSIZE, compptr->DCT_scaled_size); + break; + } + idct->pub.inverse_DCT[ci] = method_ptr; + /* Create multiplier table from quant table. + * However, we can skip this if the component is uninteresting + * or if we already built the table. Also, if no quant table + * has yet been saved for the component, we leave the + * multiplier table all-zero; we'll be reading zeroes from the + * coefficient controller's buffer anyway. + */ + if (! compptr->component_needed || idct->cur_method[ci] == method) + continue; + qtbl = compptr->quant_table; + if (qtbl == NULL) /* happens if no data yet for component */ + continue; + idct->cur_method[ci] = method; + switch (method) { +#ifdef PROVIDE_ISLOW_TABLES + case JDCT_ISLOW: + { + /* For LL&M IDCT method, multipliers are equal to raw quantization + * coefficients, but are stored as ints to ensure access efficiency. + */ + ISLOW_MULT_TYPE * ismtbl = (ISLOW_MULT_TYPE *) compptr->dct_table; + for (i = 0; i < DCTSIZE2; i++) { + ismtbl[i] = (ISLOW_MULT_TYPE) qtbl->quantval[i]; + } + } + break; +#endif +#ifdef DCT_IFAST_SUPPORTED + case JDCT_IFAST: + { + /* For AA&N IDCT method, multipliers are equal to quantization + * coefficients scaled by scalefactor[row]*scalefactor[col], where + * scalefactor[0] = 1 + * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7 + * For integer operation, the multiplier table is to be scaled by + * IFAST_SCALE_BITS. + */ + IFAST_MULT_TYPE * ifmtbl = (IFAST_MULT_TYPE *) compptr->dct_table; +#define CONST_BITS 14 + static const INT16 aanscales[DCTSIZE2] = { + /* precomputed values scaled up by 14 bits */ + 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, + 22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270, + 21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906, + 19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315, + 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, + 12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552, + 8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446, + 4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247 + }; + SHIFT_TEMPS + + for (i = 0; i < DCTSIZE2; i++) { + ifmtbl[i] = (IFAST_MULT_TYPE) + DESCALE(MULTIPLY16V16((INT32) qtbl->quantval[i], + (INT32) aanscales[i]), + CONST_BITS-IFAST_SCALE_BITS); + } + } + break; +#endif +#ifdef DCT_FLOAT_SUPPORTED + case JDCT_FLOAT: + { + /* For float AA&N IDCT method, multipliers are equal to quantization + * coefficients scaled by scalefactor[row]*scalefactor[col], where + * scalefactor[0] = 1 + * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7 + */ + FLOAT_MULT_TYPE * fmtbl = (FLOAT_MULT_TYPE *) compptr->dct_table; + int row, col; + static const double aanscalefactor[DCTSIZE] = { + 1.0, 1.387039845, 1.306562965, 1.175875602, + 1.0, 0.785694958, 0.541196100, 0.275899379 + }; + + i = 0; + for (row = 0; row < DCTSIZE; row++) { + for (col = 0; col < DCTSIZE; col++) { + fmtbl[i] = (FLOAT_MULT_TYPE) + ((double) qtbl->quantval[i] * + aanscalefactor[row] * aanscalefactor[col]); + i++; + } + } + } + break; +#endif + default: + ERREXIT(cinfo, JERR_NOT_COMPILED); + break; + } + } +} + + +/* + * Initialize IDCT manager. + */ + +GLOBAL(void) +jinit_inverse_dct (j_decompress_ptr cinfo) +{ + my_idct_ptr idct; + int ci; + jpeg_component_info *compptr; + + idct = (my_idct_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_idct_controller)); + cinfo->idct = (struct jpeg_inverse_dct *) idct; + idct->pub.start_pass = start_pass; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Allocate and pre-zero a multiplier table for each component */ + compptr->dct_table = + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(multiplier_table)); + MEMZERO(compptr->dct_table, SIZEOF(multiplier_table)); + /* Mark multiplier table not yet set up for any method */ + idct->cur_method[ci] = -1; + } +} diff --git a/mk4/modimage/jpeg-6b/jdhuff.c b/mk4/modimage/jpeg-6b/jdhuff.c new file mode 100644 index 0000000..b5ba39f --- /dev/null +++ b/mk4/modimage/jpeg-6b/jdhuff.c @@ -0,0 +1,651 @@ +/* + * jdhuff.c + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains Huffman entropy decoding routines. + * + * Much of the complexity here has to do with supporting input suspension. + * If the data source module demands suspension, we want to be able to back + * up to the start of the current MCU. To do this, we copy state variables + * into local working storage, and update them back to the permanent + * storage only upon successful completion of an MCU. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdhuff.h" /* Declarations shared with jdphuff.c */ + + +/* + * Expanded entropy decoder object for Huffman decoding. + * + * The savable_state subrecord contains fields that change within an MCU, + * but must not be updated permanently until we complete the MCU. + */ + +typedef struct { + int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */ +} savable_state; + +/* This macro is to work around compilers with missing or broken + * structure assignment. You'll need to fix this code if you have + * such a compiler and you change MAX_COMPS_IN_SCAN. + */ + +#ifndef NO_STRUCT_ASSIGN +#define ASSIGN_STATE(dest,src) ((dest) = (src)) +#else +#if MAX_COMPS_IN_SCAN == 4 +#define ASSIGN_STATE(dest,src) \ + ((dest).last_dc_val[0] = (src).last_dc_val[0], \ + (dest).last_dc_val[1] = (src).last_dc_val[1], \ + (dest).last_dc_val[2] = (src).last_dc_val[2], \ + (dest).last_dc_val[3] = (src).last_dc_val[3]) +#endif +#endif + + +typedef struct { + struct jpeg_entropy_decoder pub; /* public fields */ + + /* These fields are loaded into local variables at start of each MCU. + * In case of suspension, we exit WITHOUT updating them. + */ + bitread_perm_state bitstate; /* Bit buffer at start of MCU */ + savable_state saved; /* Other state at start of MCU */ + + /* These fields are NOT loaded into local working state. */ + unsigned int restarts_to_go; /* MCUs left in this restart interval */ + + /* Pointers to derived tables (these workspaces have image lifespan) */ + d_derived_tbl * dc_derived_tbls[NUM_HUFF_TBLS]; + d_derived_tbl * ac_derived_tbls[NUM_HUFF_TBLS]; + + /* Precalculated info set up by start_pass for use in decode_mcu: */ + + /* Pointers to derived tables to be used for each block within an MCU */ + d_derived_tbl * dc_cur_tbls[D_MAX_BLOCKS_IN_MCU]; + d_derived_tbl * ac_cur_tbls[D_MAX_BLOCKS_IN_MCU]; + /* Whether we care about the DC and AC coefficient values for each block */ + boolean dc_needed[D_MAX_BLOCKS_IN_MCU]; + boolean ac_needed[D_MAX_BLOCKS_IN_MCU]; +} huff_entropy_decoder; + +typedef huff_entropy_decoder * huff_entropy_ptr; + + +/* + * Initialize for a Huffman-compressed scan. + */ + +METHODDEF(void) +start_pass_huff_decoder (j_decompress_ptr cinfo) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + int ci, blkn, dctbl, actbl; + jpeg_component_info * compptr; + + /* Check that the scan parameters Ss, Se, Ah/Al are OK for sequential JPEG. + * This ought to be an error condition, but we make it a warning because + * there are some baseline files out there with all zeroes in these bytes. + */ + if (cinfo->Ss != 0 || cinfo->Se != DCTSIZE2-1 || + cinfo->Ah != 0 || cinfo->Al != 0) + WARNMS(cinfo, JWRN_NOT_SEQUENTIAL); + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + dctbl = compptr->dc_tbl_no; + actbl = compptr->ac_tbl_no; + /* Compute derived values for Huffman tables */ + /* We may do this more than once for a table, but it's not expensive */ + jpeg_make_d_derived_tbl(cinfo, TRUE, dctbl, + & entropy->dc_derived_tbls[dctbl]); + jpeg_make_d_derived_tbl(cinfo, FALSE, actbl, + & entropy->ac_derived_tbls[actbl]); + /* Initialize DC predictions to 0 */ + entropy->saved.last_dc_val[ci] = 0; + } + + /* Precalculate decoding info for each block in an MCU of this scan */ + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + ci = cinfo->MCU_membership[blkn]; + compptr = cinfo->cur_comp_info[ci]; + /* Precalculate which table to use for each block */ + entropy->dc_cur_tbls[blkn] = entropy->dc_derived_tbls[compptr->dc_tbl_no]; + entropy->ac_cur_tbls[blkn] = entropy->ac_derived_tbls[compptr->ac_tbl_no]; + /* Decide whether we really care about the coefficient values */ + if (compptr->component_needed) { + entropy->dc_needed[blkn] = TRUE; + /* we don't need the ACs if producing a 1/8th-size image */ + entropy->ac_needed[blkn] = (compptr->DCT_scaled_size > 1); + } else { + entropy->dc_needed[blkn] = entropy->ac_needed[blkn] = FALSE; + } + } + + /* Initialize bitread state variables */ + entropy->bitstate.bits_left = 0; + entropy->bitstate.get_buffer = 0; /* unnecessary, but keeps Purify quiet */ + entropy->pub.insufficient_data = FALSE; + + /* Initialize restart counter */ + entropy->restarts_to_go = cinfo->restart_interval; +} + + +/* + * Compute the derived values for a Huffman table. + * This routine also performs some validation checks on the table. + * + * Note this is also used by jdphuff.c. + */ + +GLOBAL(void) +jpeg_make_d_derived_tbl (j_decompress_ptr cinfo, boolean isDC, int tblno, + d_derived_tbl ** pdtbl) +{ + JHUFF_TBL *htbl; + d_derived_tbl *dtbl; + int p, i, l, si, numsymbols; + int lookbits, ctr; + char huffsize[257]; + unsigned int huffcode[257]; + unsigned int code; + + /* Note that huffsize[] and huffcode[] are filled in code-length order, + * paralleling the order of the symbols themselves in htbl->huffval[]. + */ + + /* Find the input Huffman table */ + if (tblno < 0 || tblno >= NUM_HUFF_TBLS) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tblno); + htbl = + isDC ? cinfo->dc_huff_tbl_ptrs[tblno] : cinfo->ac_huff_tbl_ptrs[tblno]; + if (htbl == NULL) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tblno); + + /* Allocate a workspace if we haven't already done so. */ + if (*pdtbl == NULL) + *pdtbl = (d_derived_tbl *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(d_derived_tbl)); + dtbl = *pdtbl; + dtbl->pub = htbl; /* fill in back link */ + + /* Figure C.1: make table of Huffman code length for each symbol */ + + p = 0; + for (l = 1; l <= 16; l++) { + i = (int) htbl->bits[l]; + if (i < 0 || p + i > 256) /* protect against table overrun */ + ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); + while (i--) + huffsize[p++] = (char) l; + } + huffsize[p] = 0; + numsymbols = p; + + /* Figure C.2: generate the codes themselves */ + /* We also validate that the counts represent a legal Huffman code tree. */ + + code = 0; + si = huffsize[0]; + p = 0; + while (huffsize[p]) { + while (((int) huffsize[p]) == si) { + huffcode[p++] = code; + code++; + } + /* code is now 1 more than the last code used for codelength si; but + * it must still fit in si bits, since no code is allowed to be all ones. + */ + if (((INT32) code) >= (((INT32) 1) << si)) + ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); + code <<= 1; + si++; + } + + /* Figure F.15: generate decoding tables for bit-sequential decoding */ + + p = 0; + for (l = 1; l <= 16; l++) { + if (htbl->bits[l]) { + /* valoffset[l] = huffval[] index of 1st symbol of code length l, + * minus the minimum code of length l + */ + dtbl->valoffset[l] = (INT32) p - (INT32) huffcode[p]; + p += htbl->bits[l]; + dtbl->maxcode[l] = huffcode[p-1]; /* maximum code of length l */ + } else { + dtbl->maxcode[l] = -1; /* -1 if no codes of this length */ + } + } + dtbl->maxcode[17] = 0xFFFFFL; /* ensures jpeg_huff_decode terminates */ + + /* Compute lookahead tables to speed up decoding. + * First we set all the table entries to 0, indicating "too long"; + * then we iterate through the Huffman codes that are short enough and + * fill in all the entries that correspond to bit sequences starting + * with that code. + */ + + MEMZERO(dtbl->look_nbits, SIZEOF(dtbl->look_nbits)); + + p = 0; + for (l = 1; l <= HUFF_LOOKAHEAD; l++) { + for (i = 1; i <= (int) htbl->bits[l]; i++, p++) { + /* l = current code's length, p = its index in huffcode[] & huffval[]. */ + /* Generate left-justified code followed by all possible bit sequences */ + lookbits = huffcode[p] << (HUFF_LOOKAHEAD-l); + for (ctr = 1 << (HUFF_LOOKAHEAD-l); ctr > 0; ctr--) { + dtbl->look_nbits[lookbits] = l; + dtbl->look_sym[lookbits] = htbl->huffval[p]; + lookbits++; + } + } + } + + /* Validate symbols as being reasonable. + * For AC tables, we make no check, but accept all byte values 0..255. + * For DC tables, we require the symbols to be in range 0..15. + * (Tighter bounds could be applied depending on the data depth and mode, + * but this is sufficient to ensure safe decoding.) + */ + if (isDC) { + for (i = 0; i < numsymbols; i++) { + int sym = htbl->huffval[i]; + if (sym < 0 || sym > 15) + ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); + } + } +} + + +/* + * Out-of-line code for bit fetching (shared with jdphuff.c). + * See jdhuff.h for info about usage. + * Note: current values of get_buffer and bits_left are passed as parameters, + * but are returned in the corresponding fields of the state struct. + * + * On most machines MIN_GET_BITS should be 25 to allow the full 32-bit width + * of get_buffer to be used. (On machines with wider words, an even larger + * buffer could be used.) However, on some machines 32-bit shifts are + * quite slow and take time proportional to the number of places shifted. + * (This is true with most PC compilers, for instance.) In this case it may + * be a win to set MIN_GET_BITS to the minimum value of 15. This reduces the + * average shift distance at the cost of more calls to jpeg_fill_bit_buffer. + */ + +#ifdef SLOW_SHIFT_32 +#define MIN_GET_BITS 15 /* minimum allowable value */ +#else +#define MIN_GET_BITS (BIT_BUF_SIZE-7) +#endif + + +GLOBAL(boolean) +jpeg_fill_bit_buffer (bitread_working_state * state, + register bit_buf_type get_buffer, register int bits_left, + int nbits) +/* Load up the bit buffer to a depth of at least nbits */ +{ + /* Copy heavily used state fields into locals (hopefully registers) */ + register const JOCTET * next_input_byte = state->next_input_byte; + register size_t bytes_in_buffer = state->bytes_in_buffer; + j_decompress_ptr cinfo = state->cinfo; + + /* Attempt to load at least MIN_GET_BITS bits into get_buffer. */ + /* (It is assumed that no request will be for more than that many bits.) */ + /* We fail to do so only if we hit a marker or are forced to suspend. */ + + if (cinfo->unread_marker == 0) { /* cannot advance past a marker */ + while (bits_left < MIN_GET_BITS) { + register int c; + + /* Attempt to read a byte */ + if (bytes_in_buffer == 0) { + if (! (*cinfo->src->fill_input_buffer) (cinfo)) + return FALSE; + next_input_byte = cinfo->src->next_input_byte; + bytes_in_buffer = cinfo->src->bytes_in_buffer; + } + bytes_in_buffer--; + c = GETJOCTET(*next_input_byte++); + + /* If it's 0xFF, check and discard stuffed zero byte */ + if (c == 0xFF) { + /* Loop here to discard any padding FF's on terminating marker, + * so that we can save a valid unread_marker value. NOTE: we will + * accept multiple FF's followed by a 0 as meaning a single FF data + * byte. This data pattern is not valid according to the standard. + */ + do { + if (bytes_in_buffer == 0) { + if (! (*cinfo->src->fill_input_buffer) (cinfo)) + return FALSE; + next_input_byte = cinfo->src->next_input_byte; + bytes_in_buffer = cinfo->src->bytes_in_buffer; + } + bytes_in_buffer--; + c = GETJOCTET(*next_input_byte++); + } while (c == 0xFF); + + if (c == 0) { + /* Found FF/00, which represents an FF data byte */ + c = 0xFF; + } else { + /* Oops, it's actually a marker indicating end of compressed data. + * Save the marker code for later use. + * Fine point: it might appear that we should save the marker into + * bitread working state, not straight into permanent state. But + * once we have hit a marker, we cannot need to suspend within the + * current MCU, because we will read no more bytes from the data + * source. So it is OK to update permanent state right away. + */ + cinfo->unread_marker = c; + /* See if we need to insert some fake zero bits. */ + goto no_more_bytes; + } + } + + /* OK, load c into get_buffer */ + get_buffer = (get_buffer << 8) | c; + bits_left += 8; + } /* end while */ + } else { + no_more_bytes: + /* We get here if we've read the marker that terminates the compressed + * data segment. There should be enough bits in the buffer register + * to satisfy the request; if so, no problem. + */ + if (nbits > bits_left) { + /* Uh-oh. Report corrupted data to user and stuff zeroes into + * the data stream, so that we can produce some kind of image. + * We use a nonvolatile flag to ensure that only one warning message + * appears per data segment. + */ + if (! cinfo->entropy->insufficient_data) { + WARNMS(cinfo, JWRN_HIT_MARKER); + cinfo->entropy->insufficient_data = TRUE; + } + /* Fill the buffer with zero bits */ + get_buffer <<= MIN_GET_BITS - bits_left; + bits_left = MIN_GET_BITS; + } + } + + /* Unload the local registers */ + state->next_input_byte = next_input_byte; + state->bytes_in_buffer = bytes_in_buffer; + state->get_buffer = get_buffer; + state->bits_left = bits_left; + + return TRUE; +} + + +/* + * Out-of-line code for Huffman code decoding. + * See jdhuff.h for info about usage. + */ + +GLOBAL(int) +jpeg_huff_decode (bitread_working_state * state, + register bit_buf_type get_buffer, register int bits_left, + d_derived_tbl * htbl, int min_bits) +{ + register int l = min_bits; + register INT32 code; + + /* HUFF_DECODE has determined that the code is at least min_bits */ + /* bits long, so fetch that many bits in one swoop. */ + + CHECK_BIT_BUFFER(*state, l, return -1); + code = GET_BITS(l); + + /* Collect the rest of the Huffman code one bit at a time. */ + /* This is per Figure F.16 in the JPEG spec. */ + + while (code > htbl->maxcode[l]) { + code <<= 1; + CHECK_BIT_BUFFER(*state, 1, return -1); + code |= GET_BITS(1); + l++; + } + + /* Unload the local registers */ + state->get_buffer = get_buffer; + state->bits_left = bits_left; + + /* With garbage input we may reach the sentinel value l = 17. */ + + if (l > 16) { + WARNMS(state->cinfo, JWRN_HUFF_BAD_CODE); + return 0; /* fake a zero as the safest result */ + } + + return htbl->pub->huffval[ (int) (code + htbl->valoffset[l]) ]; +} + + +/* + * Figure F.12: extend sign bit. + * On some machines, a shift and add will be faster than a table lookup. + */ + +#ifdef AVOID_TABLES + +#define HUFF_EXTEND(x,s) ((x) < (1<<((s)-1)) ? (x) + (((-1)<<(s)) + 1) : (x)) + +#else + +#define HUFF_EXTEND(x,s) ((x) < extend_test[s] ? (x) + extend_offset[s] : (x)) + +static const int extend_test[16] = /* entry n is 2**(n-1) */ + { 0, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, + 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000 }; + +static const int extend_offset[16] = /* entry n is (-1 << n) + 1 */ + { 0, ((-1)<<1) + 1, ((-1)<<2) + 1, ((-1)<<3) + 1, ((-1)<<4) + 1, + ((-1)<<5) + 1, ((-1)<<6) + 1, ((-1)<<7) + 1, ((-1)<<8) + 1, + ((-1)<<9) + 1, ((-1)<<10) + 1, ((-1)<<11) + 1, ((-1)<<12) + 1, + ((-1)<<13) + 1, ((-1)<<14) + 1, ((-1)<<15) + 1 }; + +#endif /* AVOID_TABLES */ + + +/* + * Check for a restart marker & resynchronize decoder. + * Returns FALSE if must suspend. + */ + +LOCAL(boolean) +process_restart (j_decompress_ptr cinfo) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + int ci; + + /* Throw away any unused bits remaining in bit buffer; */ + /* include any full bytes in next_marker's count of discarded bytes */ + cinfo->marker->discarded_bytes += entropy->bitstate.bits_left / 8; + entropy->bitstate.bits_left = 0; + + /* Advance past the RSTn marker */ + if (! (*cinfo->marker->read_restart_marker) (cinfo)) + return FALSE; + + /* Re-initialize DC predictions to 0 */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) + entropy->saved.last_dc_val[ci] = 0; + + /* Reset restart counter */ + entropy->restarts_to_go = cinfo->restart_interval; + + /* Reset out-of-data flag, unless read_restart_marker left us smack up + * against a marker. In that case we will end up treating the next data + * segment as empty, and we can avoid producing bogus output pixels by + * leaving the flag set. + */ + if (cinfo->unread_marker == 0) + entropy->pub.insufficient_data = FALSE; + + return TRUE; +} + + +/* + * Decode and return one MCU's worth of Huffman-compressed coefficients. + * The coefficients are reordered from zigzag order into natural array order, + * but are not dequantized. + * + * The i'th block of the MCU is stored into the block pointed to by + * MCU_data[i]. WE ASSUME THIS AREA HAS BEEN ZEROED BY THE CALLER. + * (Wholesale zeroing is usually a little faster than retail...) + * + * Returns FALSE if data source requested suspension. In that case no + * changes have been made to permanent state. (Exception: some output + * coefficients may already have been assigned. This is harmless for + * this module, since we'll just re-assign them on the next call.) + */ + +METHODDEF(boolean) +decode_mcu (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + int blkn; + BITREAD_STATE_VARS; + savable_state state; + + /* Process restart marker if needed; may have to suspend */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + if (! process_restart(cinfo)) + return FALSE; + } + + /* If we've run out of data, just leave the MCU set to zeroes. + * This way, we return uniform gray for the remainder of the segment. + */ + if (! entropy->pub.insufficient_data) { + + /* Load up working state */ + BITREAD_LOAD_STATE(cinfo,entropy->bitstate); + ASSIGN_STATE(state, entropy->saved); + + /* Outer loop handles each block in the MCU */ + + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + JBLOCKROW block = MCU_data[blkn]; + d_derived_tbl * dctbl = entropy->dc_cur_tbls[blkn]; + d_derived_tbl * actbl = entropy->ac_cur_tbls[blkn]; + register int s, k, r; + + /* Decode a single block's worth of coefficients */ + + /* Section F.2.2.1: decode the DC coefficient difference */ + HUFF_DECODE(s, br_state, dctbl, return FALSE, label1); + if (s) { + CHECK_BIT_BUFFER(br_state, s, return FALSE); + r = GET_BITS(s); + s = HUFF_EXTEND(r, s); + } + + if (entropy->dc_needed[blkn]) { + /* Convert DC difference to actual value, update last_dc_val */ + int ci = cinfo->MCU_membership[blkn]; + s += state.last_dc_val[ci]; + state.last_dc_val[ci] = s; + /* Output the DC coefficient (assumes jpeg_natural_order[0] = 0) */ + (*block)[0] = (JCOEF) s; + } + + if (entropy->ac_needed[blkn]) { + + /* Section F.2.2.2: decode the AC coefficients */ + /* Since zeroes are skipped, output area must be cleared beforehand */ + for (k = 1; k < DCTSIZE2; k++) { + HUFF_DECODE(s, br_state, actbl, return FALSE, label2); + + r = s >> 4; + s &= 15; + + if (s) { + k += r; + CHECK_BIT_BUFFER(br_state, s, return FALSE); + r = GET_BITS(s); + s = HUFF_EXTEND(r, s); + /* Output coefficient in natural (dezigzagged) order. + * Note: the extra entries in jpeg_natural_order[] will save us + * if k >= DCTSIZE2, which could happen if the data is corrupted. + */ + (*block)[jpeg_natural_order[k]] = (JCOEF) s; + } else { + if (r != 15) + break; + k += 15; + } + } + + } else { + + /* Section F.2.2.2: decode the AC coefficients */ + /* In this path we just discard the values */ + for (k = 1; k < DCTSIZE2; k++) { + HUFF_DECODE(s, br_state, actbl, return FALSE, label3); + + r = s >> 4; + s &= 15; + + if (s) { + k += r; + CHECK_BIT_BUFFER(br_state, s, return FALSE); + DROP_BITS(s); + } else { + if (r != 15) + break; + k += 15; + } + } + + } + } + + /* Completed MCU, so update state */ + BITREAD_SAVE_STATE(cinfo,entropy->bitstate); + ASSIGN_STATE(entropy->saved, state); + } + + /* Account for restart interval (no-op if not using restarts) */ + entropy->restarts_to_go--; + + return TRUE; +} + + +/* + * Module initialization routine for Huffman entropy decoding. + */ + +GLOBAL(void) +jinit_huff_decoder (j_decompress_ptr cinfo) +{ + huff_entropy_ptr entropy; + int i; + + entropy = (huff_entropy_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(huff_entropy_decoder)); + cinfo->entropy = (struct jpeg_entropy_decoder *) entropy; + entropy->pub.start_pass = start_pass_huff_decoder; + entropy->pub.decode_mcu = decode_mcu; + + /* Mark tables unallocated */ + for (i = 0; i < NUM_HUFF_TBLS; i++) { + entropy->dc_derived_tbls[i] = entropy->ac_derived_tbls[i] = NULL; + } +} diff --git a/mk4/modimage/jpeg-6b/jdhuff.h b/mk4/modimage/jpeg-6b/jdhuff.h new file mode 100644 index 0000000..ae19b6c --- /dev/null +++ b/mk4/modimage/jpeg-6b/jdhuff.h @@ -0,0 +1,201 @@ +/* + * jdhuff.h + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains declarations for Huffman entropy decoding routines + * that are shared between the sequential decoder (jdhuff.c) and the + * progressive decoder (jdphuff.c). No other modules need to see these. + */ + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_make_d_derived_tbl jMkDDerived +#define jpeg_fill_bit_buffer jFilBitBuf +#define jpeg_huff_decode jHufDecode +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* Derived data constructed for each Huffman table */ + +#define HUFF_LOOKAHEAD 8 /* # of bits of lookahead */ + +typedef struct { + /* Basic tables: (element [0] of each array is unused) */ + INT32 maxcode[18]; /* largest code of length k (-1 if none) */ + /* (maxcode[17] is a sentinel to ensure jpeg_huff_decode terminates) */ + INT32 valoffset[17]; /* huffval[] offset for codes of length k */ + /* valoffset[k] = huffval[] index of 1st symbol of code length k, less + * the smallest code of length k; so given a code of length k, the + * corresponding symbol is huffval[code + valoffset[k]] + */ + + /* Link to public Huffman table (needed only in jpeg_huff_decode) */ + JHUFF_TBL *pub; + + /* Lookahead tables: indexed by the next HUFF_LOOKAHEAD bits of + * the input data stream. If the next Huffman code is no more + * than HUFF_LOOKAHEAD bits long, we can obtain its length and + * the corresponding symbol directly from these tables. + */ + int look_nbits[1< 32 bits on your machine, and shifting/masking longs is + * reasonably fast, making bit_buf_type be long and setting BIT_BUF_SIZE + * appropriately should be a win. Unfortunately we can't define the size + * with something like #define BIT_BUF_SIZE (sizeof(bit_buf_type)*8) + * because not all machines measure sizeof in 8-bit bytes. + */ + +typedef struct { /* Bitreading state saved across MCUs */ + bit_buf_type get_buffer; /* current bit-extraction buffer */ + int bits_left; /* # of unused bits in it */ +} bitread_perm_state; + +typedef struct { /* Bitreading working state within an MCU */ + /* Current data source location */ + /* We need a copy, rather than munging the original, in case of suspension */ + const JOCTET * next_input_byte; /* => next byte to read from source */ + size_t bytes_in_buffer; /* # of bytes remaining in source buffer */ + /* Bit input buffer --- note these values are kept in register variables, + * not in this struct, inside the inner loops. + */ + bit_buf_type get_buffer; /* current bit-extraction buffer */ + int bits_left; /* # of unused bits in it */ + /* Pointer needed by jpeg_fill_bit_buffer. */ + j_decompress_ptr cinfo; /* back link to decompress master record */ +} bitread_working_state; + +/* Macros to declare and load/save bitread local variables. */ +#define BITREAD_STATE_VARS \ + register bit_buf_type get_buffer; \ + register int bits_left; \ + bitread_working_state br_state + +#define BITREAD_LOAD_STATE(cinfop,permstate) \ + br_state.cinfo = cinfop; \ + br_state.next_input_byte = cinfop->src->next_input_byte; \ + br_state.bytes_in_buffer = cinfop->src->bytes_in_buffer; \ + get_buffer = permstate.get_buffer; \ + bits_left = permstate.bits_left; + +#define BITREAD_SAVE_STATE(cinfop,permstate) \ + cinfop->src->next_input_byte = br_state.next_input_byte; \ + cinfop->src->bytes_in_buffer = br_state.bytes_in_buffer; \ + permstate.get_buffer = get_buffer; \ + permstate.bits_left = bits_left + +/* + * These macros provide the in-line portion of bit fetching. + * Use CHECK_BIT_BUFFER to ensure there are N bits in get_buffer + * before using GET_BITS, PEEK_BITS, or DROP_BITS. + * The variables get_buffer and bits_left are assumed to be locals, + * but the state struct might not be (jpeg_huff_decode needs this). + * CHECK_BIT_BUFFER(state,n,action); + * Ensure there are N bits in get_buffer; if suspend, take action. + * val = GET_BITS(n); + * Fetch next N bits. + * val = PEEK_BITS(n); + * Fetch next N bits without removing them from the buffer. + * DROP_BITS(n); + * Discard next N bits. + * The value N should be a simple variable, not an expression, because it + * is evaluated multiple times. + */ + +#define CHECK_BIT_BUFFER(state,nbits,action) \ + { if (bits_left < (nbits)) { \ + if (! jpeg_fill_bit_buffer(&(state),get_buffer,bits_left,nbits)) \ + { action; } \ + get_buffer = (state).get_buffer; bits_left = (state).bits_left; } } + +#define GET_BITS(nbits) \ + (((int) (get_buffer >> (bits_left -= (nbits)))) & ((1<<(nbits))-1)) + +#define PEEK_BITS(nbits) \ + (((int) (get_buffer >> (bits_left - (nbits)))) & ((1<<(nbits))-1)) + +#define DROP_BITS(nbits) \ + (bits_left -= (nbits)) + +/* Load up the bit buffer to a depth of at least nbits */ +EXTERN(boolean) jpeg_fill_bit_buffer + JPP((bitread_working_state * state, register bit_buf_type get_buffer, + register int bits_left, int nbits)); + + +/* + * Code for extracting next Huffman-coded symbol from input bit stream. + * Again, this is time-critical and we make the main paths be macros. + * + * We use a lookahead table to process codes of up to HUFF_LOOKAHEAD bits + * without looping. Usually, more than 95% of the Huffman codes will be 8 + * or fewer bits long. The few overlength codes are handled with a loop, + * which need not be inline code. + * + * Notes about the HUFF_DECODE macro: + * 1. Near the end of the data segment, we may fail to get enough bits + * for a lookahead. In that case, we do it the hard way. + * 2. If the lookahead table contains no entry, the next code must be + * more than HUFF_LOOKAHEAD bits long. + * 3. jpeg_huff_decode returns -1 if forced to suspend. + */ + +#define HUFF_DECODE(result,state,htbl,failaction,slowlabel) \ +{ register int nb, look; \ + if (bits_left < HUFF_LOOKAHEAD) { \ + if (! jpeg_fill_bit_buffer(&state,get_buffer,bits_left, 0)) {failaction;} \ + get_buffer = state.get_buffer; bits_left = state.bits_left; \ + if (bits_left < HUFF_LOOKAHEAD) { \ + nb = 1; goto slowlabel; \ + } \ + } \ + look = PEEK_BITS(HUFF_LOOKAHEAD); \ + if ((nb = htbl->look_nbits[look]) != 0) { \ + DROP_BITS(nb); \ + result = htbl->look_sym[look]; \ + } else { \ + nb = HUFF_LOOKAHEAD+1; \ +slowlabel: \ + if ((result=jpeg_huff_decode(&state,get_buffer,bits_left,htbl,nb)) < 0) \ + { failaction; } \ + get_buffer = state.get_buffer; bits_left = state.bits_left; \ + } \ +} + +/* Out-of-line case for Huffman code fetching */ +EXTERN(int) jpeg_huff_decode + JPP((bitread_working_state * state, register bit_buf_type get_buffer, + register int bits_left, d_derived_tbl * htbl, int min_bits)); diff --git a/mk4/modimage/jpeg-6b/jdinput.c b/mk4/modimage/jpeg-6b/jdinput.c new file mode 100644 index 0000000..0c2ac8f --- /dev/null +++ b/mk4/modimage/jpeg-6b/jdinput.c @@ -0,0 +1,381 @@ +/* + * jdinput.c + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains input control logic for the JPEG decompressor. + * These routines are concerned with controlling the decompressor's input + * processing (marker reading and coefficient decoding). The actual input + * reading is done in jdmarker.c, jdhuff.c, and jdphuff.c. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Private state */ + +typedef struct { + struct jpeg_input_controller pub; /* public fields */ + + boolean inheaders; /* TRUE until first SOS is reached */ +} my_input_controller; + +typedef my_input_controller * my_inputctl_ptr; + + +/* Forward declarations */ +METHODDEF(int) consume_markers JPP((j_decompress_ptr cinfo)); + + +/* + * Routines to calculate various quantities related to the size of the image. + */ + +LOCAL(void) +initial_setup (j_decompress_ptr cinfo) +/* Called once, when first SOS marker is reached */ +{ + int ci; + jpeg_component_info *compptr; + + /* Make sure image isn't bigger than I can handle */ + if ((long) cinfo->image_height > (long) JPEG_MAX_DIMENSION || + (long) cinfo->image_width > (long) JPEG_MAX_DIMENSION) + ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) JPEG_MAX_DIMENSION); + + /* For now, precision must match compiled-in value... */ + if (cinfo->data_precision != BITS_IN_JSAMPLE) + ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision); + + /* Check that number of components won't exceed internal array sizes */ + if (cinfo->num_components > MAX_COMPONENTS) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components, + MAX_COMPONENTS); + + /* Compute maximum sampling factors; check factor validity */ + cinfo->max_h_samp_factor = 1; + cinfo->max_v_samp_factor = 1; + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + if (compptr->h_samp_factor<=0 || compptr->h_samp_factor>MAX_SAMP_FACTOR || + compptr->v_samp_factor<=0 || compptr->v_samp_factor>MAX_SAMP_FACTOR) + ERREXIT(cinfo, JERR_BAD_SAMPLING); + cinfo->max_h_samp_factor = MAX(cinfo->max_h_samp_factor, + compptr->h_samp_factor); + cinfo->max_v_samp_factor = MAX(cinfo->max_v_samp_factor, + compptr->v_samp_factor); + } + + /* We initialize DCT_scaled_size and min_DCT_scaled_size to DCTSIZE. + * In the full decompressor, this will be overridden by jdmaster.c; + * but in the transcoder, jdmaster.c is not used, so we must do it here. + */ + cinfo->min_DCT_scaled_size = DCTSIZE; + + /* Compute dimensions of components */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + compptr->DCT_scaled_size = DCTSIZE; + /* Size in DCT blocks */ + compptr->width_in_blocks = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor, + (long) (cinfo->max_h_samp_factor * DCTSIZE)); + compptr->height_in_blocks = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor, + (long) (cinfo->max_v_samp_factor * DCTSIZE)); + /* downsampled_width and downsampled_height will also be overridden by + * jdmaster.c if we are doing full decompression. The transcoder library + * doesn't use these values, but the calling application might. + */ + /* Size in samples */ + compptr->downsampled_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor, + (long) cinfo->max_h_samp_factor); + compptr->downsampled_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor, + (long) cinfo->max_v_samp_factor); + /* Mark component needed, until color conversion says otherwise */ + compptr->component_needed = TRUE; + /* Mark no quantization table yet saved for component */ + compptr->quant_table = NULL; + } + + /* Compute number of fully interleaved MCU rows. */ + cinfo->total_iMCU_rows = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height, + (long) (cinfo->max_v_samp_factor*DCTSIZE)); + + /* Decide whether file contains multiple scans */ + if (cinfo->comps_in_scan < cinfo->num_components || cinfo->progressive_mode) + cinfo->inputctl->has_multiple_scans = TRUE; + else + cinfo->inputctl->has_multiple_scans = FALSE; +} + + +LOCAL(void) +per_scan_setup (j_decompress_ptr cinfo) +/* Do computations that are needed before processing a JPEG scan */ +/* cinfo->comps_in_scan and cinfo->cur_comp_info[] were set from SOS marker */ +{ + int ci, mcublks, tmp; + jpeg_component_info *compptr; + + if (cinfo->comps_in_scan == 1) { + + /* Noninterleaved (single-component) scan */ + compptr = cinfo->cur_comp_info[0]; + + /* Overall image size in MCUs */ + cinfo->MCUs_per_row = compptr->width_in_blocks; + cinfo->MCU_rows_in_scan = compptr->height_in_blocks; + + /* For noninterleaved scan, always one block per MCU */ + compptr->MCU_width = 1; + compptr->MCU_height = 1; + compptr->MCU_blocks = 1; + compptr->MCU_sample_width = compptr->DCT_scaled_size; + compptr->last_col_width = 1; + /* For noninterleaved scans, it is convenient to define last_row_height + * as the number of block rows present in the last iMCU row. + */ + tmp = (int) (compptr->height_in_blocks % compptr->v_samp_factor); + if (tmp == 0) tmp = compptr->v_samp_factor; + compptr->last_row_height = tmp; + + /* Prepare array describing MCU composition */ + cinfo->blocks_in_MCU = 1; + cinfo->MCU_membership[0] = 0; + + } else { + + /* Interleaved (multi-component) scan */ + if (cinfo->comps_in_scan <= 0 || cinfo->comps_in_scan > MAX_COMPS_IN_SCAN) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->comps_in_scan, + MAX_COMPS_IN_SCAN); + + /* Overall image size in MCUs */ + cinfo->MCUs_per_row = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width, + (long) (cinfo->max_h_samp_factor*DCTSIZE)); + cinfo->MCU_rows_in_scan = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height, + (long) (cinfo->max_v_samp_factor*DCTSIZE)); + + cinfo->blocks_in_MCU = 0; + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* Sampling factors give # of blocks of component in each MCU */ + compptr->MCU_width = compptr->h_samp_factor; + compptr->MCU_height = compptr->v_samp_factor; + compptr->MCU_blocks = compptr->MCU_width * compptr->MCU_height; + compptr->MCU_sample_width = compptr->MCU_width * compptr->DCT_scaled_size; + /* Figure number of non-dummy blocks in last MCU column & row */ + tmp = (int) (compptr->width_in_blocks % compptr->MCU_width); + if (tmp == 0) tmp = compptr->MCU_width; + compptr->last_col_width = tmp; + tmp = (int) (compptr->height_in_blocks % compptr->MCU_height); + if (tmp == 0) tmp = compptr->MCU_height; + compptr->last_row_height = tmp; + /* Prepare array describing MCU composition */ + mcublks = compptr->MCU_blocks; + if (cinfo->blocks_in_MCU + mcublks > D_MAX_BLOCKS_IN_MCU) + ERREXIT(cinfo, JERR_BAD_MCU_SIZE); + while (mcublks-- > 0) { + cinfo->MCU_membership[cinfo->blocks_in_MCU++] = ci; + } + } + + } +} + + +/* + * Save away a copy of the Q-table referenced by each component present + * in the current scan, unless already saved during a prior scan. + * + * In a multiple-scan JPEG file, the encoder could assign different components + * the same Q-table slot number, but change table definitions between scans + * so that each component uses a different Q-table. (The IJG encoder is not + * currently capable of doing this, but other encoders might.) Since we want + * to be able to dequantize all the components at the end of the file, this + * means that we have to save away the table actually used for each component. + * We do this by copying the table at the start of the first scan containing + * the component. + * The JPEG spec prohibits the encoder from changing the contents of a Q-table + * slot between scans of a component using that slot. If the encoder does so + * anyway, this decoder will simply use the Q-table values that were current + * at the start of the first scan for the component. + * + * The decompressor output side looks only at the saved quant tables, + * not at the current Q-table slots. + */ + +LOCAL(void) +latch_quant_tables (j_decompress_ptr cinfo) +{ + int ci, qtblno; + jpeg_component_info *compptr; + JQUANT_TBL * qtbl; + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* No work if we already saved Q-table for this component */ + if (compptr->quant_table != NULL) + continue; + /* Make sure specified quantization table is present */ + qtblno = compptr->quant_tbl_no; + if (qtblno < 0 || qtblno >= NUM_QUANT_TBLS || + cinfo->quant_tbl_ptrs[qtblno] == NULL) + ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, qtblno); + /* OK, save away the quantization table */ + qtbl = (JQUANT_TBL *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(JQUANT_TBL)); + MEMCOPY(qtbl, cinfo->quant_tbl_ptrs[qtblno], SIZEOF(JQUANT_TBL)); + compptr->quant_table = qtbl; + } +} + + +/* + * Initialize the input modules to read a scan of compressed data. + * The first call to this is done by jdmaster.c after initializing + * the entire decompressor (during jpeg_start_decompress). + * Subsequent calls come from consume_markers, below. + */ + +METHODDEF(void) +start_input_pass (j_decompress_ptr cinfo) +{ + per_scan_setup(cinfo); + latch_quant_tables(cinfo); + (*cinfo->entropy->start_pass) (cinfo); + (*cinfo->coef->start_input_pass) (cinfo); + cinfo->inputctl->consume_input = cinfo->coef->consume_data; +} + + +/* + * Finish up after inputting a compressed-data scan. + * This is called by the coefficient controller after it's read all + * the expected data of the scan. + */ + +METHODDEF(void) +finish_input_pass (j_decompress_ptr cinfo) +{ + cinfo->inputctl->consume_input = consume_markers; +} + + +/* + * Read JPEG markers before, between, or after compressed-data scans. + * Change state as necessary when a new scan is reached. + * Return value is JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI. + * + * The consume_input method pointer points either here or to the + * coefficient controller's consume_data routine, depending on whether + * we are reading a compressed data segment or inter-segment markers. + */ + +METHODDEF(int) +consume_markers (j_decompress_ptr cinfo) +{ + my_inputctl_ptr inputctl = (my_inputctl_ptr) cinfo->inputctl; + int val; + + if (inputctl->pub.eoi_reached) /* After hitting EOI, read no further */ + return JPEG_REACHED_EOI; + + val = (*cinfo->marker->read_markers) (cinfo); + + switch (val) { + case JPEG_REACHED_SOS: /* Found SOS */ + if (inputctl->inheaders) { /* 1st SOS */ + initial_setup(cinfo); + inputctl->inheaders = FALSE; + /* Note: start_input_pass must be called by jdmaster.c + * before any more input can be consumed. jdapimin.c is + * responsible for enforcing this sequencing. + */ + } else { /* 2nd or later SOS marker */ + if (! inputctl->pub.has_multiple_scans) + ERREXIT(cinfo, JERR_EOI_EXPECTED); /* Oops, I wasn't expecting this! */ + start_input_pass(cinfo); + } + break; + case JPEG_REACHED_EOI: /* Found EOI */ + inputctl->pub.eoi_reached = TRUE; + if (inputctl->inheaders) { /* Tables-only datastream, apparently */ + if (cinfo->marker->saw_SOF) + ERREXIT(cinfo, JERR_SOF_NO_SOS); + } else { + /* Prevent infinite loop in coef ctlr's decompress_data routine + * if user set output_scan_number larger than number of scans. + */ + if (cinfo->output_scan_number > cinfo->input_scan_number) + cinfo->output_scan_number = cinfo->input_scan_number; + } + break; + case JPEG_SUSPENDED: + break; + } + + return val; +} + + +/* + * Reset state to begin a fresh datastream. + */ + +METHODDEF(void) +reset_input_controller (j_decompress_ptr cinfo) +{ + my_inputctl_ptr inputctl = (my_inputctl_ptr) cinfo->inputctl; + + inputctl->pub.consume_input = consume_markers; + inputctl->pub.has_multiple_scans = FALSE; /* "unknown" would be better */ + inputctl->pub.eoi_reached = FALSE; + inputctl->inheaders = TRUE; + /* Reset other modules */ + (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo); + (*cinfo->marker->reset_marker_reader) (cinfo); + /* Reset progression state -- would be cleaner if entropy decoder did this */ + cinfo->coef_bits = NULL; +} + + +/* + * Initialize the input controller module. + * This is called only once, when the decompression object is created. + */ + +GLOBAL(void) +jinit_input_controller (j_decompress_ptr cinfo) +{ + my_inputctl_ptr inputctl; + + /* Create subobject in permanent pool */ + inputctl = (my_inputctl_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + SIZEOF(my_input_controller)); + cinfo->inputctl = (struct jpeg_input_controller *) inputctl; + /* Initialize method pointers */ + inputctl->pub.consume_input = consume_markers; + inputctl->pub.reset_input_controller = reset_input_controller; + inputctl->pub.start_input_pass = start_input_pass; + inputctl->pub.finish_input_pass = finish_input_pass; + /* Initialize state: can't use reset_input_controller since we don't + * want to try to reset other modules yet. + */ + inputctl->pub.has_multiple_scans = FALSE; /* "unknown" would be better */ + inputctl->pub.eoi_reached = FALSE; + inputctl->inheaders = TRUE; +} diff --git a/mk4/modimage/jpeg-6b/jdmainct.c b/mk4/modimage/jpeg-6b/jdmainct.c new file mode 100644 index 0000000..13c956f --- /dev/null +++ b/mk4/modimage/jpeg-6b/jdmainct.c @@ -0,0 +1,512 @@ +/* + * jdmainct.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the main buffer controller for decompression. + * The main buffer lies between the JPEG decompressor proper and the + * post-processor; it holds downsampled data in the JPEG colorspace. + * + * Note that this code is bypassed in raw-data mode, since the application + * supplies the equivalent of the main buffer in that case. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * In the current system design, the main buffer need never be a full-image + * buffer; any full-height buffers will be found inside the coefficient or + * postprocessing controllers. Nonetheless, the main controller is not + * trivial. Its responsibility is to provide context rows for upsampling/ + * rescaling, and doing this in an efficient fashion is a bit tricky. + * + * Postprocessor input data is counted in "row groups". A row group + * is defined to be (v_samp_factor * DCT_scaled_size / min_DCT_scaled_size) + * sample rows of each component. (We require DCT_scaled_size values to be + * chosen such that these numbers are integers. In practice DCT_scaled_size + * values will likely be powers of two, so we actually have the stronger + * condition that DCT_scaled_size / min_DCT_scaled_size is an integer.) + * Upsampling will typically produce max_v_samp_factor pixel rows from each + * row group (times any additional scale factor that the upsampler is + * applying). + * + * The coefficient controller will deliver data to us one iMCU row at a time; + * each iMCU row contains v_samp_factor * DCT_scaled_size sample rows, or + * exactly min_DCT_scaled_size row groups. (This amount of data corresponds + * to one row of MCUs when the image is fully interleaved.) Note that the + * number of sample rows varies across components, but the number of row + * groups does not. Some garbage sample rows may be included in the last iMCU + * row at the bottom of the image. + * + * Depending on the vertical scaling algorithm used, the upsampler may need + * access to the sample row(s) above and below its current input row group. + * The upsampler is required to set need_context_rows TRUE at global selection + * time if so. When need_context_rows is FALSE, this controller can simply + * obtain one iMCU row at a time from the coefficient controller and dole it + * out as row groups to the postprocessor. + * + * When need_context_rows is TRUE, this controller guarantees that the buffer + * passed to postprocessing contains at least one row group's worth of samples + * above and below the row group(s) being processed. Note that the context + * rows "above" the first passed row group appear at negative row offsets in + * the passed buffer. At the top and bottom of the image, the required + * context rows are manufactured by duplicating the first or last real sample + * row; this avoids having special cases in the upsampling inner loops. + * + * The amount of context is fixed at one row group just because that's a + * convenient number for this controller to work with. The existing + * upsamplers really only need one sample row of context. An upsampler + * supporting arbitrary output rescaling might wish for more than one row + * group of context when shrinking the image; tough, we don't handle that. + * (This is justified by the assumption that downsizing will be handled mostly + * by adjusting the DCT_scaled_size values, so that the actual scale factor at + * the upsample step needn't be much less than one.) + * + * To provide the desired context, we have to retain the last two row groups + * of one iMCU row while reading in the next iMCU row. (The last row group + * can't be processed until we have another row group for its below-context, + * and so we have to save the next-to-last group too for its above-context.) + * We could do this most simply by copying data around in our buffer, but + * that'd be very slow. We can avoid copying any data by creating a rather + * strange pointer structure. Here's how it works. We allocate a workspace + * consisting of M+2 row groups (where M = min_DCT_scaled_size is the number + * of row groups per iMCU row). We create two sets of redundant pointers to + * the workspace. Labeling the physical row groups 0 to M+1, the synthesized + * pointer lists look like this: + * M+1 M-1 + * master pointer --> 0 master pointer --> 0 + * 1 1 + * ... ... + * M-3 M-3 + * M-2 M + * M-1 M+1 + * M M-2 + * M+1 M-1 + * 0 0 + * We read alternate iMCU rows using each master pointer; thus the last two + * row groups of the previous iMCU row remain un-overwritten in the workspace. + * The pointer lists are set up so that the required context rows appear to + * be adjacent to the proper places when we pass the pointer lists to the + * upsampler. + * + * The above pictures describe the normal state of the pointer lists. + * At top and bottom of the image, we diddle the pointer lists to duplicate + * the first or last sample row as necessary (this is cheaper than copying + * sample rows around). + * + * This scheme breaks down if M < 2, ie, min_DCT_scaled_size is 1. In that + * situation each iMCU row provides only one row group so the buffering logic + * must be different (eg, we must read two iMCU rows before we can emit the + * first row group). For now, we simply do not support providing context + * rows when min_DCT_scaled_size is 1. That combination seems unlikely to + * be worth providing --- if someone wants a 1/8th-size preview, they probably + * want it quick and dirty, so a context-free upsampler is sufficient. + */ + + +/* Private buffer controller object */ + +typedef struct { + struct jpeg_d_main_controller pub; /* public fields */ + + /* Pointer to allocated workspace (M or M+2 row groups). */ + JSAMPARRAY buffer[MAX_COMPONENTS]; + + boolean buffer_full; /* Have we gotten an iMCU row from decoder? */ + JDIMENSION rowgroup_ctr; /* counts row groups output to postprocessor */ + + /* Remaining fields are only used in the context case. */ + + /* These are the master pointers to the funny-order pointer lists. */ + JSAMPIMAGE xbuffer[2]; /* pointers to weird pointer lists */ + + int whichptr; /* indicates which pointer set is now in use */ + int context_state; /* process_data state machine status */ + JDIMENSION rowgroups_avail; /* row groups available to postprocessor */ + JDIMENSION iMCU_row_ctr; /* counts iMCU rows to detect image top/bot */ +} my_main_controller; + +typedef my_main_controller * my_main_ptr; + +/* context_state values: */ +#define CTX_PREPARE_FOR_IMCU 0 /* need to prepare for MCU row */ +#define CTX_PROCESS_IMCU 1 /* feeding iMCU to postprocessor */ +#define CTX_POSTPONED_ROW 2 /* feeding postponed row group */ + + +/* Forward declarations */ +METHODDEF(void) process_data_simple_main + JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf, + JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)); +METHODDEF(void) process_data_context_main + JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf, + JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)); +#ifdef QUANT_2PASS_SUPPORTED +METHODDEF(void) process_data_crank_post + JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf, + JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)); +#endif + + +LOCAL(void) +alloc_funny_pointers (j_decompress_ptr cinfo) +/* Allocate space for the funny pointer lists. + * This is done only once, not once per pass. + */ +{ + my_main_ptr main = (my_main_ptr) cinfo->main; + int ci, rgroup; + int M = cinfo->min_DCT_scaled_size; + jpeg_component_info *compptr; + JSAMPARRAY xbuf; + + /* Get top-level space for component array pointers. + * We alloc both arrays with one call to save a few cycles. + */ + main->xbuffer[0] = (JSAMPIMAGE) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + cinfo->num_components * 2 * SIZEOF(JSAMPARRAY)); + main->xbuffer[1] = main->xbuffer[0] + cinfo->num_components; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + rgroup = (compptr->v_samp_factor * compptr->DCT_scaled_size) / + cinfo->min_DCT_scaled_size; /* height of a row group of component */ + /* Get space for pointer lists --- M+4 row groups in each list. + * We alloc both pointer lists with one call to save a few cycles. + */ + xbuf = (JSAMPARRAY) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + 2 * (rgroup * (M + 4)) * SIZEOF(JSAMPROW)); + xbuf += rgroup; /* want one row group at negative offsets */ + main->xbuffer[0][ci] = xbuf; + xbuf += rgroup * (M + 4); + main->xbuffer[1][ci] = xbuf; + } +} + + +LOCAL(void) +make_funny_pointers (j_decompress_ptr cinfo) +/* Create the funny pointer lists discussed in the comments above. + * The actual workspace is already allocated (in main->buffer), + * and the space for the pointer lists is allocated too. + * This routine just fills in the curiously ordered lists. + * This will be repeated at the beginning of each pass. + */ +{ + my_main_ptr main = (my_main_ptr) cinfo->main; + int ci, i, rgroup; + int M = cinfo->min_DCT_scaled_size; + jpeg_component_info *compptr; + JSAMPARRAY buf, xbuf0, xbuf1; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + rgroup = (compptr->v_samp_factor * compptr->DCT_scaled_size) / + cinfo->min_DCT_scaled_size; /* height of a row group of component */ + xbuf0 = main->xbuffer[0][ci]; + xbuf1 = main->xbuffer[1][ci]; + /* First copy the workspace pointers as-is */ + buf = main->buffer[ci]; + for (i = 0; i < rgroup * (M + 2); i++) { + xbuf0[i] = xbuf1[i] = buf[i]; + } + /* In the second list, put the last four row groups in swapped order */ + for (i = 0; i < rgroup * 2; i++) { + xbuf1[rgroup*(M-2) + i] = buf[rgroup*M + i]; + xbuf1[rgroup*M + i] = buf[rgroup*(M-2) + i]; + } + /* The wraparound pointers at top and bottom will be filled later + * (see set_wraparound_pointers, below). Initially we want the "above" + * pointers to duplicate the first actual data line. This only needs + * to happen in xbuffer[0]. + */ + for (i = 0; i < rgroup; i++) { + xbuf0[i - rgroup] = xbuf0[0]; + } + } +} + + +LOCAL(void) +set_wraparound_pointers (j_decompress_ptr cinfo) +/* Set up the "wraparound" pointers at top and bottom of the pointer lists. + * This changes the pointer list state from top-of-image to the normal state. + */ +{ + my_main_ptr main = (my_main_ptr) cinfo->main; + int ci, i, rgroup; + int M = cinfo->min_DCT_scaled_size; + jpeg_component_info *compptr; + JSAMPARRAY xbuf0, xbuf1; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + rgroup = (compptr->v_samp_factor * compptr->DCT_scaled_size) / + cinfo->min_DCT_scaled_size; /* height of a row group of component */ + xbuf0 = main->xbuffer[0][ci]; + xbuf1 = main->xbuffer[1][ci]; + for (i = 0; i < rgroup; i++) { + xbuf0[i - rgroup] = xbuf0[rgroup*(M+1) + i]; + xbuf1[i - rgroup] = xbuf1[rgroup*(M+1) + i]; + xbuf0[rgroup*(M+2) + i] = xbuf0[i]; + xbuf1[rgroup*(M+2) + i] = xbuf1[i]; + } + } +} + + +LOCAL(void) +set_bottom_pointers (j_decompress_ptr cinfo) +/* Change the pointer lists to duplicate the last sample row at the bottom + * of the image. whichptr indicates which xbuffer holds the final iMCU row. + * Also sets rowgroups_avail to indicate number of nondummy row groups in row. + */ +{ + my_main_ptr main = (my_main_ptr) cinfo->main; + int ci, i, rgroup, iMCUheight, rows_left; + jpeg_component_info *compptr; + JSAMPARRAY xbuf; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Count sample rows in one iMCU row and in one row group */ + iMCUheight = compptr->v_samp_factor * compptr->DCT_scaled_size; + rgroup = iMCUheight / cinfo->min_DCT_scaled_size; + /* Count nondummy sample rows remaining for this component */ + rows_left = (int) (compptr->downsampled_height % (JDIMENSION) iMCUheight); + if (rows_left == 0) rows_left = iMCUheight; + /* Count nondummy row groups. Should get same answer for each component, + * so we need only do it once. + */ + if (ci == 0) { + main->rowgroups_avail = (JDIMENSION) ((rows_left-1) / rgroup + 1); + } + /* Duplicate the last real sample row rgroup*2 times; this pads out the + * last partial rowgroup and ensures at least one full rowgroup of context. + */ + xbuf = main->xbuffer[main->whichptr][ci]; + for (i = 0; i < rgroup * 2; i++) { + xbuf[rows_left + i] = xbuf[rows_left-1]; + } + } +} + + +/* + * Initialize for a processing pass. + */ + +METHODDEF(void) +start_pass_main (j_decompress_ptr cinfo, J_BUF_MODE pass_mode) +{ + my_main_ptr main = (my_main_ptr) cinfo->main; + + switch (pass_mode) { + case JBUF_PASS_THRU: + if (cinfo->upsample->need_context_rows) { + main->pub.process_data = process_data_context_main; + make_funny_pointers(cinfo); /* Create the xbuffer[] lists */ + main->whichptr = 0; /* Read first iMCU row into xbuffer[0] */ + main->context_state = CTX_PREPARE_FOR_IMCU; + main->iMCU_row_ctr = 0; + } else { + /* Simple case with no context needed */ + main->pub.process_data = process_data_simple_main; + } + main->buffer_full = FALSE; /* Mark buffer empty */ + main->rowgroup_ctr = 0; + break; +#ifdef QUANT_2PASS_SUPPORTED + case JBUF_CRANK_DEST: + /* For last pass of 2-pass quantization, just crank the postprocessor */ + main->pub.process_data = process_data_crank_post; + break; +#endif + default: + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + break; + } +} + + +/* + * Process some data. + * This handles the simple case where no context is required. + */ + +METHODDEF(void) +process_data_simple_main (j_decompress_ptr cinfo, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +{ + my_main_ptr main = (my_main_ptr) cinfo->main; + JDIMENSION rowgroups_avail; + + /* Read input data if we haven't filled the main buffer yet */ + if (! main->buffer_full) { + if (! (*cinfo->coef->decompress_data) (cinfo, main->buffer)) + return; /* suspension forced, can do nothing more */ + main->buffer_full = TRUE; /* OK, we have an iMCU row to work with */ + } + + /* There are always min_DCT_scaled_size row groups in an iMCU row. */ + rowgroups_avail = (JDIMENSION) cinfo->min_DCT_scaled_size; + /* Note: at the bottom of the image, we may pass extra garbage row groups + * to the postprocessor. The postprocessor has to check for bottom + * of image anyway (at row resolution), so no point in us doing it too. + */ + + /* Feed the postprocessor */ + (*cinfo->post->post_process_data) (cinfo, main->buffer, + &main->rowgroup_ctr, rowgroups_avail, + output_buf, out_row_ctr, out_rows_avail); + + /* Has postprocessor consumed all the data yet? If so, mark buffer empty */ + if (main->rowgroup_ctr >= rowgroups_avail) { + main->buffer_full = FALSE; + main->rowgroup_ctr = 0; + } +} + + +/* + * Process some data. + * This handles the case where context rows must be provided. + */ + +METHODDEF(void) +process_data_context_main (j_decompress_ptr cinfo, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +{ + my_main_ptr main = (my_main_ptr) cinfo->main; + + /* Read input data if we haven't filled the main buffer yet */ + if (! main->buffer_full) { + if (! (*cinfo->coef->decompress_data) (cinfo, + main->xbuffer[main->whichptr])) + return; /* suspension forced, can do nothing more */ + main->buffer_full = TRUE; /* OK, we have an iMCU row to work with */ + main->iMCU_row_ctr++; /* count rows received */ + } + + /* Postprocessor typically will not swallow all the input data it is handed + * in one call (due to filling the output buffer first). Must be prepared + * to exit and restart. This switch lets us keep track of how far we got. + * Note that each case falls through to the next on successful completion. + */ + switch (main->context_state) { + case CTX_POSTPONED_ROW: + /* Call postprocessor using previously set pointers for postponed row */ + (*cinfo->post->post_process_data) (cinfo, main->xbuffer[main->whichptr], + &main->rowgroup_ctr, main->rowgroups_avail, + output_buf, out_row_ctr, out_rows_avail); + if (main->rowgroup_ctr < main->rowgroups_avail) + return; /* Need to suspend */ + main->context_state = CTX_PREPARE_FOR_IMCU; + if (*out_row_ctr >= out_rows_avail) + return; /* Postprocessor exactly filled output buf */ + /*FALLTHROUGH*/ + case CTX_PREPARE_FOR_IMCU: + /* Prepare to process first M-1 row groups of this iMCU row */ + main->rowgroup_ctr = 0; + main->rowgroups_avail = (JDIMENSION) (cinfo->min_DCT_scaled_size - 1); + /* Check for bottom of image: if so, tweak pointers to "duplicate" + * the last sample row, and adjust rowgroups_avail to ignore padding rows. + */ + if (main->iMCU_row_ctr == cinfo->total_iMCU_rows) + set_bottom_pointers(cinfo); + main->context_state = CTX_PROCESS_IMCU; + /*FALLTHROUGH*/ + case CTX_PROCESS_IMCU: + /* Call postprocessor using previously set pointers */ + (*cinfo->post->post_process_data) (cinfo, main->xbuffer[main->whichptr], + &main->rowgroup_ctr, main->rowgroups_avail, + output_buf, out_row_ctr, out_rows_avail); + if (main->rowgroup_ctr < main->rowgroups_avail) + return; /* Need to suspend */ + /* After the first iMCU, change wraparound pointers to normal state */ + if (main->iMCU_row_ctr == 1) + set_wraparound_pointers(cinfo); + /* Prepare to load new iMCU row using other xbuffer list */ + main->whichptr ^= 1; /* 0=>1 or 1=>0 */ + main->buffer_full = FALSE; + /* Still need to process last row group of this iMCU row, */ + /* which is saved at index M+1 of the other xbuffer */ + main->rowgroup_ctr = (JDIMENSION) (cinfo->min_DCT_scaled_size + 1); + main->rowgroups_avail = (JDIMENSION) (cinfo->min_DCT_scaled_size + 2); + main->context_state = CTX_POSTPONED_ROW; + } +} + + +/* + * Process some data. + * Final pass of two-pass quantization: just call the postprocessor. + * Source data will be the postprocessor controller's internal buffer. + */ + +#ifdef QUANT_2PASS_SUPPORTED + +METHODDEF(void) +process_data_crank_post (j_decompress_ptr cinfo, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +{ + (*cinfo->post->post_process_data) (cinfo, (JSAMPIMAGE) NULL, + (JDIMENSION *) NULL, (JDIMENSION) 0, + output_buf, out_row_ctr, out_rows_avail); +} + +#endif /* QUANT_2PASS_SUPPORTED */ + + +/* + * Initialize main buffer controller. + */ + +GLOBAL(void) +jinit_d_main_controller (j_decompress_ptr cinfo, boolean need_full_buffer) +{ + my_main_ptr main; + int ci, rgroup, ngroups; + jpeg_component_info *compptr; + + main = (my_main_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_main_controller)); + cinfo->main = (struct jpeg_d_main_controller *) main; + main->pub.start_pass = start_pass_main; + + if (need_full_buffer) /* shouldn't happen */ + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + + /* Allocate the workspace. + * ngroups is the number of row groups we need. + */ + if (cinfo->upsample->need_context_rows) { + if (cinfo->min_DCT_scaled_size < 2) /* unsupported, see comments above */ + ERREXIT(cinfo, JERR_NOTIMPL); + alloc_funny_pointers(cinfo); /* Alloc space for xbuffer[] lists */ + ngroups = cinfo->min_DCT_scaled_size + 2; + } else { + ngroups = cinfo->min_DCT_scaled_size; + } + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + rgroup = (compptr->v_samp_factor * compptr->DCT_scaled_size) / + cinfo->min_DCT_scaled_size; /* height of a row group of component */ + main->buffer[ci] = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + compptr->width_in_blocks * compptr->DCT_scaled_size, + (JDIMENSION) (rgroup * ngroups)); + } +} diff --git a/mk4/modimage/jpeg-6b/jdmarker.c b/mk4/modimage/jpeg-6b/jdmarker.c new file mode 100644 index 0000000..f4cca8c --- /dev/null +++ b/mk4/modimage/jpeg-6b/jdmarker.c @@ -0,0 +1,1360 @@ +/* + * jdmarker.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to decode JPEG datastream markers. + * Most of the complexity arises from our desire to support input + * suspension: if not all of the data for a marker is available, + * we must exit back to the application. On resumption, we reprocess + * the marker. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +typedef enum { /* JPEG marker codes */ + M_SOF0 = 0xc0, + M_SOF1 = 0xc1, + M_SOF2 = 0xc2, + M_SOF3 = 0xc3, + + M_SOF5 = 0xc5, + M_SOF6 = 0xc6, + M_SOF7 = 0xc7, + + M_JPG = 0xc8, + M_SOF9 = 0xc9, + M_SOF10 = 0xca, + M_SOF11 = 0xcb, + + M_SOF13 = 0xcd, + M_SOF14 = 0xce, + M_SOF15 = 0xcf, + + M_DHT = 0xc4, + + M_DAC = 0xcc, + + M_RST0 = 0xd0, + M_RST1 = 0xd1, + M_RST2 = 0xd2, + M_RST3 = 0xd3, + M_RST4 = 0xd4, + M_RST5 = 0xd5, + M_RST6 = 0xd6, + M_RST7 = 0xd7, + + M_SOI = 0xd8, + M_EOI = 0xd9, + M_SOS = 0xda, + M_DQT = 0xdb, + M_DNL = 0xdc, + M_DRI = 0xdd, + M_DHP = 0xde, + M_EXP = 0xdf, + + M_APP0 = 0xe0, + M_APP1 = 0xe1, + M_APP2 = 0xe2, + M_APP3 = 0xe3, + M_APP4 = 0xe4, + M_APP5 = 0xe5, + M_APP6 = 0xe6, + M_APP7 = 0xe7, + M_APP8 = 0xe8, + M_APP9 = 0xe9, + M_APP10 = 0xea, + M_APP11 = 0xeb, + M_APP12 = 0xec, + M_APP13 = 0xed, + M_APP14 = 0xee, + M_APP15 = 0xef, + + M_JPG0 = 0xf0, + M_JPG13 = 0xfd, + M_COM = 0xfe, + + M_TEM = 0x01, + + M_ERROR = 0x100 +} JPEG_MARKER; + + +/* Private state */ + +typedef struct { + struct jpeg_marker_reader pub; /* public fields */ + + /* Application-overridable marker processing methods */ + jpeg_marker_parser_method process_COM; + jpeg_marker_parser_method process_APPn[16]; + + /* Limit on marker data length to save for each marker type */ + unsigned int length_limit_COM; + unsigned int length_limit_APPn[16]; + + /* Status of COM/APPn marker saving */ + jpeg_saved_marker_ptr cur_marker; /* NULL if not processing a marker */ + unsigned int bytes_read; /* data bytes read so far in marker */ + /* Note: cur_marker is not linked into marker_list until it's all read. */ +} my_marker_reader; + +typedef my_marker_reader * my_marker_ptr; + + +/* + * Macros for fetching data from the data source module. + * + * At all times, cinfo->src->next_input_byte and ->bytes_in_buffer reflect + * the current restart point; we update them only when we have reached a + * suitable place to restart if a suspension occurs. + */ + +/* Declare and initialize local copies of input pointer/count */ +#define INPUT_VARS(cinfo) \ + struct jpeg_source_mgr * datasrc = (cinfo)->src; \ + const JOCTET * next_input_byte = datasrc->next_input_byte; \ + size_t bytes_in_buffer = datasrc->bytes_in_buffer + +/* Unload the local copies --- do this only at a restart boundary */ +#define INPUT_SYNC(cinfo) \ + ( datasrc->next_input_byte = next_input_byte, \ + datasrc->bytes_in_buffer = bytes_in_buffer ) + +/* Reload the local copies --- used only in MAKE_BYTE_AVAIL */ +#define INPUT_RELOAD(cinfo) \ + ( next_input_byte = datasrc->next_input_byte, \ + bytes_in_buffer = datasrc->bytes_in_buffer ) + +/* Internal macro for INPUT_BYTE and INPUT_2BYTES: make a byte available. + * Note we do *not* do INPUT_SYNC before calling fill_input_buffer, + * but we must reload the local copies after a successful fill. + */ +#define MAKE_BYTE_AVAIL(cinfo,action) \ + if (bytes_in_buffer == 0) { \ + if (! (*datasrc->fill_input_buffer) (cinfo)) \ + { action; } \ + INPUT_RELOAD(cinfo); \ + } + +/* Read a byte into variable V. + * If must suspend, take the specified action (typically "return FALSE"). + */ +#define INPUT_BYTE(cinfo,V,action) \ + MAKESTMT( MAKE_BYTE_AVAIL(cinfo,action); \ + bytes_in_buffer--; \ + V = GETJOCTET(*next_input_byte++); ) + +/* As above, but read two bytes interpreted as an unsigned 16-bit integer. + * V should be declared unsigned int or perhaps INT32. + */ +#define INPUT_2BYTES(cinfo,V,action) \ + MAKESTMT( MAKE_BYTE_AVAIL(cinfo,action); \ + bytes_in_buffer--; \ + V = ((unsigned int) GETJOCTET(*next_input_byte++)) << 8; \ + MAKE_BYTE_AVAIL(cinfo,action); \ + bytes_in_buffer--; \ + V += GETJOCTET(*next_input_byte++); ) + + +/* + * Routines to process JPEG markers. + * + * Entry condition: JPEG marker itself has been read and its code saved + * in cinfo->unread_marker; input restart point is just after the marker. + * + * Exit: if return TRUE, have read and processed any parameters, and have + * updated the restart point to point after the parameters. + * If return FALSE, was forced to suspend before reaching end of + * marker parameters; restart point has not been moved. Same routine + * will be called again after application supplies more input data. + * + * This approach to suspension assumes that all of a marker's parameters + * can fit into a single input bufferload. This should hold for "normal" + * markers. Some COM/APPn markers might have large parameter segments + * that might not fit. If we are simply dropping such a marker, we use + * skip_input_data to get past it, and thereby put the problem on the + * source manager's shoulders. If we are saving the marker's contents + * into memory, we use a slightly different convention: when forced to + * suspend, the marker processor updates the restart point to the end of + * what it's consumed (ie, the end of the buffer) before returning FALSE. + * On resumption, cinfo->unread_marker still contains the marker code, + * but the data source will point to the next chunk of marker data. + * The marker processor must retain internal state to deal with this. + * + * Note that we don't bother to avoid duplicate trace messages if a + * suspension occurs within marker parameters. Other side effects + * require more care. + */ + + +LOCAL(boolean) +get_soi (j_decompress_ptr cinfo) +/* Process an SOI marker */ +{ + int i; + + TRACEMS(cinfo, 1, JTRC_SOI); + + if (cinfo->marker->saw_SOI) + ERREXIT(cinfo, JERR_SOI_DUPLICATE); + + /* Reset all parameters that are defined to be reset by SOI */ + + for (i = 0; i < NUM_ARITH_TBLS; i++) { + cinfo->arith_dc_L[i] = 0; + cinfo->arith_dc_U[i] = 1; + cinfo->arith_ac_K[i] = 5; + } + cinfo->restart_interval = 0; + + /* Set initial assumptions for colorspace etc */ + + cinfo->jpeg_color_space = JCS_UNKNOWN; + cinfo->CCIR601_sampling = FALSE; /* Assume non-CCIR sampling??? */ + + cinfo->saw_JFIF_marker = FALSE; + cinfo->JFIF_major_version = 1; /* set default JFIF APP0 values */ + cinfo->JFIF_minor_version = 1; + cinfo->density_unit = 0; + cinfo->X_density = 1; + cinfo->Y_density = 1; + cinfo->saw_Adobe_marker = FALSE; + cinfo->Adobe_transform = 0; + + cinfo->marker->saw_SOI = TRUE; + + return TRUE; +} + + +LOCAL(boolean) +get_sof (j_decompress_ptr cinfo, boolean is_prog, boolean is_arith) +/* Process a SOFn marker */ +{ + INT32 length; + int c, ci; + jpeg_component_info * compptr; + INPUT_VARS(cinfo); + + cinfo->progressive_mode = is_prog; + cinfo->arith_code = is_arith; + + INPUT_2BYTES(cinfo, length, return FALSE); + + INPUT_BYTE(cinfo, cinfo->data_precision, return FALSE); + INPUT_2BYTES(cinfo, cinfo->image_height, return FALSE); + INPUT_2BYTES(cinfo, cinfo->image_width, return FALSE); + INPUT_BYTE(cinfo, cinfo->num_components, return FALSE); + + length -= 8; + + TRACEMS4(cinfo, 1, JTRC_SOF, cinfo->unread_marker, + (int) cinfo->image_width, (int) cinfo->image_height, + cinfo->num_components); + + if (cinfo->marker->saw_SOF) + ERREXIT(cinfo, JERR_SOF_DUPLICATE); + + /* We don't support files in which the image height is initially specified */ + /* as 0 and is later redefined by DNL. As long as we have to check that, */ + /* might as well have a general sanity check. */ + if (cinfo->image_height <= 0 || cinfo->image_width <= 0 + || cinfo->num_components <= 0) + ERREXIT(cinfo, JERR_EMPTY_IMAGE); + + if (length != (cinfo->num_components * 3)) + ERREXIT(cinfo, JERR_BAD_LENGTH); + + if (cinfo->comp_info == NULL) /* do only once, even if suspend */ + cinfo->comp_info = (jpeg_component_info *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + cinfo->num_components * SIZEOF(jpeg_component_info)); + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + compptr->component_index = ci; + INPUT_BYTE(cinfo, compptr->component_id, return FALSE); + INPUT_BYTE(cinfo, c, return FALSE); + compptr->h_samp_factor = (c >> 4) & 15; + compptr->v_samp_factor = (c ) & 15; + INPUT_BYTE(cinfo, compptr->quant_tbl_no, return FALSE); + + TRACEMS4(cinfo, 1, JTRC_SOF_COMPONENT, + compptr->component_id, compptr->h_samp_factor, + compptr->v_samp_factor, compptr->quant_tbl_no); + } + + cinfo->marker->saw_SOF = TRUE; + + INPUT_SYNC(cinfo); + return TRUE; +} + + +LOCAL(boolean) +get_sos (j_decompress_ptr cinfo) +/* Process a SOS marker */ +{ + INT32 length; + int i, ci, n, c, cc; + jpeg_component_info * compptr; + INPUT_VARS(cinfo); + + if (! cinfo->marker->saw_SOF) + ERREXIT(cinfo, JERR_SOS_NO_SOF); + + INPUT_2BYTES(cinfo, length, return FALSE); + + INPUT_BYTE(cinfo, n, return FALSE); /* Number of components */ + + TRACEMS1(cinfo, 1, JTRC_SOS, n); + + if (length != (n * 2 + 6) || n < 1 || n > MAX_COMPS_IN_SCAN) + ERREXIT(cinfo, JERR_BAD_LENGTH); + + cinfo->comps_in_scan = n; + + /* Collect the component-spec parameters */ + + for (i = 0; i < n; i++) { + INPUT_BYTE(cinfo, cc, return FALSE); + INPUT_BYTE(cinfo, c, return FALSE); + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + if (cc == compptr->component_id) + goto id_found; + } + + ERREXIT1(cinfo, JERR_BAD_COMPONENT_ID, cc); + + id_found: + + cinfo->cur_comp_info[i] = compptr; + compptr->dc_tbl_no = (c >> 4) & 15; + compptr->ac_tbl_no = (c ) & 15; + + TRACEMS3(cinfo, 1, JTRC_SOS_COMPONENT, cc, + compptr->dc_tbl_no, compptr->ac_tbl_no); + } + + /* Collect the additional scan parameters Ss, Se, Ah/Al. */ + INPUT_BYTE(cinfo, c, return FALSE); + cinfo->Ss = c; + INPUT_BYTE(cinfo, c, return FALSE); + cinfo->Se = c; + INPUT_BYTE(cinfo, c, return FALSE); + cinfo->Ah = (c >> 4) & 15; + cinfo->Al = (c ) & 15; + + TRACEMS4(cinfo, 1, JTRC_SOS_PARAMS, cinfo->Ss, cinfo->Se, + cinfo->Ah, cinfo->Al); + + /* Prepare to scan data & restart markers */ + cinfo->marker->next_restart_num = 0; + + /* Count another SOS marker */ + cinfo->input_scan_number++; + + INPUT_SYNC(cinfo); + return TRUE; +} + + +#ifdef D_ARITH_CODING_SUPPORTED + +LOCAL(boolean) +get_dac (j_decompress_ptr cinfo) +/* Process a DAC marker */ +{ + INT32 length; + int index, val; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + + while (length > 0) { + INPUT_BYTE(cinfo, index, return FALSE); + INPUT_BYTE(cinfo, val, return FALSE); + + length -= 2; + + TRACEMS2(cinfo, 1, JTRC_DAC, index, val); + + if (index < 0 || index >= (2*NUM_ARITH_TBLS)) + ERREXIT1(cinfo, JERR_DAC_INDEX, index); + + if (index >= NUM_ARITH_TBLS) { /* define AC table */ + cinfo->arith_ac_K[index-NUM_ARITH_TBLS] = (UINT8) val; + } else { /* define DC table */ + cinfo->arith_dc_L[index] = (UINT8) (val & 0x0F); + cinfo->arith_dc_U[index] = (UINT8) (val >> 4); + if (cinfo->arith_dc_L[index] > cinfo->arith_dc_U[index]) + ERREXIT1(cinfo, JERR_DAC_VALUE, val); + } + } + + if (length != 0) + ERREXIT(cinfo, JERR_BAD_LENGTH); + + INPUT_SYNC(cinfo); + return TRUE; +} + +#else /* ! D_ARITH_CODING_SUPPORTED */ + +#define get_dac(cinfo) skip_variable(cinfo) + +#endif /* D_ARITH_CODING_SUPPORTED */ + + +LOCAL(boolean) +get_dht (j_decompress_ptr cinfo) +/* Process a DHT marker */ +{ + INT32 length; + UINT8 bits[17]; + UINT8 huffval[256]; + int i, index, count; + JHUFF_TBL **htblptr; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + + while (length > 16) { + INPUT_BYTE(cinfo, index, return FALSE); + + TRACEMS1(cinfo, 1, JTRC_DHT, index); + + bits[0] = 0; + count = 0; + for (i = 1; i <= 16; i++) { + INPUT_BYTE(cinfo, bits[i], return FALSE); + count += bits[i]; + } + + length -= 1 + 16; + + TRACEMS8(cinfo, 2, JTRC_HUFFBITS, + bits[1], bits[2], bits[3], bits[4], + bits[5], bits[6], bits[7], bits[8]); + TRACEMS8(cinfo, 2, JTRC_HUFFBITS, + bits[9], bits[10], bits[11], bits[12], + bits[13], bits[14], bits[15], bits[16]); + + /* Here we just do minimal validation of the counts to avoid walking + * off the end of our table space. jdhuff.c will check more carefully. + */ + if (count > 256 || ((INT32) count) > length) + ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); + + for (i = 0; i < count; i++) + INPUT_BYTE(cinfo, huffval[i], return FALSE); + + length -= count; + + if (index & 0x10) { /* AC table definition */ + index -= 0x10; + htblptr = &cinfo->ac_huff_tbl_ptrs[index]; + } else { /* DC table definition */ + htblptr = &cinfo->dc_huff_tbl_ptrs[index]; + } + + if (index < 0 || index >= NUM_HUFF_TBLS) + ERREXIT1(cinfo, JERR_DHT_INDEX, index); + + if (*htblptr == NULL) + *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo); + + MEMCOPY((*htblptr)->bits, bits, SIZEOF((*htblptr)->bits)); + MEMCOPY((*htblptr)->huffval, huffval, SIZEOF((*htblptr)->huffval)); + } + + if (length != 0) + ERREXIT(cinfo, JERR_BAD_LENGTH); + + INPUT_SYNC(cinfo); + return TRUE; +} + + +LOCAL(boolean) +get_dqt (j_decompress_ptr cinfo) +/* Process a DQT marker */ +{ + INT32 length; + int n, i, prec; + unsigned int tmp; + JQUANT_TBL *quant_ptr; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + + while (length > 0) { + INPUT_BYTE(cinfo, n, return FALSE); + prec = n >> 4; + n &= 0x0F; + + TRACEMS2(cinfo, 1, JTRC_DQT, n, prec); + + if (n >= NUM_QUANT_TBLS) + ERREXIT1(cinfo, JERR_DQT_INDEX, n); + + if (cinfo->quant_tbl_ptrs[n] == NULL) + cinfo->quant_tbl_ptrs[n] = jpeg_alloc_quant_table((j_common_ptr) cinfo); + quant_ptr = cinfo->quant_tbl_ptrs[n]; + + for (i = 0; i < DCTSIZE2; i++) { + if (prec) + INPUT_2BYTES(cinfo, tmp, return FALSE); + else + INPUT_BYTE(cinfo, tmp, return FALSE); + /* We convert the zigzag-order table to natural array order. */ + quant_ptr->quantval[jpeg_natural_order[i]] = (UINT16) tmp; + } + + if (cinfo->err->trace_level >= 2) { + for (i = 0; i < DCTSIZE2; i += 8) { + TRACEMS8(cinfo, 2, JTRC_QUANTVALS, + quant_ptr->quantval[i], quant_ptr->quantval[i+1], + quant_ptr->quantval[i+2], quant_ptr->quantval[i+3], + quant_ptr->quantval[i+4], quant_ptr->quantval[i+5], + quant_ptr->quantval[i+6], quant_ptr->quantval[i+7]); + } + } + + length -= DCTSIZE2+1; + if (prec) length -= DCTSIZE2; + } + + if (length != 0) + ERREXIT(cinfo, JERR_BAD_LENGTH); + + INPUT_SYNC(cinfo); + return TRUE; +} + + +LOCAL(boolean) +get_dri (j_decompress_ptr cinfo) +/* Process a DRI marker */ +{ + INT32 length; + unsigned int tmp; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + + if (length != 4) + ERREXIT(cinfo, JERR_BAD_LENGTH); + + INPUT_2BYTES(cinfo, tmp, return FALSE); + + TRACEMS1(cinfo, 1, JTRC_DRI, tmp); + + cinfo->restart_interval = tmp; + + INPUT_SYNC(cinfo); + return TRUE; +} + + +/* + * Routines for processing APPn and COM markers. + * These are either saved in memory or discarded, per application request. + * APP0 and APP14 are specially checked to see if they are + * JFIF and Adobe markers, respectively. + */ + +#define APP0_DATA_LEN 14 /* Length of interesting data in APP0 */ +#define APP14_DATA_LEN 12 /* Length of interesting data in APP14 */ +#define APPN_DATA_LEN 14 /* Must be the largest of the above!! */ + + +LOCAL(void) +examine_app0 (j_decompress_ptr cinfo, JOCTET FAR * data, + unsigned int datalen, INT32 remaining) +/* Examine first few bytes from an APP0. + * Take appropriate action if it is a JFIF marker. + * datalen is # of bytes at data[], remaining is length of rest of marker data. + */ +{ + INT32 totallen = (INT32) datalen + remaining; + + if (datalen >= APP0_DATA_LEN && + GETJOCTET(data[0]) == 0x4A && + GETJOCTET(data[1]) == 0x46 && + GETJOCTET(data[2]) == 0x49 && + GETJOCTET(data[3]) == 0x46 && + GETJOCTET(data[4]) == 0) { + /* Found JFIF APP0 marker: save info */ + cinfo->saw_JFIF_marker = TRUE; + cinfo->JFIF_major_version = GETJOCTET(data[5]); + cinfo->JFIF_minor_version = GETJOCTET(data[6]); + cinfo->density_unit = GETJOCTET(data[7]); + cinfo->X_density = (GETJOCTET(data[8]) << 8) + GETJOCTET(data[9]); + cinfo->Y_density = (GETJOCTET(data[10]) << 8) + GETJOCTET(data[11]); + /* Check version. + * Major version must be 1, anything else signals an incompatible change. + * (We used to treat this as an error, but now it's a nonfatal warning, + * because some bozo at Hijaak couldn't read the spec.) + * Minor version should be 0..2, but process anyway if newer. + */ + if (cinfo->JFIF_major_version != 1) + WARNMS2(cinfo, JWRN_JFIF_MAJOR, + cinfo->JFIF_major_version, cinfo->JFIF_minor_version); + /* Generate trace messages */ + TRACEMS5(cinfo, 1, JTRC_JFIF, + cinfo->JFIF_major_version, cinfo->JFIF_minor_version, + cinfo->X_density, cinfo->Y_density, cinfo->density_unit); + /* Validate thumbnail dimensions and issue appropriate messages */ + if (GETJOCTET(data[12]) | GETJOCTET(data[13])) + TRACEMS2(cinfo, 1, JTRC_JFIF_THUMBNAIL, + GETJOCTET(data[12]), GETJOCTET(data[13])); + totallen -= APP0_DATA_LEN; + if (totallen != + ((INT32)GETJOCTET(data[12]) * (INT32)GETJOCTET(data[13]) * (INT32) 3)) + TRACEMS1(cinfo, 1, JTRC_JFIF_BADTHUMBNAILSIZE, (int) totallen); + } else if (datalen >= 6 && + GETJOCTET(data[0]) == 0x4A && + GETJOCTET(data[1]) == 0x46 && + GETJOCTET(data[2]) == 0x58 && + GETJOCTET(data[3]) == 0x58 && + GETJOCTET(data[4]) == 0) { + /* Found JFIF "JFXX" extension APP0 marker */ + /* The library doesn't actually do anything with these, + * but we try to produce a helpful trace message. + */ + switch (GETJOCTET(data[5])) { + case 0x10: + TRACEMS1(cinfo, 1, JTRC_THUMB_JPEG, (int) totallen); + break; + case 0x11: + TRACEMS1(cinfo, 1, JTRC_THUMB_PALETTE, (int) totallen); + break; + case 0x13: + TRACEMS1(cinfo, 1, JTRC_THUMB_RGB, (int) totallen); + break; + default: + TRACEMS2(cinfo, 1, JTRC_JFIF_EXTENSION, + GETJOCTET(data[5]), (int) totallen); + break; + } + } else { + /* Start of APP0 does not match "JFIF" or "JFXX", or too short */ + TRACEMS1(cinfo, 1, JTRC_APP0, (int) totallen); + } +} + + +LOCAL(void) +examine_app14 (j_decompress_ptr cinfo, JOCTET FAR * data, + unsigned int datalen, INT32 remaining) +/* Examine first few bytes from an APP14. + * Take appropriate action if it is an Adobe marker. + * datalen is # of bytes at data[], remaining is length of rest of marker data. + */ +{ + unsigned int version, flags0, flags1, transform; + + if (datalen >= APP14_DATA_LEN && + GETJOCTET(data[0]) == 0x41 && + GETJOCTET(data[1]) == 0x64 && + GETJOCTET(data[2]) == 0x6F && + GETJOCTET(data[3]) == 0x62 && + GETJOCTET(data[4]) == 0x65) { + /* Found Adobe APP14 marker */ + version = (GETJOCTET(data[5]) << 8) + GETJOCTET(data[6]); + flags0 = (GETJOCTET(data[7]) << 8) + GETJOCTET(data[8]); + flags1 = (GETJOCTET(data[9]) << 8) + GETJOCTET(data[10]); + transform = GETJOCTET(data[11]); + TRACEMS4(cinfo, 1, JTRC_ADOBE, version, flags0, flags1, transform); + cinfo->saw_Adobe_marker = TRUE; + cinfo->Adobe_transform = (UINT8) transform; + } else { + /* Start of APP14 does not match "Adobe", or too short */ + TRACEMS1(cinfo, 1, JTRC_APP14, (int) (datalen + remaining)); + } +} + + +METHODDEF(boolean) +get_interesting_appn (j_decompress_ptr cinfo) +/* Process an APP0 or APP14 marker without saving it */ +{ + INT32 length; + JOCTET b[APPN_DATA_LEN]; + unsigned int i, numtoread; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + + /* get the interesting part of the marker data */ + if (length >= APPN_DATA_LEN) + numtoread = APPN_DATA_LEN; + else if (length > 0) + numtoread = (unsigned int) length; + else + numtoread = 0; + for (i = 0; i < numtoread; i++) + INPUT_BYTE(cinfo, b[i], return FALSE); + length -= numtoread; + + /* process it */ + switch (cinfo->unread_marker) { + case M_APP0: + examine_app0(cinfo, (JOCTET FAR *) b, numtoread, length); + break; + case M_APP14: + examine_app14(cinfo, (JOCTET FAR *) b, numtoread, length); + break; + default: + /* can't get here unless jpeg_save_markers chooses wrong processor */ + ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, cinfo->unread_marker); + break; + } + + /* skip any remaining data -- could be lots */ + INPUT_SYNC(cinfo); + if (length > 0) + (*cinfo->src->skip_input_data) (cinfo, (long) length); + + return TRUE; +} + + +#ifdef SAVE_MARKERS_SUPPORTED + +METHODDEF(boolean) +save_marker (j_decompress_ptr cinfo) +/* Save an APPn or COM marker into the marker list */ +{ + my_marker_ptr marker = (my_marker_ptr) cinfo->marker; + jpeg_saved_marker_ptr cur_marker = marker->cur_marker; + unsigned int bytes_read, data_length; + JOCTET FAR * data; + INT32 length = 0; + INPUT_VARS(cinfo); + + if (cur_marker == NULL) { + /* begin reading a marker */ + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + if (length >= 0) { /* watch out for bogus length word */ + /* figure out how much we want to save */ + unsigned int limit; + if (cinfo->unread_marker == (int) M_COM) + limit = marker->length_limit_COM; + else + limit = marker->length_limit_APPn[cinfo->unread_marker - (int) M_APP0]; + if ((unsigned int) length < limit) + limit = (unsigned int) length; + /* allocate and initialize the marker item */ + cur_marker = (jpeg_saved_marker_ptr) + (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(struct jpeg_marker_struct) + limit); + cur_marker->next = NULL; + cur_marker->marker = (UINT8) cinfo->unread_marker; + cur_marker->original_length = (unsigned int) length; + cur_marker->data_length = limit; + /* data area is just beyond the jpeg_marker_struct */ + data = cur_marker->data = (JOCTET FAR *) (cur_marker + 1); + marker->cur_marker = cur_marker; + marker->bytes_read = 0; + bytes_read = 0; + data_length = limit; + } else { + /* deal with bogus length word */ + bytes_read = data_length = 0; + data = NULL; + } + } else { + /* resume reading a marker */ + bytes_read = marker->bytes_read; + data_length = cur_marker->data_length; + data = cur_marker->data + bytes_read; + } + + while (bytes_read < data_length) { + INPUT_SYNC(cinfo); /* move the restart point to here */ + marker->bytes_read = bytes_read; + /* If there's not at least one byte in buffer, suspend */ + MAKE_BYTE_AVAIL(cinfo, return FALSE); + /* Copy bytes with reasonable rapidity */ + while (bytes_read < data_length && bytes_in_buffer > 0) { + *data++ = *next_input_byte++; + bytes_in_buffer--; + bytes_read++; + } + } + + /* Done reading what we want to read */ + if (cur_marker != NULL) { /* will be NULL if bogus length word */ + /* Add new marker to end of list */ + if (cinfo->marker_list == NULL) { + cinfo->marker_list = cur_marker; + } else { + jpeg_saved_marker_ptr prev = cinfo->marker_list; + while (prev->next != NULL) + prev = prev->next; + prev->next = cur_marker; + } + /* Reset pointer & calc remaining data length */ + data = cur_marker->data; + length = cur_marker->original_length - data_length; + } + /* Reset to initial state for next marker */ + marker->cur_marker = NULL; + + /* Process the marker if interesting; else just make a generic trace msg */ + switch (cinfo->unread_marker) { + case M_APP0: + examine_app0(cinfo, data, data_length, length); + break; + case M_APP14: + examine_app14(cinfo, data, data_length, length); + break; + default: + TRACEMS2(cinfo, 1, JTRC_MISC_MARKER, cinfo->unread_marker, + (int) (data_length + length)); + break; + } + + /* skip any remaining data -- could be lots */ + INPUT_SYNC(cinfo); /* do before skip_input_data */ + if (length > 0) + (*cinfo->src->skip_input_data) (cinfo, (long) length); + + return TRUE; +} + +#endif /* SAVE_MARKERS_SUPPORTED */ + + +METHODDEF(boolean) +skip_variable (j_decompress_ptr cinfo) +/* Skip over an unknown or uninteresting variable-length marker */ +{ + INT32 length; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + + TRACEMS2(cinfo, 1, JTRC_MISC_MARKER, cinfo->unread_marker, (int) length); + + INPUT_SYNC(cinfo); /* do before skip_input_data */ + if (length > 0) + (*cinfo->src->skip_input_data) (cinfo, (long) length); + + return TRUE; +} + + +/* + * Find the next JPEG marker, save it in cinfo->unread_marker. + * Returns FALSE if had to suspend before reaching a marker; + * in that case cinfo->unread_marker is unchanged. + * + * Note that the result might not be a valid marker code, + * but it will never be 0 or FF. + */ + +LOCAL(boolean) +next_marker (j_decompress_ptr cinfo) +{ + int c; + INPUT_VARS(cinfo); + + for (;;) { + INPUT_BYTE(cinfo, c, return FALSE); + /* Skip any non-FF bytes. + * This may look a bit inefficient, but it will not occur in a valid file. + * We sync after each discarded byte so that a suspending data source + * can discard the byte from its buffer. + */ + while (c != 0xFF) { + cinfo->marker->discarded_bytes++; + INPUT_SYNC(cinfo); + INPUT_BYTE(cinfo, c, return FALSE); + } + /* This loop swallows any duplicate FF bytes. Extra FFs are legal as + * pad bytes, so don't count them in discarded_bytes. We assume there + * will not be so many consecutive FF bytes as to overflow a suspending + * data source's input buffer. + */ + do { + INPUT_BYTE(cinfo, c, return FALSE); + } while (c == 0xFF); + if (c != 0) + break; /* found a valid marker, exit loop */ + /* Reach here if we found a stuffed-zero data sequence (FF/00). + * Discard it and loop back to try again. + */ + cinfo->marker->discarded_bytes += 2; + INPUT_SYNC(cinfo); + } + + if (cinfo->marker->discarded_bytes != 0) { + WARNMS2(cinfo, JWRN_EXTRANEOUS_DATA, cinfo->marker->discarded_bytes, c); + cinfo->marker->discarded_bytes = 0; + } + + cinfo->unread_marker = c; + + INPUT_SYNC(cinfo); + return TRUE; +} + + +LOCAL(boolean) +first_marker (j_decompress_ptr cinfo) +/* Like next_marker, but used to obtain the initial SOI marker. */ +/* For this marker, we do not allow preceding garbage or fill; otherwise, + * we might well scan an entire input file before realizing it ain't JPEG. + * If an application wants to process non-JFIF files, it must seek to the + * SOI before calling the JPEG library. + */ +{ + int c, c2; + INPUT_VARS(cinfo); + + INPUT_BYTE(cinfo, c, return FALSE); + INPUT_BYTE(cinfo, c2, return FALSE); + if (c != 0xFF || c2 != (int) M_SOI) + ERREXIT2(cinfo, JERR_NO_SOI, c, c2); + + cinfo->unread_marker = c2; + + INPUT_SYNC(cinfo); + return TRUE; +} + + +/* + * Read markers until SOS or EOI. + * + * Returns same codes as are defined for jpeg_consume_input: + * JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI. + */ + +METHODDEF(int) +read_markers (j_decompress_ptr cinfo) +{ + /* Outer loop repeats once for each marker. */ + for (;;) { + /* Collect the marker proper, unless we already did. */ + /* NB: first_marker() enforces the requirement that SOI appear first. */ + if (cinfo->unread_marker == 0) { + if (! cinfo->marker->saw_SOI) { + if (! first_marker(cinfo)) + return JPEG_SUSPENDED; + } else { + if (! next_marker(cinfo)) + return JPEG_SUSPENDED; + } + } + /* At this point cinfo->unread_marker contains the marker code and the + * input point is just past the marker proper, but before any parameters. + * A suspension will cause us to return with this state still true. + */ + switch (cinfo->unread_marker) { + case M_SOI: + if (! get_soi(cinfo)) + return JPEG_SUSPENDED; + break; + + case M_SOF0: /* Baseline */ + case M_SOF1: /* Extended sequential, Huffman */ + if (! get_sof(cinfo, FALSE, FALSE)) + return JPEG_SUSPENDED; + break; + + case M_SOF2: /* Progressive, Huffman */ + if (! get_sof(cinfo, TRUE, FALSE)) + return JPEG_SUSPENDED; + break; + + case M_SOF9: /* Extended sequential, arithmetic */ + if (! get_sof(cinfo, FALSE, TRUE)) + return JPEG_SUSPENDED; + break; + + case M_SOF10: /* Progressive, arithmetic */ + if (! get_sof(cinfo, TRUE, TRUE)) + return JPEG_SUSPENDED; + break; + + /* Currently unsupported SOFn types */ + case M_SOF3: /* Lossless, Huffman */ + case M_SOF5: /* Differential sequential, Huffman */ + case M_SOF6: /* Differential progressive, Huffman */ + case M_SOF7: /* Differential lossless, Huffman */ + case M_JPG: /* Reserved for JPEG extensions */ + case M_SOF11: /* Lossless, arithmetic */ + case M_SOF13: /* Differential sequential, arithmetic */ + case M_SOF14: /* Differential progressive, arithmetic */ + case M_SOF15: /* Differential lossless, arithmetic */ + ERREXIT1(cinfo, JERR_SOF_UNSUPPORTED, cinfo->unread_marker); + break; + + case M_SOS: + if (! get_sos(cinfo)) + return JPEG_SUSPENDED; + cinfo->unread_marker = 0; /* processed the marker */ + return JPEG_REACHED_SOS; + + case M_EOI: + TRACEMS(cinfo, 1, JTRC_EOI); + cinfo->unread_marker = 0; /* processed the marker */ + return JPEG_REACHED_EOI; + + case M_DAC: + if (! get_dac(cinfo)) + return JPEG_SUSPENDED; + break; + + case M_DHT: + if (! get_dht(cinfo)) + return JPEG_SUSPENDED; + break; + + case M_DQT: + if (! get_dqt(cinfo)) + return JPEG_SUSPENDED; + break; + + case M_DRI: + if (! get_dri(cinfo)) + return JPEG_SUSPENDED; + break; + + case M_APP0: + case M_APP1: + case M_APP2: + case M_APP3: + case M_APP4: + case M_APP5: + case M_APP6: + case M_APP7: + case M_APP8: + case M_APP9: + case M_APP10: + case M_APP11: + case M_APP12: + case M_APP13: + case M_APP14: + case M_APP15: + if (! (*((my_marker_ptr) cinfo->marker)->process_APPn[ + cinfo->unread_marker - (int) M_APP0]) (cinfo)) + return JPEG_SUSPENDED; + break; + + case M_COM: + if (! (*((my_marker_ptr) cinfo->marker)->process_COM) (cinfo)) + return JPEG_SUSPENDED; + break; + + case M_RST0: /* these are all parameterless */ + case M_RST1: + case M_RST2: + case M_RST3: + case M_RST4: + case M_RST5: + case M_RST6: + case M_RST7: + case M_TEM: + TRACEMS1(cinfo, 1, JTRC_PARMLESS_MARKER, cinfo->unread_marker); + break; + + case M_DNL: /* Ignore DNL ... perhaps the wrong thing */ + if (! skip_variable(cinfo)) + return JPEG_SUSPENDED; + break; + + default: /* must be DHP, EXP, JPGn, or RESn */ + /* For now, we treat the reserved markers as fatal errors since they are + * likely to be used to signal incompatible JPEG Part 3 extensions. + * Once the JPEG 3 version-number marker is well defined, this code + * ought to change! + */ + ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, cinfo->unread_marker); + break; + } + /* Successfully processed marker, so reset state variable */ + cinfo->unread_marker = 0; + } /* end loop */ +} + + +/* + * Read a restart marker, which is expected to appear next in the datastream; + * if the marker is not there, take appropriate recovery action. + * Returns FALSE if suspension is required. + * + * This is called by the entropy decoder after it has read an appropriate + * number of MCUs. cinfo->unread_marker may be nonzero if the entropy decoder + * has already read a marker from the data source. Under normal conditions + * cinfo->unread_marker will be reset to 0 before returning; if not reset, + * it holds a marker which the decoder will be unable to read past. + */ + +METHODDEF(boolean) +read_restart_marker (j_decompress_ptr cinfo) +{ + /* Obtain a marker unless we already did. */ + /* Note that next_marker will complain if it skips any data. */ + if (cinfo->unread_marker == 0) { + if (! next_marker(cinfo)) + return FALSE; + } + + if (cinfo->unread_marker == + ((int) M_RST0 + cinfo->marker->next_restart_num)) { + /* Normal case --- swallow the marker and let entropy decoder continue */ + TRACEMS1(cinfo, 3, JTRC_RST, cinfo->marker->next_restart_num); + cinfo->unread_marker = 0; + } else { + /* Uh-oh, the restart markers have been messed up. */ + /* Let the data source manager determine how to resync. */ + if (! (*cinfo->src->resync_to_restart) (cinfo, + cinfo->marker->next_restart_num)) + return FALSE; + } + + /* Update next-restart state */ + cinfo->marker->next_restart_num = (cinfo->marker->next_restart_num + 1) & 7; + + return TRUE; +} + + +/* + * This is the default resync_to_restart method for data source managers + * to use if they don't have any better approach. Some data source managers + * may be able to back up, or may have additional knowledge about the data + * which permits a more intelligent recovery strategy; such managers would + * presumably supply their own resync method. + * + * read_restart_marker calls resync_to_restart if it finds a marker other than + * the restart marker it was expecting. (This code is *not* used unless + * a nonzero restart interval has been declared.) cinfo->unread_marker is + * the marker code actually found (might be anything, except 0 or FF). + * The desired restart marker number (0..7) is passed as a parameter. + * This routine is supposed to apply whatever error recovery strategy seems + * appropriate in order to position the input stream to the next data segment. + * Note that cinfo->unread_marker is treated as a marker appearing before + * the current data-source input point; usually it should be reset to zero + * before returning. + * Returns FALSE if suspension is required. + * + * This implementation is substantially constrained by wanting to treat the + * input as a data stream; this means we can't back up. Therefore, we have + * only the following actions to work with: + * 1. Simply discard the marker and let the entropy decoder resume at next + * byte of file. + * 2. Read forward until we find another marker, discarding intervening + * data. (In theory we could look ahead within the current bufferload, + * without having to discard data if we don't find the desired marker. + * This idea is not implemented here, in part because it makes behavior + * dependent on buffer size and chance buffer-boundary positions.) + * 3. Leave the marker unread (by failing to zero cinfo->unread_marker). + * This will cause the entropy decoder to process an empty data segment, + * inserting dummy zeroes, and then we will reprocess the marker. + * + * #2 is appropriate if we think the desired marker lies ahead, while #3 is + * appropriate if the found marker is a future restart marker (indicating + * that we have missed the desired restart marker, probably because it got + * corrupted). + * We apply #2 or #3 if the found marker is a restart marker no more than + * two counts behind or ahead of the expected one. We also apply #2 if the + * found marker is not a legal JPEG marker code (it's certainly bogus data). + * If the found marker is a restart marker more than 2 counts away, we do #1 + * (too much risk that the marker is erroneous; with luck we will be able to + * resync at some future point). + * For any valid non-restart JPEG marker, we apply #3. This keeps us from + * overrunning the end of a scan. An implementation limited to single-scan + * files might find it better to apply #2 for markers other than EOI, since + * any other marker would have to be bogus data in that case. + */ + +GLOBAL(boolean) +jpeg_resync_to_restart (j_decompress_ptr cinfo, int desired) +{ + int marker = cinfo->unread_marker; + int action = 1; + + /* Always put up a warning. */ + WARNMS2(cinfo, JWRN_MUST_RESYNC, marker, desired); + + /* Outer loop handles repeated decision after scanning forward. */ + for (;;) { + if (marker < (int) M_SOF0) + action = 2; /* invalid marker */ + else if (marker < (int) M_RST0 || marker > (int) M_RST7) + action = 3; /* valid non-restart marker */ + else { + if (marker == ((int) M_RST0 + ((desired+1) & 7)) || + marker == ((int) M_RST0 + ((desired+2) & 7))) + action = 3; /* one of the next two expected restarts */ + else if (marker == ((int) M_RST0 + ((desired-1) & 7)) || + marker == ((int) M_RST0 + ((desired-2) & 7))) + action = 2; /* a prior restart, so advance */ + else + action = 1; /* desired restart or too far away */ + } + TRACEMS2(cinfo, 4, JTRC_RECOVERY_ACTION, marker, action); + switch (action) { + case 1: + /* Discard marker and let entropy decoder resume processing. */ + cinfo->unread_marker = 0; + return TRUE; + case 2: + /* Scan to the next marker, and repeat the decision loop. */ + if (! next_marker(cinfo)) + return FALSE; + marker = cinfo->unread_marker; + break; + case 3: + /* Return without advancing past this marker. */ + /* Entropy decoder will be forced to process an empty segment. */ + return TRUE; + } + } /* end loop */ +} + + +/* + * Reset marker processing state to begin a fresh datastream. + */ + +METHODDEF(void) +reset_marker_reader (j_decompress_ptr cinfo) +{ + my_marker_ptr marker = (my_marker_ptr) cinfo->marker; + + cinfo->comp_info = NULL; /* until allocated by get_sof */ + cinfo->input_scan_number = 0; /* no SOS seen yet */ + cinfo->unread_marker = 0; /* no pending marker */ + marker->pub.saw_SOI = FALSE; /* set internal state too */ + marker->pub.saw_SOF = FALSE; + marker->pub.discarded_bytes = 0; + marker->cur_marker = NULL; +} + + +/* + * Initialize the marker reader module. + * This is called only once, when the decompression object is created. + */ + +GLOBAL(void) +jinit_marker_reader (j_decompress_ptr cinfo) +{ + my_marker_ptr marker; + int i; + + /* Create subobject in permanent pool */ + marker = (my_marker_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + SIZEOF(my_marker_reader)); + cinfo->marker = (struct jpeg_marker_reader *) marker; + /* Initialize public method pointers */ + marker->pub.reset_marker_reader = reset_marker_reader; + marker->pub.read_markers = read_markers; + marker->pub.read_restart_marker = read_restart_marker; + /* Initialize COM/APPn processing. + * By default, we examine and then discard APP0 and APP14, + * but simply discard COM and all other APPn. + */ + marker->process_COM = skip_variable; + marker->length_limit_COM = 0; + for (i = 0; i < 16; i++) { + marker->process_APPn[i] = skip_variable; + marker->length_limit_APPn[i] = 0; + } + marker->process_APPn[0] = get_interesting_appn; + marker->process_APPn[14] = get_interesting_appn; + /* Reset marker processing state */ + reset_marker_reader(cinfo); +} + + +/* + * Control saving of COM and APPn markers into marker_list. + */ + +#ifdef SAVE_MARKERS_SUPPORTED + +GLOBAL(void) +jpeg_save_markers (j_decompress_ptr cinfo, int marker_code, + unsigned int length_limit) +{ + my_marker_ptr marker = (my_marker_ptr) cinfo->marker; + long maxlength; + jpeg_marker_parser_method processor; + + /* Length limit mustn't be larger than what we can allocate + * (should only be a concern in a 16-bit environment). + */ + maxlength = cinfo->mem->max_alloc_chunk - SIZEOF(struct jpeg_marker_struct); + if (((long) length_limit) > maxlength) + length_limit = (unsigned int) maxlength; + + /* Choose processor routine to use. + * APP0/APP14 have special requirements. + */ + if (length_limit) { + processor = save_marker; + /* If saving APP0/APP14, save at least enough for our internal use. */ + if (marker_code == (int) M_APP0 && length_limit < APP0_DATA_LEN) + length_limit = APP0_DATA_LEN; + else if (marker_code == (int) M_APP14 && length_limit < APP14_DATA_LEN) + length_limit = APP14_DATA_LEN; + } else { + processor = skip_variable; + /* If discarding APP0/APP14, use our regular on-the-fly processor. */ + if (marker_code == (int) M_APP0 || marker_code == (int) M_APP14) + processor = get_interesting_appn; + } + + if (marker_code == (int) M_COM) { + marker->process_COM = processor; + marker->length_limit_COM = length_limit; + } else if (marker_code >= (int) M_APP0 && marker_code <= (int) M_APP15) { + marker->process_APPn[marker_code - (int) M_APP0] = processor; + marker->length_limit_APPn[marker_code - (int) M_APP0] = length_limit; + } else + ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, marker_code); +} + +#endif /* SAVE_MARKERS_SUPPORTED */ + + +/* + * Install a special processing method for COM or APPn markers. + */ + +GLOBAL(void) +jpeg_set_marker_processor (j_decompress_ptr cinfo, int marker_code, + jpeg_marker_parser_method routine) +{ + my_marker_ptr marker = (my_marker_ptr) cinfo->marker; + + if (marker_code == (int) M_COM) + marker->process_COM = routine; + else if (marker_code >= (int) M_APP0 && marker_code <= (int) M_APP15) + marker->process_APPn[marker_code - (int) M_APP0] = routine; + else + ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, marker_code); +} diff --git a/mk4/modimage/jpeg-6b/jdmaster.c b/mk4/modimage/jpeg-6b/jdmaster.c new file mode 100644 index 0000000..2802c5b --- /dev/null +++ b/mk4/modimage/jpeg-6b/jdmaster.c @@ -0,0 +1,557 @@ +/* + * jdmaster.c + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains master control logic for the JPEG decompressor. + * These routines are concerned with selecting the modules to be executed + * and with determining the number of passes and the work to be done in each + * pass. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Private state */ + +typedef struct { + struct jpeg_decomp_master pub; /* public fields */ + + int pass_number; /* # of passes completed */ + + boolean using_merged_upsample; /* TRUE if using merged upsample/cconvert */ + + /* Saved references to initialized quantizer modules, + * in case we need to switch modes. + */ + struct jpeg_color_quantizer * quantizer_1pass; + struct jpeg_color_quantizer * quantizer_2pass; +} my_decomp_master; + +typedef my_decomp_master * my_master_ptr; + + +/* + * Determine whether merged upsample/color conversion should be used. + * CRUCIAL: this must match the actual capabilities of jdmerge.c! + */ + +LOCAL(boolean) +use_merged_upsample (j_decompress_ptr cinfo) +{ +#ifdef UPSAMPLE_MERGING_SUPPORTED + /* Merging is the equivalent of plain box-filter upsampling */ + if (cinfo->do_fancy_upsampling || cinfo->CCIR601_sampling) + return FALSE; + /* jdmerge.c only supports YCC=>RGB color conversion */ + if (cinfo->jpeg_color_space != JCS_YCbCr || cinfo->num_components != 3 || + cinfo->out_color_space != JCS_RGB || + cinfo->out_color_components != RGB_PIXELSIZE) + return FALSE; + /* and it only handles 2h1v or 2h2v sampling ratios */ + if (cinfo->comp_info[0].h_samp_factor != 2 || + cinfo->comp_info[1].h_samp_factor != 1 || + cinfo->comp_info[2].h_samp_factor != 1 || + cinfo->comp_info[0].v_samp_factor > 2 || + cinfo->comp_info[1].v_samp_factor != 1 || + cinfo->comp_info[2].v_samp_factor != 1) + return FALSE; + /* furthermore, it doesn't work if we've scaled the IDCTs differently */ + if (cinfo->comp_info[0].DCT_scaled_size != cinfo->min_DCT_scaled_size || + cinfo->comp_info[1].DCT_scaled_size != cinfo->min_DCT_scaled_size || + cinfo->comp_info[2].DCT_scaled_size != cinfo->min_DCT_scaled_size) + return FALSE; + /* ??? also need to test for upsample-time rescaling, when & if supported */ + return TRUE; /* by golly, it'll work... */ +#else + return FALSE; +#endif +} + + +/* + * Compute output image dimensions and related values. + * NOTE: this is exported for possible use by application. + * Hence it mustn't do anything that can't be done twice. + * Also note that it may be called before the master module is initialized! + */ + +GLOBAL(void) +jpeg_calc_output_dimensions (j_decompress_ptr cinfo) +/* Do computations that are needed before master selection phase */ +{ +#ifdef IDCT_SCALING_SUPPORTED + int ci; + jpeg_component_info *compptr; +#endif + + /* Prevent application from calling me at wrong times */ + if (cinfo->global_state != DSTATE_READY) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + +#ifdef IDCT_SCALING_SUPPORTED + + /* Compute actual output image dimensions and DCT scaling choices. */ + if (cinfo->scale_num * 8 <= cinfo->scale_denom) { + /* Provide 1/8 scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width, 8L); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height, 8L); + cinfo->min_DCT_scaled_size = 1; + } else if (cinfo->scale_num * 4 <= cinfo->scale_denom) { + /* Provide 1/4 scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width, 4L); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height, 4L); + cinfo->min_DCT_scaled_size = 2; + } else if (cinfo->scale_num * 2 <= cinfo->scale_denom) { + /* Provide 1/2 scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width, 2L); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height, 2L); + cinfo->min_DCT_scaled_size = 4; + } else { + /* Provide 1/1 scaling */ + cinfo->output_width = cinfo->image_width; + cinfo->output_height = cinfo->image_height; + cinfo->min_DCT_scaled_size = DCTSIZE; + } + /* In selecting the actual DCT scaling for each component, we try to + * scale up the chroma components via IDCT scaling rather than upsampling. + * This saves time if the upsampler gets to use 1:1 scaling. + * Note this code assumes that the supported DCT scalings are powers of 2. + */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + int ssize = cinfo->min_DCT_scaled_size; + while (ssize < DCTSIZE && + (compptr->h_samp_factor * ssize * 2 <= + cinfo->max_h_samp_factor * cinfo->min_DCT_scaled_size) && + (compptr->v_samp_factor * ssize * 2 <= + cinfo->max_v_samp_factor * cinfo->min_DCT_scaled_size)) { + ssize = ssize * 2; + } + compptr->DCT_scaled_size = ssize; + } + + /* Recompute downsampled dimensions of components; + * application needs to know these if using raw downsampled data. + */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Size in samples, after IDCT scaling */ + compptr->downsampled_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * + (long) (compptr->h_samp_factor * compptr->DCT_scaled_size), + (long) (cinfo->max_h_samp_factor * DCTSIZE)); + compptr->downsampled_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * + (long) (compptr->v_samp_factor * compptr->DCT_scaled_size), + (long) (cinfo->max_v_samp_factor * DCTSIZE)); + } + +#else /* !IDCT_SCALING_SUPPORTED */ + + /* Hardwire it to "no scaling" */ + cinfo->output_width = cinfo->image_width; + cinfo->output_height = cinfo->image_height; + /* jdinput.c has already initialized DCT_scaled_size to DCTSIZE, + * and has computed unscaled downsampled_width and downsampled_height. + */ + +#endif /* IDCT_SCALING_SUPPORTED */ + + /* Report number of components in selected colorspace. */ + /* Probably this should be in the color conversion module... */ + switch (cinfo->out_color_space) { + case JCS_GRAYSCALE: + cinfo->out_color_components = 1; + break; + case JCS_RGB: +#if RGB_PIXELSIZE != 3 + cinfo->out_color_components = RGB_PIXELSIZE; + break; +#endif /* else share code with YCbCr */ + case JCS_YCbCr: + cinfo->out_color_components = 3; + break; + case JCS_CMYK: + case JCS_YCCK: + cinfo->out_color_components = 4; + break; + default: /* else must be same colorspace as in file */ + cinfo->out_color_components = cinfo->num_components; + break; + } + cinfo->output_components = (cinfo->quantize_colors ? 1 : + cinfo->out_color_components); + + /* See if upsampler will want to emit more than one row at a time */ + if (use_merged_upsample(cinfo)) + cinfo->rec_outbuf_height = cinfo->max_v_samp_factor; + else + cinfo->rec_outbuf_height = 1; +} + + +/* + * Several decompression processes need to range-limit values to the range + * 0..MAXJSAMPLE; the input value may fall somewhat outside this range + * due to noise introduced by quantization, roundoff error, etc. These + * processes are inner loops and need to be as fast as possible. On most + * machines, particularly CPUs with pipelines or instruction prefetch, + * a (subscript-check-less) C table lookup + * x = sample_range_limit[x]; + * is faster than explicit tests + * if (x < 0) x = 0; + * else if (x > MAXJSAMPLE) x = MAXJSAMPLE; + * These processes all use a common table prepared by the routine below. + * + * For most steps we can mathematically guarantee that the initial value + * of x is within MAXJSAMPLE+1 of the legal range, so a table running from + * -(MAXJSAMPLE+1) to 2*MAXJSAMPLE+1 is sufficient. But for the initial + * limiting step (just after the IDCT), a wildly out-of-range value is + * possible if the input data is corrupt. To avoid any chance of indexing + * off the end of memory and getting a bad-pointer trap, we perform the + * post-IDCT limiting thus: + * x = range_limit[x & MASK]; + * where MASK is 2 bits wider than legal sample data, ie 10 bits for 8-bit + * samples. Under normal circumstances this is more than enough range and + * a correct output will be generated; with bogus input data the mask will + * cause wraparound, and we will safely generate a bogus-but-in-range output. + * For the post-IDCT step, we want to convert the data from signed to unsigned + * representation by adding CENTERJSAMPLE at the same time that we limit it. + * So the post-IDCT limiting table ends up looking like this: + * CENTERJSAMPLE,CENTERJSAMPLE+1,...,MAXJSAMPLE, + * MAXJSAMPLE (repeat 2*(MAXJSAMPLE+1)-CENTERJSAMPLE times), + * 0 (repeat 2*(MAXJSAMPLE+1)-CENTERJSAMPLE times), + * 0,1,...,CENTERJSAMPLE-1 + * Negative inputs select values from the upper half of the table after + * masking. + * + * We can save some space by overlapping the start of the post-IDCT table + * with the simpler range limiting table. The post-IDCT table begins at + * sample_range_limit + CENTERJSAMPLE. + * + * Note that the table is allocated in near data space on PCs; it's small + * enough and used often enough to justify this. + */ + +LOCAL(void) +prepare_range_limit_table (j_decompress_ptr cinfo) +/* Allocate and fill in the sample_range_limit table */ +{ + JSAMPLE * table; + int i; + + table = (JSAMPLE *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (5 * (MAXJSAMPLE+1) + CENTERJSAMPLE) * SIZEOF(JSAMPLE)); + table += (MAXJSAMPLE+1); /* allow negative subscripts of simple table */ + cinfo->sample_range_limit = table; + /* First segment of "simple" table: limit[x] = 0 for x < 0 */ + MEMZERO(table - (MAXJSAMPLE+1), (MAXJSAMPLE+1) * SIZEOF(JSAMPLE)); + /* Main part of "simple" table: limit[x] = x */ + for (i = 0; i <= MAXJSAMPLE; i++) + table[i] = (JSAMPLE) i; + table += CENTERJSAMPLE; /* Point to where post-IDCT table starts */ + /* End of simple table, rest of first half of post-IDCT table */ + for (i = CENTERJSAMPLE; i < 2*(MAXJSAMPLE+1); i++) + table[i] = MAXJSAMPLE; + /* Second half of post-IDCT table */ + MEMZERO(table + (2 * (MAXJSAMPLE+1)), + (2 * (MAXJSAMPLE+1) - CENTERJSAMPLE) * SIZEOF(JSAMPLE)); + MEMCOPY(table + (4 * (MAXJSAMPLE+1) - CENTERJSAMPLE), + cinfo->sample_range_limit, CENTERJSAMPLE * SIZEOF(JSAMPLE)); +} + + +/* + * Master selection of decompression modules. + * This is done once at jpeg_start_decompress time. We determine + * which modules will be used and give them appropriate initialization calls. + * We also initialize the decompressor input side to begin consuming data. + * + * Since jpeg_read_header has finished, we know what is in the SOF + * and (first) SOS markers. We also have all the application parameter + * settings. + */ + +LOCAL(void) +master_selection (j_decompress_ptr cinfo) +{ + my_master_ptr master = (my_master_ptr) cinfo->master; + boolean use_c_buffer; + long samplesperrow; + JDIMENSION jd_samplesperrow; + + /* Initialize dimensions and other stuff */ + jpeg_calc_output_dimensions(cinfo); + prepare_range_limit_table(cinfo); + + /* Width of an output scanline must be representable as JDIMENSION. */ + samplesperrow = (long) cinfo->output_width * (long) cinfo->out_color_components; + jd_samplesperrow = (JDIMENSION) samplesperrow; + if ((long) jd_samplesperrow != samplesperrow) + ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); + + /* Initialize my private state */ + master->pass_number = 0; + master->using_merged_upsample = use_merged_upsample(cinfo); + + /* Color quantizer selection */ + master->quantizer_1pass = NULL; + master->quantizer_2pass = NULL; + /* No mode changes if not using buffered-image mode. */ + if (! cinfo->quantize_colors || ! cinfo->buffered_image) { + cinfo->enable_1pass_quant = FALSE; + cinfo->enable_external_quant = FALSE; + cinfo->enable_2pass_quant = FALSE; + } + if (cinfo->quantize_colors) { + if (cinfo->raw_data_out) + ERREXIT(cinfo, JERR_NOTIMPL); + /* 2-pass quantizer only works in 3-component color space. */ + if (cinfo->out_color_components != 3) { + cinfo->enable_1pass_quant = TRUE; + cinfo->enable_external_quant = FALSE; + cinfo->enable_2pass_quant = FALSE; + cinfo->colormap = NULL; + } else if (cinfo->colormap != NULL) { + cinfo->enable_external_quant = TRUE; + } else if (cinfo->two_pass_quantize) { + cinfo->enable_2pass_quant = TRUE; + } else { + cinfo->enable_1pass_quant = TRUE; + } + + if (cinfo->enable_1pass_quant) { +#ifdef QUANT_1PASS_SUPPORTED + jinit_1pass_quantizer(cinfo); + master->quantizer_1pass = cinfo->cquantize; +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } + + /* We use the 2-pass code to map to external colormaps. */ + if (cinfo->enable_2pass_quant || cinfo->enable_external_quant) { +#ifdef QUANT_2PASS_SUPPORTED + jinit_2pass_quantizer(cinfo); + master->quantizer_2pass = cinfo->cquantize; +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } + /* If both quantizers are initialized, the 2-pass one is left active; + * this is necessary for starting with quantization to an external map. + */ + } + + /* Post-processing: in particular, color conversion first */ + if (! cinfo->raw_data_out) { + if (master->using_merged_upsample) { +#ifdef UPSAMPLE_MERGING_SUPPORTED + jinit_merged_upsampler(cinfo); /* does color conversion too */ +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else { + jinit_color_deconverter(cinfo); + jinit_upsampler(cinfo); + } + jinit_d_post_controller(cinfo, cinfo->enable_2pass_quant); + } + /* Inverse DCT */ + jinit_inverse_dct(cinfo); + /* Entropy decoding: either Huffman or arithmetic coding. */ + if (cinfo->arith_code) { + ERREXIT(cinfo, JERR_ARITH_NOTIMPL); + } else { + if (cinfo->progressive_mode) { +#ifdef D_PROGRESSIVE_SUPPORTED + jinit_phuff_decoder(cinfo); +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else + jinit_huff_decoder(cinfo); + } + + /* Initialize principal buffer controllers. */ + use_c_buffer = cinfo->inputctl->has_multiple_scans || cinfo->buffered_image; + jinit_d_coef_controller(cinfo, use_c_buffer); + + if (! cinfo->raw_data_out) + jinit_d_main_controller(cinfo, FALSE /* never need full buffer here */); + + /* We can now tell the memory manager to allocate virtual arrays. */ + (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo); + + /* Initialize input side of decompressor to consume first scan. */ + (*cinfo->inputctl->start_input_pass) (cinfo); + +#ifdef D_MULTISCAN_FILES_SUPPORTED + /* If jpeg_start_decompress will read the whole file, initialize + * progress monitoring appropriately. The input step is counted + * as one pass. + */ + if (cinfo->progress != NULL && ! cinfo->buffered_image && + cinfo->inputctl->has_multiple_scans) { + int nscans; + /* Estimate number of scans to set pass_limit. */ + if (cinfo->progressive_mode) { + /* Arbitrarily estimate 2 interleaved DC scans + 3 AC scans/component. */ + nscans = 2 + 3 * cinfo->num_components; + } else { + /* For a nonprogressive multiscan file, estimate 1 scan per component. */ + nscans = cinfo->num_components; + } + cinfo->progress->pass_counter = 0L; + cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows * nscans; + cinfo->progress->completed_passes = 0; + cinfo->progress->total_passes = (cinfo->enable_2pass_quant ? 3 : 2); + /* Count the input pass as done */ + master->pass_number++; + } +#endif /* D_MULTISCAN_FILES_SUPPORTED */ +} + + +/* + * Per-pass setup. + * This is called at the beginning of each output pass. We determine which + * modules will be active during this pass and give them appropriate + * start_pass calls. We also set is_dummy_pass to indicate whether this + * is a "real" output pass or a dummy pass for color quantization. + * (In the latter case, jdapistd.c will crank the pass to completion.) + */ + +METHODDEF(void) +prepare_for_output_pass (j_decompress_ptr cinfo) +{ + my_master_ptr master = (my_master_ptr) cinfo->master; + + if (master->pub.is_dummy_pass) { +#ifdef QUANT_2PASS_SUPPORTED + /* Final pass of 2-pass quantization */ + master->pub.is_dummy_pass = FALSE; + (*cinfo->cquantize->start_pass) (cinfo, FALSE); + (*cinfo->post->start_pass) (cinfo, JBUF_CRANK_DEST); + (*cinfo->main->start_pass) (cinfo, JBUF_CRANK_DEST); +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif /* QUANT_2PASS_SUPPORTED */ + } else { + if (cinfo->quantize_colors && cinfo->colormap == NULL) { + /* Select new quantization method */ + if (cinfo->two_pass_quantize && cinfo->enable_2pass_quant) { + cinfo->cquantize = master->quantizer_2pass; + master->pub.is_dummy_pass = TRUE; + } else if (cinfo->enable_1pass_quant) { + cinfo->cquantize = master->quantizer_1pass; + } else { + ERREXIT(cinfo, JERR_MODE_CHANGE); + } + } + (*cinfo->idct->start_pass) (cinfo); + (*cinfo->coef->start_output_pass) (cinfo); + if (! cinfo->raw_data_out) { + if (! master->using_merged_upsample) + (*cinfo->cconvert->start_pass) (cinfo); + (*cinfo->upsample->start_pass) (cinfo); + if (cinfo->quantize_colors) + (*cinfo->cquantize->start_pass) (cinfo, master->pub.is_dummy_pass); + (*cinfo->post->start_pass) (cinfo, + (master->pub.is_dummy_pass ? JBUF_SAVE_AND_PASS : JBUF_PASS_THRU)); + (*cinfo->main->start_pass) (cinfo, JBUF_PASS_THRU); + } + } + + /* Set up progress monitor's pass info if present */ + if (cinfo->progress != NULL) { + cinfo->progress->completed_passes = master->pass_number; + cinfo->progress->total_passes = master->pass_number + + (master->pub.is_dummy_pass ? 2 : 1); + /* In buffered-image mode, we assume one more output pass if EOI not + * yet reached, but no more passes if EOI has been reached. + */ + if (cinfo->buffered_image && ! cinfo->inputctl->eoi_reached) { + cinfo->progress->total_passes += (cinfo->enable_2pass_quant ? 2 : 1); + } + } +} + + +/* + * Finish up at end of an output pass. + */ + +METHODDEF(void) +finish_output_pass (j_decompress_ptr cinfo) +{ + my_master_ptr master = (my_master_ptr) cinfo->master; + + if (cinfo->quantize_colors) + (*cinfo->cquantize->finish_pass) (cinfo); + master->pass_number++; +} + + +#ifdef D_MULTISCAN_FILES_SUPPORTED + +/* + * Switch to a new external colormap between output passes. + */ + +GLOBAL(void) +jpeg_new_colormap (j_decompress_ptr cinfo) +{ + my_master_ptr master = (my_master_ptr) cinfo->master; + + /* Prevent application from calling me at wrong times */ + if (cinfo->global_state != DSTATE_BUFIMAGE) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + if (cinfo->quantize_colors && cinfo->enable_external_quant && + cinfo->colormap != NULL) { + /* Select 2-pass quantizer for external colormap use */ + cinfo->cquantize = master->quantizer_2pass; + /* Notify quantizer of colormap change */ + (*cinfo->cquantize->new_color_map) (cinfo); + master->pub.is_dummy_pass = FALSE; /* just in case */ + } else + ERREXIT(cinfo, JERR_MODE_CHANGE); +} + +#endif /* D_MULTISCAN_FILES_SUPPORTED */ + + +/* + * Initialize master decompression control and select active modules. + * This is performed at the start of jpeg_start_decompress. + */ + +GLOBAL(void) +jinit_master_decompress (j_decompress_ptr cinfo) +{ + my_master_ptr master; + + master = (my_master_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_decomp_master)); + cinfo->master = (struct jpeg_decomp_master *) master; + master->pub.prepare_for_output_pass = prepare_for_output_pass; + master->pub.finish_output_pass = finish_output_pass; + + master->pub.is_dummy_pass = FALSE; + + master_selection(cinfo); +} diff --git a/mk4/modimage/jpeg-6b/jdmerge.c b/mk4/modimage/jpeg-6b/jdmerge.c new file mode 100644 index 0000000..3744446 --- /dev/null +++ b/mk4/modimage/jpeg-6b/jdmerge.c @@ -0,0 +1,400 @@ +/* + * jdmerge.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains code for merged upsampling/color conversion. + * + * This file combines functions from jdsample.c and jdcolor.c; + * read those files first to understand what's going on. + * + * When the chroma components are to be upsampled by simple replication + * (ie, box filtering), we can save some work in color conversion by + * calculating all the output pixels corresponding to a pair of chroma + * samples at one time. In the conversion equations + * R = Y + K1 * Cr + * G = Y + K2 * Cb + K3 * Cr + * B = Y + K4 * Cb + * only the Y term varies among the group of pixels corresponding to a pair + * of chroma samples, so the rest of the terms can be calculated just once. + * At typical sampling ratios, this eliminates half or three-quarters of the + * multiplications needed for color conversion. + * + * This file currently provides implementations for the following cases: + * YCbCr => RGB color conversion only. + * Sampling ratios of 2h1v or 2h2v. + * No scaling needed at upsample time. + * Corner-aligned (non-CCIR601) sampling alignment. + * Other special cases could be added, but in most applications these are + * the only common cases. (For uncommon cases we fall back on the more + * general code in jdsample.c and jdcolor.c.) + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + +#ifdef UPSAMPLE_MERGING_SUPPORTED + + +/* Private subobject */ + +typedef struct { + struct jpeg_upsampler pub; /* public fields */ + + /* Pointer to routine to do actual upsampling/conversion of one row group */ + JMETHOD(void, upmethod, (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr, + JSAMPARRAY output_buf)); + + /* Private state for YCC->RGB conversion */ + int * Cr_r_tab; /* => table for Cr to R conversion */ + int * Cb_b_tab; /* => table for Cb to B conversion */ + INT32 * Cr_g_tab; /* => table for Cr to G conversion */ + INT32 * Cb_g_tab; /* => table for Cb to G conversion */ + + /* For 2:1 vertical sampling, we produce two output rows at a time. + * We need a "spare" row buffer to hold the second output row if the + * application provides just a one-row buffer; we also use the spare + * to discard the dummy last row if the image height is odd. + */ + JSAMPROW spare_row; + boolean spare_full; /* T if spare buffer is occupied */ + + JDIMENSION out_row_width; /* samples per output row */ + JDIMENSION rows_to_go; /* counts rows remaining in image */ +} my_upsampler; + +typedef my_upsampler * my_upsample_ptr; + +#define SCALEBITS 16 /* speediest right-shift on some machines */ +#define ONE_HALF ((INT32) 1 << (SCALEBITS-1)) +#define FIX(x) ((INT32) ((x) * (1L<RGB colorspace conversion. + * This is taken directly from jdcolor.c; see that file for more info. + */ + +LOCAL(void) +build_ycc_rgb_table (j_decompress_ptr cinfo) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + int i; + INT32 x; + SHIFT_TEMPS + + upsample->Cr_r_tab = (int *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (MAXJSAMPLE+1) * SIZEOF(int)); + upsample->Cb_b_tab = (int *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (MAXJSAMPLE+1) * SIZEOF(int)); + upsample->Cr_g_tab = (INT32 *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (MAXJSAMPLE+1) * SIZEOF(INT32)); + upsample->Cb_g_tab = (INT32 *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (MAXJSAMPLE+1) * SIZEOF(INT32)); + + for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) { + /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */ + /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */ + /* Cr=>R value is nearest int to 1.40200 * x */ + upsample->Cr_r_tab[i] = (int) + RIGHT_SHIFT(FIX(1.40200) * x + ONE_HALF, SCALEBITS); + /* Cb=>B value is nearest int to 1.77200 * x */ + upsample->Cb_b_tab[i] = (int) + RIGHT_SHIFT(FIX(1.77200) * x + ONE_HALF, SCALEBITS); + /* Cr=>G value is scaled-up -0.71414 * x */ + upsample->Cr_g_tab[i] = (- FIX(0.71414)) * x; + /* Cb=>G value is scaled-up -0.34414 * x */ + /* We also add in ONE_HALF so that need not do it in inner loop */ + upsample->Cb_g_tab[i] = (- FIX(0.34414)) * x + ONE_HALF; + } +} + + +/* + * Initialize for an upsampling pass. + */ + +METHODDEF(void) +start_pass_merged_upsample (j_decompress_ptr cinfo) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + + /* Mark the spare buffer empty */ + upsample->spare_full = FALSE; + /* Initialize total-height counter for detecting bottom of image */ + upsample->rows_to_go = cinfo->output_height; +} + + +/* + * Control routine to do upsampling (and color conversion). + * + * The control routine just handles the row buffering considerations. + */ + +METHODDEF(void) +merged_2v_upsample (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +/* 2:1 vertical sampling case: may need a spare row. */ +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + JSAMPROW work_ptrs[2]; + JDIMENSION num_rows; /* number of rows returned to caller */ + + if (upsample->spare_full) { + /* If we have a spare row saved from a previous cycle, just return it. */ + jcopy_sample_rows(& upsample->spare_row, 0, output_buf + *out_row_ctr, 0, + 1, upsample->out_row_width); + num_rows = 1; + upsample->spare_full = FALSE; + } else { + /* Figure number of rows to return to caller. */ + num_rows = 2; + /* Not more than the distance to the end of the image. */ + if (num_rows > upsample->rows_to_go) + num_rows = upsample->rows_to_go; + /* And not more than what the client can accept: */ + out_rows_avail -= *out_row_ctr; + if (num_rows > out_rows_avail) + num_rows = out_rows_avail; + /* Create output pointer array for upsampler. */ + work_ptrs[0] = output_buf[*out_row_ctr]; + if (num_rows > 1) { + work_ptrs[1] = output_buf[*out_row_ctr + 1]; + } else { + work_ptrs[1] = upsample->spare_row; + upsample->spare_full = TRUE; + } + /* Now do the upsampling. */ + (*upsample->upmethod) (cinfo, input_buf, *in_row_group_ctr, work_ptrs); + } + + /* Adjust counts */ + *out_row_ctr += num_rows; + upsample->rows_to_go -= num_rows; + /* When the buffer is emptied, declare this input row group consumed */ + if (! upsample->spare_full) + (*in_row_group_ctr)++; +} + + +METHODDEF(void) +merged_1v_upsample (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +/* 1:1 vertical sampling case: much easier, never need a spare row. */ +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + + /* Just do the upsampling. */ + (*upsample->upmethod) (cinfo, input_buf, *in_row_group_ctr, + output_buf + *out_row_ctr); + /* Adjust counts */ + (*out_row_ctr)++; + (*in_row_group_ctr)++; +} + + +/* + * These are the routines invoked by the control routines to do + * the actual upsampling/conversion. One row group is processed per call. + * + * Note: since we may be writing directly into application-supplied buffers, + * we have to be honest about the output width; we can't assume the buffer + * has been rounded up to an even width. + */ + + +/* + * Upsample and color convert for the case of 2:1 horizontal and 1:1 vertical. + */ + +METHODDEF(void) +h2v1_merged_upsample (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr, + JSAMPARRAY output_buf) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + register int y, cred, cgreen, cblue; + int cb, cr; + register JSAMPROW outptr; + JSAMPROW inptr0, inptr1, inptr2; + JDIMENSION col; + /* copy these pointers into registers if possible */ + register JSAMPLE * range_limit = cinfo->sample_range_limit; + int * Crrtab = upsample->Cr_r_tab; + int * Cbbtab = upsample->Cb_b_tab; + INT32 * Crgtab = upsample->Cr_g_tab; + INT32 * Cbgtab = upsample->Cb_g_tab; + SHIFT_TEMPS + + inptr0 = input_buf[0][in_row_group_ctr]; + inptr1 = input_buf[1][in_row_group_ctr]; + inptr2 = input_buf[2][in_row_group_ctr]; + outptr = output_buf[0]; + /* Loop for each pair of output pixels */ + for (col = cinfo->output_width >> 1; col > 0; col--) { + /* Do the chroma part of the calculation */ + cb = GETJSAMPLE(*inptr1++); + cr = GETJSAMPLE(*inptr2++); + cred = Crrtab[cr]; + cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS); + cblue = Cbbtab[cb]; + /* Fetch 2 Y values and emit 2 pixels */ + y = GETJSAMPLE(*inptr0++); + outptr[RGB_RED] = range_limit[y + cred]; + outptr[RGB_GREEN] = range_limit[y + cgreen]; + outptr[RGB_BLUE] = range_limit[y + cblue]; + outptr += RGB_PIXELSIZE; + y = GETJSAMPLE(*inptr0++); + outptr[RGB_RED] = range_limit[y + cred]; + outptr[RGB_GREEN] = range_limit[y + cgreen]; + outptr[RGB_BLUE] = range_limit[y + cblue]; + outptr += RGB_PIXELSIZE; + } + /* If image width is odd, do the last output column separately */ + if (cinfo->output_width & 1) { + cb = GETJSAMPLE(*inptr1); + cr = GETJSAMPLE(*inptr2); + cred = Crrtab[cr]; + cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS); + cblue = Cbbtab[cb]; + y = GETJSAMPLE(*inptr0); + outptr[RGB_RED] = range_limit[y + cred]; + outptr[RGB_GREEN] = range_limit[y + cgreen]; + outptr[RGB_BLUE] = range_limit[y + cblue]; + } +} + + +/* + * Upsample and color convert for the case of 2:1 horizontal and 2:1 vertical. + */ + +METHODDEF(void) +h2v2_merged_upsample (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr, + JSAMPARRAY output_buf) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + register int y, cred, cgreen, cblue; + int cb, cr; + register JSAMPROW outptr0, outptr1; + JSAMPROW inptr00, inptr01, inptr1, inptr2; + JDIMENSION col; + /* copy these pointers into registers if possible */ + register JSAMPLE * range_limit = cinfo->sample_range_limit; + int * Crrtab = upsample->Cr_r_tab; + int * Cbbtab = upsample->Cb_b_tab; + INT32 * Crgtab = upsample->Cr_g_tab; + INT32 * Cbgtab = upsample->Cb_g_tab; + SHIFT_TEMPS + + inptr00 = input_buf[0][in_row_group_ctr*2]; + inptr01 = input_buf[0][in_row_group_ctr*2 + 1]; + inptr1 = input_buf[1][in_row_group_ctr]; + inptr2 = input_buf[2][in_row_group_ctr]; + outptr0 = output_buf[0]; + outptr1 = output_buf[1]; + /* Loop for each group of output pixels */ + for (col = cinfo->output_width >> 1; col > 0; col--) { + /* Do the chroma part of the calculation */ + cb = GETJSAMPLE(*inptr1++); + cr = GETJSAMPLE(*inptr2++); + cred = Crrtab[cr]; + cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS); + cblue = Cbbtab[cb]; + /* Fetch 4 Y values and emit 4 pixels */ + y = GETJSAMPLE(*inptr00++); + outptr0[RGB_RED] = range_limit[y + cred]; + outptr0[RGB_GREEN] = range_limit[y + cgreen]; + outptr0[RGB_BLUE] = range_limit[y + cblue]; + outptr0 += RGB_PIXELSIZE; + y = GETJSAMPLE(*inptr00++); + outptr0[RGB_RED] = range_limit[y + cred]; + outptr0[RGB_GREEN] = range_limit[y + cgreen]; + outptr0[RGB_BLUE] = range_limit[y + cblue]; + outptr0 += RGB_PIXELSIZE; + y = GETJSAMPLE(*inptr01++); + outptr1[RGB_RED] = range_limit[y + cred]; + outptr1[RGB_GREEN] = range_limit[y + cgreen]; + outptr1[RGB_BLUE] = range_limit[y + cblue]; + outptr1 += RGB_PIXELSIZE; + y = GETJSAMPLE(*inptr01++); + outptr1[RGB_RED] = range_limit[y + cred]; + outptr1[RGB_GREEN] = range_limit[y + cgreen]; + outptr1[RGB_BLUE] = range_limit[y + cblue]; + outptr1 += RGB_PIXELSIZE; + } + /* If image width is odd, do the last output column separately */ + if (cinfo->output_width & 1) { + cb = GETJSAMPLE(*inptr1); + cr = GETJSAMPLE(*inptr2); + cred = Crrtab[cr]; + cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS); + cblue = Cbbtab[cb]; + y = GETJSAMPLE(*inptr00); + outptr0[RGB_RED] = range_limit[y + cred]; + outptr0[RGB_GREEN] = range_limit[y + cgreen]; + outptr0[RGB_BLUE] = range_limit[y + cblue]; + y = GETJSAMPLE(*inptr01); + outptr1[RGB_RED] = range_limit[y + cred]; + outptr1[RGB_GREEN] = range_limit[y + cgreen]; + outptr1[RGB_BLUE] = range_limit[y + cblue]; + } +} + + +/* + * Module initialization routine for merged upsampling/color conversion. + * + * NB: this is called under the conditions determined by use_merged_upsample() + * in jdmaster.c. That routine MUST correspond to the actual capabilities + * of this module; no safety checks are made here. + */ + +GLOBAL(void) +jinit_merged_upsampler (j_decompress_ptr cinfo) +{ + my_upsample_ptr upsample; + + upsample = (my_upsample_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_upsampler)); + cinfo->upsample = (struct jpeg_upsampler *) upsample; + upsample->pub.start_pass = start_pass_merged_upsample; + upsample->pub.need_context_rows = FALSE; + + upsample->out_row_width = cinfo->output_width * cinfo->out_color_components; + + if (cinfo->max_v_samp_factor == 2) { + upsample->pub.upsample = merged_2v_upsample; + upsample->upmethod = h2v2_merged_upsample; + /* Allocate a spare row buffer */ + upsample->spare_row = (JSAMPROW) + (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (size_t) (upsample->out_row_width * SIZEOF(JSAMPLE))); + } else { + upsample->pub.upsample = merged_1v_upsample; + upsample->upmethod = h2v1_merged_upsample; + /* No spare row needed */ + upsample->spare_row = NULL; + } + + build_ycc_rgb_table(cinfo); +} + +#endif /* UPSAMPLE_MERGING_SUPPORTED */ diff --git a/mk4/modimage/jpeg-6b/jdphuff.c b/mk4/modimage/jpeg-6b/jdphuff.c new file mode 100644 index 0000000..2267809 --- /dev/null +++ b/mk4/modimage/jpeg-6b/jdphuff.c @@ -0,0 +1,668 @@ +/* + * jdphuff.c + * + * Copyright (C) 1995-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains Huffman entropy decoding routines for progressive JPEG. + * + * Much of the complexity here has to do with supporting input suspension. + * If the data source module demands suspension, we want to be able to back + * up to the start of the current MCU. To do this, we copy state variables + * into local working storage, and update them back to the permanent + * storage only upon successful completion of an MCU. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdhuff.h" /* Declarations shared with jdhuff.c */ + + +#ifdef D_PROGRESSIVE_SUPPORTED + +/* + * Expanded entropy decoder object for progressive Huffman decoding. + * + * The savable_state subrecord contains fields that change within an MCU, + * but must not be updated permanently until we complete the MCU. + */ + +typedef struct { + unsigned int EOBRUN; /* remaining EOBs in EOBRUN */ + int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */ +} savable_state; + +/* This macro is to work around compilers with missing or broken + * structure assignment. You'll need to fix this code if you have + * such a compiler and you change MAX_COMPS_IN_SCAN. + */ + +#ifndef NO_STRUCT_ASSIGN +#define ASSIGN_STATE(dest,src) ((dest) = (src)) +#else +#if MAX_COMPS_IN_SCAN == 4 +#define ASSIGN_STATE(dest,src) \ + ((dest).EOBRUN = (src).EOBRUN, \ + (dest).last_dc_val[0] = (src).last_dc_val[0], \ + (dest).last_dc_val[1] = (src).last_dc_val[1], \ + (dest).last_dc_val[2] = (src).last_dc_val[2], \ + (dest).last_dc_val[3] = (src).last_dc_val[3]) +#endif +#endif + + +typedef struct { + struct jpeg_entropy_decoder pub; /* public fields */ + + /* These fields are loaded into local variables at start of each MCU. + * In case of suspension, we exit WITHOUT updating them. + */ + bitread_perm_state bitstate; /* Bit buffer at start of MCU */ + savable_state saved; /* Other state at start of MCU */ + + /* These fields are NOT loaded into local working state. */ + unsigned int restarts_to_go; /* MCUs left in this restart interval */ + + /* Pointers to derived tables (these workspaces have image lifespan) */ + d_derived_tbl * derived_tbls[NUM_HUFF_TBLS]; + + d_derived_tbl * ac_derived_tbl; /* active table during an AC scan */ +} phuff_entropy_decoder; + +typedef phuff_entropy_decoder * phuff_entropy_ptr; + +/* Forward declarations */ +METHODDEF(boolean) decode_mcu_DC_first JPP((j_decompress_ptr cinfo, + JBLOCKROW *MCU_data)); +METHODDEF(boolean) decode_mcu_AC_first JPP((j_decompress_ptr cinfo, + JBLOCKROW *MCU_data)); +METHODDEF(boolean) decode_mcu_DC_refine JPP((j_decompress_ptr cinfo, + JBLOCKROW *MCU_data)); +METHODDEF(boolean) decode_mcu_AC_refine JPP((j_decompress_ptr cinfo, + JBLOCKROW *MCU_data)); + + +/* + * Initialize for a Huffman-compressed scan. + */ + +METHODDEF(void) +start_pass_phuff_decoder (j_decompress_ptr cinfo) +{ + phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; + boolean is_DC_band, bad; + int ci, coefi, tbl; + int *coef_bit_ptr; + jpeg_component_info * compptr; + + is_DC_band = (cinfo->Ss == 0); + + /* Validate scan parameters */ + bad = FALSE; + if (is_DC_band) { + if (cinfo->Se != 0) + bad = TRUE; + } else { + /* need not check Ss/Se < 0 since they came from unsigned bytes */ + if (cinfo->Ss > cinfo->Se || cinfo->Se >= DCTSIZE2) + bad = TRUE; + /* AC scans may have only one component */ + if (cinfo->comps_in_scan != 1) + bad = TRUE; + } + if (cinfo->Ah != 0) { + /* Successive approximation refinement scan: must have Al = Ah-1. */ + if (cinfo->Al != cinfo->Ah-1) + bad = TRUE; + } + if (cinfo->Al > 13) /* need not check for < 0 */ + bad = TRUE; + /* Arguably the maximum Al value should be less than 13 for 8-bit precision, + * but the spec doesn't say so, and we try to be liberal about what we + * accept. Note: large Al values could result in out-of-range DC + * coefficients during early scans, leading to bizarre displays due to + * overflows in the IDCT math. But we won't crash. + */ + if (bad) + ERREXIT4(cinfo, JERR_BAD_PROGRESSION, + cinfo->Ss, cinfo->Se, cinfo->Ah, cinfo->Al); + /* Update progression status, and verify that scan order is legal. + * Note that inter-scan inconsistencies are treated as warnings + * not fatal errors ... not clear if this is right way to behave. + */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + int cindex = cinfo->cur_comp_info[ci]->component_index; + coef_bit_ptr = & cinfo->coef_bits[cindex][0]; + if (!is_DC_band && coef_bit_ptr[0] < 0) /* AC without prior DC scan */ + WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, 0); + for (coefi = cinfo->Ss; coefi <= cinfo->Se; coefi++) { + int expected = (coef_bit_ptr[coefi] < 0) ? 0 : coef_bit_ptr[coefi]; + if (cinfo->Ah != expected) + WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, coefi); + coef_bit_ptr[coefi] = cinfo->Al; + } + } + + /* Select MCU decoding routine */ + if (cinfo->Ah == 0) { + if (is_DC_band) + entropy->pub.decode_mcu = decode_mcu_DC_first; + else + entropy->pub.decode_mcu = decode_mcu_AC_first; + } else { + if (is_DC_band) + entropy->pub.decode_mcu = decode_mcu_DC_refine; + else + entropy->pub.decode_mcu = decode_mcu_AC_refine; + } + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* Make sure requested tables are present, and compute derived tables. + * We may build same derived table more than once, but it's not expensive. + */ + if (is_DC_band) { + if (cinfo->Ah == 0) { /* DC refinement needs no table */ + tbl = compptr->dc_tbl_no; + jpeg_make_d_derived_tbl(cinfo, TRUE, tbl, + & entropy->derived_tbls[tbl]); + } + } else { + tbl = compptr->ac_tbl_no; + jpeg_make_d_derived_tbl(cinfo, FALSE, tbl, + & entropy->derived_tbls[tbl]); + /* remember the single active table */ + entropy->ac_derived_tbl = entropy->derived_tbls[tbl]; + } + /* Initialize DC predictions to 0 */ + entropy->saved.last_dc_val[ci] = 0; + } + + /* Initialize bitread state variables */ + entropy->bitstate.bits_left = 0; + entropy->bitstate.get_buffer = 0; /* unnecessary, but keeps Purify quiet */ + entropy->pub.insufficient_data = FALSE; + + /* Initialize private state variables */ + entropy->saved.EOBRUN = 0; + + /* Initialize restart counter */ + entropy->restarts_to_go = cinfo->restart_interval; +} + + +/* + * Figure F.12: extend sign bit. + * On some machines, a shift and add will be faster than a table lookup. + */ + +#ifdef AVOID_TABLES + +#define HUFF_EXTEND(x,s) ((x) < (1<<((s)-1)) ? (x) + (((-1)<<(s)) + 1) : (x)) + +#else + +#define HUFF_EXTEND(x,s) ((x) < extend_test[s] ? (x) + extend_offset[s] : (x)) + +static const int extend_test[16] = /* entry n is 2**(n-1) */ + { 0, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, + 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000 }; + +static const int extend_offset[16] = /* entry n is (-1 << n) + 1 */ + { 0, ((-1)<<1) + 1, ((-1)<<2) + 1, ((-1)<<3) + 1, ((-1)<<4) + 1, + ((-1)<<5) + 1, ((-1)<<6) + 1, ((-1)<<7) + 1, ((-1)<<8) + 1, + ((-1)<<9) + 1, ((-1)<<10) + 1, ((-1)<<11) + 1, ((-1)<<12) + 1, + ((-1)<<13) + 1, ((-1)<<14) + 1, ((-1)<<15) + 1 }; + +#endif /* AVOID_TABLES */ + + +/* + * Check for a restart marker & resynchronize decoder. + * Returns FALSE if must suspend. + */ + +LOCAL(boolean) +process_restart (j_decompress_ptr cinfo) +{ + phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; + int ci; + + /* Throw away any unused bits remaining in bit buffer; */ + /* include any full bytes in next_marker's count of discarded bytes */ + cinfo->marker->discarded_bytes += entropy->bitstate.bits_left / 8; + entropy->bitstate.bits_left = 0; + + /* Advance past the RSTn marker */ + if (! (*cinfo->marker->read_restart_marker) (cinfo)) + return FALSE; + + /* Re-initialize DC predictions to 0 */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) + entropy->saved.last_dc_val[ci] = 0; + /* Re-init EOB run count, too */ + entropy->saved.EOBRUN = 0; + + /* Reset restart counter */ + entropy->restarts_to_go = cinfo->restart_interval; + + /* Reset out-of-data flag, unless read_restart_marker left us smack up + * against a marker. In that case we will end up treating the next data + * segment as empty, and we can avoid producing bogus output pixels by + * leaving the flag set. + */ + if (cinfo->unread_marker == 0) + entropy->pub.insufficient_data = FALSE; + + return TRUE; +} + + +/* + * Huffman MCU decoding. + * Each of these routines decodes and returns one MCU's worth of + * Huffman-compressed coefficients. + * The coefficients are reordered from zigzag order into natural array order, + * but are not dequantized. + * + * The i'th block of the MCU is stored into the block pointed to by + * MCU_data[i]. WE ASSUME THIS AREA IS INITIALLY ZEROED BY THE CALLER. + * + * We return FALSE if data source requested suspension. In that case no + * changes have been made to permanent state. (Exception: some output + * coefficients may already have been assigned. This is harmless for + * spectral selection, since we'll just re-assign them on the next call. + * Successive approximation AC refinement has to be more careful, however.) + */ + +/* + * MCU decoding for DC initial scan (either spectral selection, + * or first pass of successive approximation). + */ + +METHODDEF(boolean) +decode_mcu_DC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) +{ + phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; + int Al = cinfo->Al; + register int s, r; + int blkn, ci; + JBLOCKROW block; + BITREAD_STATE_VARS; + savable_state state; + d_derived_tbl * tbl; + jpeg_component_info * compptr; + + /* Process restart marker if needed; may have to suspend */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + if (! process_restart(cinfo)) + return FALSE; + } + + /* If we've run out of data, just leave the MCU set to zeroes. + * This way, we return uniform gray for the remainder of the segment. + */ + if (! entropy->pub.insufficient_data) { + + /* Load up working state */ + BITREAD_LOAD_STATE(cinfo,entropy->bitstate); + ASSIGN_STATE(state, entropy->saved); + + /* Outer loop handles each block in the MCU */ + + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + block = MCU_data[blkn]; + ci = cinfo->MCU_membership[blkn]; + compptr = cinfo->cur_comp_info[ci]; + tbl = entropy->derived_tbls[compptr->dc_tbl_no]; + + /* Decode a single block's worth of coefficients */ + + /* Section F.2.2.1: decode the DC coefficient difference */ + HUFF_DECODE(s, br_state, tbl, return FALSE, label1); + if (s) { + CHECK_BIT_BUFFER(br_state, s, return FALSE); + r = GET_BITS(s); + s = HUFF_EXTEND(r, s); + } + + /* Convert DC difference to actual value, update last_dc_val */ + s += state.last_dc_val[ci]; + state.last_dc_val[ci] = s; + /* Scale and output the coefficient (assumes jpeg_natural_order[0]=0) */ + (*block)[0] = (JCOEF) (s << Al); + } + + /* Completed MCU, so update state */ + BITREAD_SAVE_STATE(cinfo,entropy->bitstate); + ASSIGN_STATE(entropy->saved, state); + } + + /* Account for restart interval (no-op if not using restarts) */ + entropy->restarts_to_go--; + + return TRUE; +} + + +/* + * MCU decoding for AC initial scan (either spectral selection, + * or first pass of successive approximation). + */ + +METHODDEF(boolean) +decode_mcu_AC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) +{ + phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; + int Se = cinfo->Se; + int Al = cinfo->Al; + register int s, k, r; + unsigned int EOBRUN; + JBLOCKROW block; + BITREAD_STATE_VARS; + d_derived_tbl * tbl; + + /* Process restart marker if needed; may have to suspend */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + if (! process_restart(cinfo)) + return FALSE; + } + + /* If we've run out of data, just leave the MCU set to zeroes. + * This way, we return uniform gray for the remainder of the segment. + */ + if (! entropy->pub.insufficient_data) { + + /* Load up working state. + * We can avoid loading/saving bitread state if in an EOB run. + */ + EOBRUN = entropy->saved.EOBRUN; /* only part of saved state we need */ + + /* There is always only one block per MCU */ + + if (EOBRUN > 0) /* if it's a band of zeroes... */ + EOBRUN--; /* ...process it now (we do nothing) */ + else { + BITREAD_LOAD_STATE(cinfo,entropy->bitstate); + block = MCU_data[0]; + tbl = entropy->ac_derived_tbl; + + for (k = cinfo->Ss; k <= Se; k++) { + HUFF_DECODE(s, br_state, tbl, return FALSE, label2); + r = s >> 4; + s &= 15; + if (s) { + k += r; + CHECK_BIT_BUFFER(br_state, s, return FALSE); + r = GET_BITS(s); + s = HUFF_EXTEND(r, s); + /* Scale and output coefficient in natural (dezigzagged) order */ + (*block)[jpeg_natural_order[k]] = (JCOEF) (s << Al); + } else { + if (r == 15) { /* ZRL */ + k += 15; /* skip 15 zeroes in band */ + } else { /* EOBr, run length is 2^r + appended bits */ + EOBRUN = 1 << r; + if (r) { /* EOBr, r > 0 */ + CHECK_BIT_BUFFER(br_state, r, return FALSE); + r = GET_BITS(r); + EOBRUN += r; + } + EOBRUN--; /* this band is processed at this moment */ + break; /* force end-of-band */ + } + } + } + + BITREAD_SAVE_STATE(cinfo,entropy->bitstate); + } + + /* Completed MCU, so update state */ + entropy->saved.EOBRUN = EOBRUN; /* only part of saved state we need */ + } + + /* Account for restart interval (no-op if not using restarts) */ + entropy->restarts_to_go--; + + return TRUE; +} + + +/* + * MCU decoding for DC successive approximation refinement scan. + * Note: we assume such scans can be multi-component, although the spec + * is not very clear on the point. + */ + +METHODDEF(boolean) +decode_mcu_DC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) +{ + phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; + int p1 = 1 << cinfo->Al; /* 1 in the bit position being coded */ + int blkn; + JBLOCKROW block; + BITREAD_STATE_VARS; + + /* Process restart marker if needed; may have to suspend */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + if (! process_restart(cinfo)) + return FALSE; + } + + /* Not worth the cycles to check insufficient_data here, + * since we will not change the data anyway if we read zeroes. + */ + + /* Load up working state */ + BITREAD_LOAD_STATE(cinfo,entropy->bitstate); + + /* Outer loop handles each block in the MCU */ + + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + block = MCU_data[blkn]; + + /* Encoded data is simply the next bit of the two's-complement DC value */ + CHECK_BIT_BUFFER(br_state, 1, return FALSE); + if (GET_BITS(1)) + (*block)[0] |= p1; + /* Note: since we use |=, repeating the assignment later is safe */ + } + + /* Completed MCU, so update state */ + BITREAD_SAVE_STATE(cinfo,entropy->bitstate); + + /* Account for restart interval (no-op if not using restarts) */ + entropy->restarts_to_go--; + + return TRUE; +} + + +/* + * MCU decoding for AC successive approximation refinement scan. + */ + +METHODDEF(boolean) +decode_mcu_AC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) +{ + phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; + int Se = cinfo->Se; + int p1 = 1 << cinfo->Al; /* 1 in the bit position being coded */ + int m1 = (-1) << cinfo->Al; /* -1 in the bit position being coded */ + register int s, k, r; + unsigned int EOBRUN; + JBLOCKROW block; + JCOEFPTR thiscoef; + BITREAD_STATE_VARS; + d_derived_tbl * tbl; + int num_newnz; + int newnz_pos[DCTSIZE2]; + + /* Process restart marker if needed; may have to suspend */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + if (! process_restart(cinfo)) + return FALSE; + } + + /* If we've run out of data, don't modify the MCU. + */ + if (! entropy->pub.insufficient_data) { + + /* Load up working state */ + BITREAD_LOAD_STATE(cinfo,entropy->bitstate); + EOBRUN = entropy->saved.EOBRUN; /* only part of saved state we need */ + + /* There is always only one block per MCU */ + block = MCU_data[0]; + tbl = entropy->ac_derived_tbl; + + /* If we are forced to suspend, we must undo the assignments to any newly + * nonzero coefficients in the block, because otherwise we'd get confused + * next time about which coefficients were already nonzero. + * But we need not undo addition of bits to already-nonzero coefficients; + * instead, we can test the current bit to see if we already did it. + */ + num_newnz = 0; + + /* initialize coefficient loop counter to start of band */ + k = cinfo->Ss; + + if (EOBRUN == 0) { + for (; k <= Se; k++) { + HUFF_DECODE(s, br_state, tbl, goto undoit, label3); + r = s >> 4; + s &= 15; + if (s) { + if (s != 1) /* size of new coef should always be 1 */ + WARNMS(cinfo, JWRN_HUFF_BAD_CODE); + CHECK_BIT_BUFFER(br_state, 1, goto undoit); + if (GET_BITS(1)) + s = p1; /* newly nonzero coef is positive */ + else + s = m1; /* newly nonzero coef is negative */ + } else { + if (r != 15) { + EOBRUN = 1 << r; /* EOBr, run length is 2^r + appended bits */ + if (r) { + CHECK_BIT_BUFFER(br_state, r, goto undoit); + r = GET_BITS(r); + EOBRUN += r; + } + break; /* rest of block is handled by EOB logic */ + } + /* note s = 0 for processing ZRL */ + } + /* Advance over already-nonzero coefs and r still-zero coefs, + * appending correction bits to the nonzeroes. A correction bit is 1 + * if the absolute value of the coefficient must be increased. + */ + do { + thiscoef = *block + jpeg_natural_order[k]; + if (*thiscoef != 0) { + CHECK_BIT_BUFFER(br_state, 1, goto undoit); + if (GET_BITS(1)) { + if ((*thiscoef & p1) == 0) { /* do nothing if already set it */ + if (*thiscoef >= 0) + *thiscoef += p1; + else + *thiscoef += m1; + } + } + } else { + if (--r < 0) + break; /* reached target zero coefficient */ + } + k++; + } while (k <= Se); + if (s) { + int pos = jpeg_natural_order[k]; + /* Output newly nonzero coefficient */ + (*block)[pos] = (JCOEF) s; + /* Remember its position in case we have to suspend */ + newnz_pos[num_newnz++] = pos; + } + } + } + + if (EOBRUN > 0) { + /* Scan any remaining coefficient positions after the end-of-band + * (the last newly nonzero coefficient, if any). Append a correction + * bit to each already-nonzero coefficient. A correction bit is 1 + * if the absolute value of the coefficient must be increased. + */ + for (; k <= Se; k++) { + thiscoef = *block + jpeg_natural_order[k]; + if (*thiscoef != 0) { + CHECK_BIT_BUFFER(br_state, 1, goto undoit); + if (GET_BITS(1)) { + if ((*thiscoef & p1) == 0) { /* do nothing if already changed it */ + if (*thiscoef >= 0) + *thiscoef += p1; + else + *thiscoef += m1; + } + } + } + } + /* Count one block completed in EOB run */ + EOBRUN--; + } + + /* Completed MCU, so update state */ + BITREAD_SAVE_STATE(cinfo,entropy->bitstate); + entropy->saved.EOBRUN = EOBRUN; /* only part of saved state we need */ + } + + /* Account for restart interval (no-op if not using restarts) */ + entropy->restarts_to_go--; + + return TRUE; + +undoit: + /* Re-zero any output coefficients that we made newly nonzero */ + while (num_newnz > 0) + (*block)[newnz_pos[--num_newnz]] = 0; + + return FALSE; +} + + +/* + * Module initialization routine for progressive Huffman entropy decoding. + */ + +GLOBAL(void) +jinit_phuff_decoder (j_decompress_ptr cinfo) +{ + phuff_entropy_ptr entropy; + int *coef_bit_ptr; + int ci, i; + + entropy = (phuff_entropy_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(phuff_entropy_decoder)); + cinfo->entropy = (struct jpeg_entropy_decoder *) entropy; + entropy->pub.start_pass = start_pass_phuff_decoder; + + /* Mark derived tables unallocated */ + for (i = 0; i < NUM_HUFF_TBLS; i++) { + entropy->derived_tbls[i] = NULL; + } + + /* Create progression status table */ + cinfo->coef_bits = (int (*)[DCTSIZE2]) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + cinfo->num_components*DCTSIZE2*SIZEOF(int)); + coef_bit_ptr = & cinfo->coef_bits[0][0]; + for (ci = 0; ci < cinfo->num_components; ci++) + for (i = 0; i < DCTSIZE2; i++) + *coef_bit_ptr++ = -1; +} + +#endif /* D_PROGRESSIVE_SUPPORTED */ diff --git a/mk4/modimage/jpeg-6b/jdpostct.c b/mk4/modimage/jpeg-6b/jdpostct.c new file mode 100644 index 0000000..571563d --- /dev/null +++ b/mk4/modimage/jpeg-6b/jdpostct.c @@ -0,0 +1,290 @@ +/* + * jdpostct.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the decompression postprocessing controller. + * This controller manages the upsampling, color conversion, and color + * quantization/reduction steps; specifically, it controls the buffering + * between upsample/color conversion and color quantization/reduction. + * + * If no color quantization/reduction is required, then this module has no + * work to do, and it just hands off to the upsample/color conversion code. + * An integrated upsample/convert/quantize process would replace this module + * entirely. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Private buffer controller object */ + +typedef struct { + struct jpeg_d_post_controller pub; /* public fields */ + + /* Color quantization source buffer: this holds output data from + * the upsample/color conversion step to be passed to the quantizer. + * For two-pass color quantization, we need a full-image buffer; + * for one-pass operation, a strip buffer is sufficient. + */ + jvirt_sarray_ptr whole_image; /* virtual array, or NULL if one-pass */ + JSAMPARRAY buffer; /* strip buffer, or current strip of virtual */ + JDIMENSION strip_height; /* buffer size in rows */ + /* for two-pass mode only: */ + JDIMENSION starting_row; /* row # of first row in current strip */ + JDIMENSION next_row; /* index of next row to fill/empty in strip */ +} my_post_controller; + +typedef my_post_controller * my_post_ptr; + + +/* Forward declarations */ +METHODDEF(void) post_process_1pass + JPP((j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); +#ifdef QUANT_2PASS_SUPPORTED +METHODDEF(void) post_process_prepass + JPP((j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); +METHODDEF(void) post_process_2pass + JPP((j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); +#endif + + +/* + * Initialize for a processing pass. + */ + +METHODDEF(void) +start_pass_dpost (j_decompress_ptr cinfo, J_BUF_MODE pass_mode) +{ + my_post_ptr post = (my_post_ptr) cinfo->post; + + switch (pass_mode) { + case JBUF_PASS_THRU: + if (cinfo->quantize_colors) { + /* Single-pass processing with color quantization. */ + post->pub.post_process_data = post_process_1pass; + /* We could be doing buffered-image output before starting a 2-pass + * color quantization; in that case, jinit_d_post_controller did not + * allocate a strip buffer. Use the virtual-array buffer as workspace. + */ + if (post->buffer == NULL) { + post->buffer = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, post->whole_image, + (JDIMENSION) 0, post->strip_height, TRUE); + } + } else { + /* For single-pass processing without color quantization, + * I have no work to do; just call the upsampler directly. + */ + post->pub.post_process_data = cinfo->upsample->upsample; + } + break; +#ifdef QUANT_2PASS_SUPPORTED + case JBUF_SAVE_AND_PASS: + /* First pass of 2-pass quantization */ + if (post->whole_image == NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + post->pub.post_process_data = post_process_prepass; + break; + case JBUF_CRANK_DEST: + /* Second pass of 2-pass quantization */ + if (post->whole_image == NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + post->pub.post_process_data = post_process_2pass; + break; +#endif /* QUANT_2PASS_SUPPORTED */ + default: + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + break; + } + post->starting_row = post->next_row = 0; +} + + +/* + * Process some data in the one-pass (strip buffer) case. + * This is used for color precision reduction as well as one-pass quantization. + */ + +METHODDEF(void) +post_process_1pass (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +{ + my_post_ptr post = (my_post_ptr) cinfo->post; + JDIMENSION num_rows, max_rows; + + /* Fill the buffer, but not more than what we can dump out in one go. */ + /* Note we rely on the upsampler to detect bottom of image. */ + max_rows = out_rows_avail - *out_row_ctr; + if (max_rows > post->strip_height) + max_rows = post->strip_height; + num_rows = 0; + (*cinfo->upsample->upsample) (cinfo, + input_buf, in_row_group_ctr, in_row_groups_avail, + post->buffer, &num_rows, max_rows); + /* Quantize and emit data. */ + (*cinfo->cquantize->color_quantize) (cinfo, + post->buffer, output_buf + *out_row_ctr, (int) num_rows); + *out_row_ctr += num_rows; +} + + +#ifdef QUANT_2PASS_SUPPORTED + +/* + * Process some data in the first pass of 2-pass quantization. + */ + +METHODDEF(void) +post_process_prepass (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +{ + my_post_ptr post = (my_post_ptr) cinfo->post; + JDIMENSION old_next_row, num_rows; + + /* Reposition virtual buffer if at start of strip. */ + if (post->next_row == 0) { + post->buffer = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, post->whole_image, + post->starting_row, post->strip_height, TRUE); + } + + /* Upsample some data (up to a strip height's worth). */ + old_next_row = post->next_row; + (*cinfo->upsample->upsample) (cinfo, + input_buf, in_row_group_ctr, in_row_groups_avail, + post->buffer, &post->next_row, post->strip_height); + + /* Allow quantizer to scan new data. No data is emitted, */ + /* but we advance out_row_ctr so outer loop can tell when we're done. */ + if (post->next_row > old_next_row) { + num_rows = post->next_row - old_next_row; + (*cinfo->cquantize->color_quantize) (cinfo, post->buffer + old_next_row, + (JSAMPARRAY) NULL, (int) num_rows); + *out_row_ctr += num_rows; + } + + /* Advance if we filled the strip. */ + if (post->next_row >= post->strip_height) { + post->starting_row += post->strip_height; + post->next_row = 0; + } +} + + +/* + * Process some data in the second pass of 2-pass quantization. + */ + +METHODDEF(void) +post_process_2pass (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +{ + my_post_ptr post = (my_post_ptr) cinfo->post; + JDIMENSION num_rows, max_rows; + + /* Reposition virtual buffer if at start of strip. */ + if (post->next_row == 0) { + post->buffer = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, post->whole_image, + post->starting_row, post->strip_height, FALSE); + } + + /* Determine number of rows to emit. */ + num_rows = post->strip_height - post->next_row; /* available in strip */ + max_rows = out_rows_avail - *out_row_ctr; /* available in output area */ + if (num_rows > max_rows) + num_rows = max_rows; + /* We have to check bottom of image here, can't depend on upsampler. */ + max_rows = cinfo->output_height - post->starting_row; + if (num_rows > max_rows) + num_rows = max_rows; + + /* Quantize and emit data. */ + (*cinfo->cquantize->color_quantize) (cinfo, + post->buffer + post->next_row, output_buf + *out_row_ctr, + (int) num_rows); + *out_row_ctr += num_rows; + + /* Advance if we filled the strip. */ + post->next_row += num_rows; + if (post->next_row >= post->strip_height) { + post->starting_row += post->strip_height; + post->next_row = 0; + } +} + +#endif /* QUANT_2PASS_SUPPORTED */ + + +/* + * Initialize postprocessing controller. + */ + +GLOBAL(void) +jinit_d_post_controller (j_decompress_ptr cinfo, boolean need_full_buffer) +{ + my_post_ptr post; + + post = (my_post_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_post_controller)); + cinfo->post = (struct jpeg_d_post_controller *) post; + post->pub.start_pass = start_pass_dpost; + post->whole_image = NULL; /* flag for no virtual arrays */ + post->buffer = NULL; /* flag for no strip buffer */ + + /* Create the quantization buffer, if needed */ + if (cinfo->quantize_colors) { + /* The buffer strip height is max_v_samp_factor, which is typically + * an efficient number of rows for upsampling to return. + * (In the presence of output rescaling, we might want to be smarter?) + */ + post->strip_height = (JDIMENSION) cinfo->max_v_samp_factor; + if (need_full_buffer) { + /* Two-pass color quantization: need full-image storage. */ + /* We round up the number of rows to a multiple of the strip height. */ +#ifdef QUANT_2PASS_SUPPORTED + post->whole_image = (*cinfo->mem->request_virt_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, + cinfo->output_width * cinfo->out_color_components, + (JDIMENSION) jround_up((long) cinfo->output_height, + (long) post->strip_height), + post->strip_height); +#else + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); +#endif /* QUANT_2PASS_SUPPORTED */ + } else { + /* One-pass color quantization: just make a strip buffer. */ + post->buffer = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + cinfo->output_width * cinfo->out_color_components, + post->strip_height); + } + } +} diff --git a/mk4/modimage/jpeg-6b/jdsample.c b/mk4/modimage/jpeg-6b/jdsample.c new file mode 100644 index 0000000..80ffefb --- /dev/null +++ b/mk4/modimage/jpeg-6b/jdsample.c @@ -0,0 +1,478 @@ +/* + * jdsample.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains upsampling routines. + * + * Upsampling input data is counted in "row groups". A row group + * is defined to be (v_samp_factor * DCT_scaled_size / min_DCT_scaled_size) + * sample rows of each component. Upsampling will normally produce + * max_v_samp_factor pixel rows from each row group (but this could vary + * if the upsampler is applying a scale factor of its own). + * + * An excellent reference for image resampling is + * Digital Image Warping, George Wolberg, 1990. + * Pub. by IEEE Computer Society Press, Los Alamitos, CA. ISBN 0-8186-8944-7. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Pointer to routine to upsample a single component */ +typedef JMETHOD(void, upsample1_ptr, + (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)); + +/* Private subobject */ + +typedef struct { + struct jpeg_upsampler pub; /* public fields */ + + /* Color conversion buffer. When using separate upsampling and color + * conversion steps, this buffer holds one upsampled row group until it + * has been color converted and output. + * Note: we do not allocate any storage for component(s) which are full-size, + * ie do not need rescaling. The corresponding entry of color_buf[] is + * simply set to point to the input data array, thereby avoiding copying. + */ + JSAMPARRAY color_buf[MAX_COMPONENTS]; + + /* Per-component upsampling method pointers */ + upsample1_ptr methods[MAX_COMPONENTS]; + + int next_row_out; /* counts rows emitted from color_buf */ + JDIMENSION rows_to_go; /* counts rows remaining in image */ + + /* Height of an input row group for each component. */ + int rowgroup_height[MAX_COMPONENTS]; + + /* These arrays save pixel expansion factors so that int_expand need not + * recompute them each time. They are unused for other upsampling methods. + */ + UINT8 h_expand[MAX_COMPONENTS]; + UINT8 v_expand[MAX_COMPONENTS]; +} my_upsampler; + +typedef my_upsampler * my_upsample_ptr; + + +/* + * Initialize for an upsampling pass. + */ + +METHODDEF(void) +start_pass_upsample (j_decompress_ptr cinfo) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + + /* Mark the conversion buffer empty */ + upsample->next_row_out = cinfo->max_v_samp_factor; + /* Initialize total-height counter for detecting bottom of image */ + upsample->rows_to_go = cinfo->output_height; +} + + +/* + * Control routine to do upsampling (and color conversion). + * + * In this version we upsample each component independently. + * We upsample one row group into the conversion buffer, then apply + * color conversion a row at a time. + */ + +METHODDEF(void) +sep_upsample (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + int ci; + jpeg_component_info * compptr; + JDIMENSION num_rows; + + /* Fill the conversion buffer, if it's empty */ + if (upsample->next_row_out >= cinfo->max_v_samp_factor) { + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Invoke per-component upsample method. Notice we pass a POINTER + * to color_buf[ci], so that fullsize_upsample can change it. + */ + (*upsample->methods[ci]) (cinfo, compptr, + input_buf[ci] + (*in_row_group_ctr * upsample->rowgroup_height[ci]), + upsample->color_buf + ci); + } + upsample->next_row_out = 0; + } + + /* Color-convert and emit rows */ + + /* How many we have in the buffer: */ + num_rows = (JDIMENSION) (cinfo->max_v_samp_factor - upsample->next_row_out); + /* Not more than the distance to the end of the image. Need this test + * in case the image height is not a multiple of max_v_samp_factor: + */ + if (num_rows > upsample->rows_to_go) + num_rows = upsample->rows_to_go; + /* And not more than what the client can accept: */ + out_rows_avail -= *out_row_ctr; + if (num_rows > out_rows_avail) + num_rows = out_rows_avail; + + (*cinfo->cconvert->color_convert) (cinfo, upsample->color_buf, + (JDIMENSION) upsample->next_row_out, + output_buf + *out_row_ctr, + (int) num_rows); + + /* Adjust counts */ + *out_row_ctr += num_rows; + upsample->rows_to_go -= num_rows; + upsample->next_row_out += num_rows; + /* When the buffer is emptied, declare this input row group consumed */ + if (upsample->next_row_out >= cinfo->max_v_samp_factor) + (*in_row_group_ctr)++; +} + + +/* + * These are the routines invoked by sep_upsample to upsample pixel values + * of a single component. One row group is processed per call. + */ + + +/* + * For full-size components, we just make color_buf[ci] point at the + * input buffer, and thus avoid copying any data. Note that this is + * safe only because sep_upsample doesn't declare the input row group + * "consumed" until we are done color converting and emitting it. + */ + +METHODDEF(void) +fullsize_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) +{ + *output_data_ptr = input_data; +} + + +/* + * This is a no-op version used for "uninteresting" components. + * These components will not be referenced by color conversion. + */ + +METHODDEF(void) +noop_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) +{ + *output_data_ptr = NULL; /* safety check */ +} + + +/* + * This version handles any integral sampling ratios. + * This is not used for typical JPEG files, so it need not be fast. + * Nor, for that matter, is it particularly accurate: the algorithm is + * simple replication of the input pixel onto the corresponding output + * pixels. The hi-falutin sampling literature refers to this as a + * "box filter". A box filter tends to introduce visible artifacts, + * so if you are actually going to use 3:1 or 4:1 sampling ratios + * you would be well advised to improve this code. + */ + +METHODDEF(void) +int_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + JSAMPARRAY output_data = *output_data_ptr; + register JSAMPROW inptr, outptr; + register JSAMPLE invalue; + register int h; + JSAMPROW outend; + int h_expand, v_expand; + int inrow, outrow; + + h_expand = upsample->h_expand[compptr->component_index]; + v_expand = upsample->v_expand[compptr->component_index]; + + inrow = outrow = 0; + while (outrow < cinfo->max_v_samp_factor) { + /* Generate one output row with proper horizontal expansion */ + inptr = input_data[inrow]; + outptr = output_data[outrow]; + outend = outptr + cinfo->output_width; + while (outptr < outend) { + invalue = *inptr++; /* don't need GETJSAMPLE() here */ + for (h = h_expand; h > 0; h--) { + *outptr++ = invalue; + } + } + /* Generate any additional output rows by duplicating the first one */ + if (v_expand > 1) { + jcopy_sample_rows(output_data, outrow, output_data, outrow+1, + v_expand-1, cinfo->output_width); + } + inrow++; + outrow += v_expand; + } +} + + +/* + * Fast processing for the common case of 2:1 horizontal and 1:1 vertical. + * It's still a box filter. + */ + +METHODDEF(void) +h2v1_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) +{ + JSAMPARRAY output_data = *output_data_ptr; + register JSAMPROW inptr, outptr; + register JSAMPLE invalue; + JSAMPROW outend; + int inrow; + + for (inrow = 0; inrow < cinfo->max_v_samp_factor; inrow++) { + inptr = input_data[inrow]; + outptr = output_data[inrow]; + outend = outptr + cinfo->output_width; + while (outptr < outend) { + invalue = *inptr++; /* don't need GETJSAMPLE() here */ + *outptr++ = invalue; + *outptr++ = invalue; + } + } +} + + +/* + * Fast processing for the common case of 2:1 horizontal and 2:1 vertical. + * It's still a box filter. + */ + +METHODDEF(void) +h2v2_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) +{ + JSAMPARRAY output_data = *output_data_ptr; + register JSAMPROW inptr, outptr; + register JSAMPLE invalue; + JSAMPROW outend; + int inrow, outrow; + + inrow = outrow = 0; + while (outrow < cinfo->max_v_samp_factor) { + inptr = input_data[inrow]; + outptr = output_data[outrow]; + outend = outptr + cinfo->output_width; + while (outptr < outend) { + invalue = *inptr++; /* don't need GETJSAMPLE() here */ + *outptr++ = invalue; + *outptr++ = invalue; + } + jcopy_sample_rows(output_data, outrow, output_data, outrow+1, + 1, cinfo->output_width); + inrow++; + outrow += 2; + } +} + + +/* + * Fancy processing for the common case of 2:1 horizontal and 1:1 vertical. + * + * The upsampling algorithm is linear interpolation between pixel centers, + * also known as a "triangle filter". This is a good compromise between + * speed and visual quality. The centers of the output pixels are 1/4 and 3/4 + * of the way between input pixel centers. + * + * A note about the "bias" calculations: when rounding fractional values to + * integer, we do not want to always round 0.5 up to the next integer. + * If we did that, we'd introduce a noticeable bias towards larger values. + * Instead, this code is arranged so that 0.5 will be rounded up or down at + * alternate pixel locations (a simple ordered dither pattern). + */ + +METHODDEF(void) +h2v1_fancy_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) +{ + JSAMPARRAY output_data = *output_data_ptr; + register JSAMPROW inptr, outptr; + register int invalue; + register JDIMENSION colctr; + int inrow; + + for (inrow = 0; inrow < cinfo->max_v_samp_factor; inrow++) { + inptr = input_data[inrow]; + outptr = output_data[inrow]; + /* Special case for first column */ + invalue = GETJSAMPLE(*inptr++); + *outptr++ = (JSAMPLE) invalue; + *outptr++ = (JSAMPLE) ((invalue * 3 + GETJSAMPLE(*inptr) + 2) >> 2); + + for (colctr = compptr->downsampled_width - 2; colctr > 0; colctr--) { + /* General case: 3/4 * nearer pixel + 1/4 * further pixel */ + invalue = GETJSAMPLE(*inptr++) * 3; + *outptr++ = (JSAMPLE) ((invalue + GETJSAMPLE(inptr[-2]) + 1) >> 2); + *outptr++ = (JSAMPLE) ((invalue + GETJSAMPLE(*inptr) + 2) >> 2); + } + + /* Special case for last column */ + invalue = GETJSAMPLE(*inptr); + *outptr++ = (JSAMPLE) ((invalue * 3 + GETJSAMPLE(inptr[-1]) + 1) >> 2); + *outptr++ = (JSAMPLE) invalue; + } +} + + +/* + * Fancy processing for the common case of 2:1 horizontal and 2:1 vertical. + * Again a triangle filter; see comments for h2v1 case, above. + * + * It is OK for us to reference the adjacent input rows because we demanded + * context from the main buffer controller (see initialization code). + */ + +METHODDEF(void) +h2v2_fancy_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) +{ + JSAMPARRAY output_data = *output_data_ptr; + register JSAMPROW inptr0, inptr1, outptr; +#if BITS_IN_JSAMPLE == 8 + register int thiscolsum, lastcolsum, nextcolsum; +#else + register INT32 thiscolsum, lastcolsum, nextcolsum; +#endif + register JDIMENSION colctr; + int inrow, outrow, v; + + inrow = outrow = 0; + while (outrow < cinfo->max_v_samp_factor) { + for (v = 0; v < 2; v++) { + /* inptr0 points to nearest input row, inptr1 points to next nearest */ + inptr0 = input_data[inrow]; + if (v == 0) /* next nearest is row above */ + inptr1 = input_data[inrow-1]; + else /* next nearest is row below */ + inptr1 = input_data[inrow+1]; + outptr = output_data[outrow++]; + + /* Special case for first column */ + thiscolsum = GETJSAMPLE(*inptr0++) * 3 + GETJSAMPLE(*inptr1++); + nextcolsum = GETJSAMPLE(*inptr0++) * 3 + GETJSAMPLE(*inptr1++); + *outptr++ = (JSAMPLE) ((thiscolsum * 4 + 8) >> 4); + *outptr++ = (JSAMPLE) ((thiscolsum * 3 + nextcolsum + 7) >> 4); + lastcolsum = thiscolsum; thiscolsum = nextcolsum; + + for (colctr = compptr->downsampled_width - 2; colctr > 0; colctr--) { + /* General case: 3/4 * nearer pixel + 1/4 * further pixel in each */ + /* dimension, thus 9/16, 3/16, 3/16, 1/16 overall */ + nextcolsum = GETJSAMPLE(*inptr0++) * 3 + GETJSAMPLE(*inptr1++); + *outptr++ = (JSAMPLE) ((thiscolsum * 3 + lastcolsum + 8) >> 4); + *outptr++ = (JSAMPLE) ((thiscolsum * 3 + nextcolsum + 7) >> 4); + lastcolsum = thiscolsum; thiscolsum = nextcolsum; + } + + /* Special case for last column */ + *outptr++ = (JSAMPLE) ((thiscolsum * 3 + lastcolsum + 8) >> 4); + *outptr++ = (JSAMPLE) ((thiscolsum * 4 + 7) >> 4); + } + inrow++; + } +} + + +/* + * Module initialization routine for upsampling. + */ + +GLOBAL(void) +jinit_upsampler (j_decompress_ptr cinfo) +{ + my_upsample_ptr upsample; + int ci; + jpeg_component_info * compptr; + boolean need_buffer, do_fancy; + int h_in_group, v_in_group, h_out_group, v_out_group; + + upsample = (my_upsample_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_upsampler)); + cinfo->upsample = (struct jpeg_upsampler *) upsample; + upsample->pub.start_pass = start_pass_upsample; + upsample->pub.upsample = sep_upsample; + upsample->pub.need_context_rows = FALSE; /* until we find out differently */ + + if (cinfo->CCIR601_sampling) /* this isn't supported */ + ERREXIT(cinfo, JERR_CCIR601_NOTIMPL); + + /* jdmainct.c doesn't support context rows when min_DCT_scaled_size = 1, + * so don't ask for it. + */ + do_fancy = cinfo->do_fancy_upsampling && cinfo->min_DCT_scaled_size > 1; + + /* Verify we can handle the sampling factors, select per-component methods, + * and create storage as needed. + */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Compute size of an "input group" after IDCT scaling. This many samples + * are to be converted to max_h_samp_factor * max_v_samp_factor pixels. + */ + h_in_group = (compptr->h_samp_factor * compptr->DCT_scaled_size) / + cinfo->min_DCT_scaled_size; + v_in_group = (compptr->v_samp_factor * compptr->DCT_scaled_size) / + cinfo->min_DCT_scaled_size; + h_out_group = cinfo->max_h_samp_factor; + v_out_group = cinfo->max_v_samp_factor; + upsample->rowgroup_height[ci] = v_in_group; /* save for use later */ + need_buffer = TRUE; + if (! compptr->component_needed) { + /* Don't bother to upsample an uninteresting component. */ + upsample->methods[ci] = noop_upsample; + need_buffer = FALSE; + } else if (h_in_group == h_out_group && v_in_group == v_out_group) { + /* Fullsize components can be processed without any work. */ + upsample->methods[ci] = fullsize_upsample; + need_buffer = FALSE; + } else if (h_in_group * 2 == h_out_group && + v_in_group == v_out_group) { + /* Special cases for 2h1v upsampling */ + if (do_fancy && compptr->downsampled_width > 2) + upsample->methods[ci] = h2v1_fancy_upsample; + else + upsample->methods[ci] = h2v1_upsample; + } else if (h_in_group * 2 == h_out_group && + v_in_group * 2 == v_out_group) { + /* Special cases for 2h2v upsampling */ + if (do_fancy && compptr->downsampled_width > 2) { + upsample->methods[ci] = h2v2_fancy_upsample; + upsample->pub.need_context_rows = TRUE; + } else + upsample->methods[ci] = h2v2_upsample; + } else if ((h_out_group % h_in_group) == 0 && + (v_out_group % v_in_group) == 0) { + /* Generic integral-factors upsampling method */ + upsample->methods[ci] = int_upsample; + upsample->h_expand[ci] = (UINT8) (h_out_group / h_in_group); + upsample->v_expand[ci] = (UINT8) (v_out_group / v_in_group); + } else + ERREXIT(cinfo, JERR_FRACT_SAMPLE_NOTIMPL); + if (need_buffer) { + upsample->color_buf[ci] = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) jround_up((long) cinfo->output_width, + (long) cinfo->max_h_samp_factor), + (JDIMENSION) cinfo->max_v_samp_factor); + } + } +} diff --git a/mk4/modimage/jpeg-6b/jdtrans.c b/mk4/modimage/jpeg-6b/jdtrans.c new file mode 100644 index 0000000..6c0ab71 --- /dev/null +++ b/mk4/modimage/jpeg-6b/jdtrans.c @@ -0,0 +1,143 @@ +/* + * jdtrans.c + * + * Copyright (C) 1995-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains library routines for transcoding decompression, + * that is, reading raw DCT coefficient arrays from an input JPEG file. + * The routines in jdapimin.c will also be needed by a transcoder. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Forward declarations */ +LOCAL(void) transdecode_master_selection JPP((j_decompress_ptr cinfo)); + + +/* + * Read the coefficient arrays from a JPEG file. + * jpeg_read_header must be completed before calling this. + * + * The entire image is read into a set of virtual coefficient-block arrays, + * one per component. The return value is a pointer to the array of + * virtual-array descriptors. These can be manipulated directly via the + * JPEG memory manager, or handed off to jpeg_write_coefficients(). + * To release the memory occupied by the virtual arrays, call + * jpeg_finish_decompress() when done with the data. + * + * An alternative usage is to simply obtain access to the coefficient arrays + * during a buffered-image-mode decompression operation. This is allowed + * after any jpeg_finish_output() call. The arrays can be accessed until + * jpeg_finish_decompress() is called. (Note that any call to the library + * may reposition the arrays, so don't rely on access_virt_barray() results + * to stay valid across library calls.) + * + * Returns NULL if suspended. This case need be checked only if + * a suspending data source is used. + */ + +GLOBAL(jvirt_barray_ptr *) +jpeg_read_coefficients (j_decompress_ptr cinfo) +{ + if (cinfo->global_state == DSTATE_READY) { + /* First call: initialize active modules */ + transdecode_master_selection(cinfo); + cinfo->global_state = DSTATE_RDCOEFS; + } + if (cinfo->global_state == DSTATE_RDCOEFS) { + /* Absorb whole file into the coef buffer */ + for (;;) { + int retcode; + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + /* Absorb some more input */ + retcode = (*cinfo->inputctl->consume_input) (cinfo); + if (retcode == JPEG_SUSPENDED) + return NULL; + if (retcode == JPEG_REACHED_EOI) + break; + /* Advance progress counter if appropriate */ + if (cinfo->progress != NULL && + (retcode == JPEG_ROW_COMPLETED || retcode == JPEG_REACHED_SOS)) { + if (++cinfo->progress->pass_counter >= cinfo->progress->pass_limit) { + /* startup underestimated number of scans; ratchet up one scan */ + cinfo->progress->pass_limit += (long) cinfo->total_iMCU_rows; + } + } + } + /* Set state so that jpeg_finish_decompress does the right thing */ + cinfo->global_state = DSTATE_STOPPING; + } + /* At this point we should be in state DSTATE_STOPPING if being used + * standalone, or in state DSTATE_BUFIMAGE if being invoked to get access + * to the coefficients during a full buffered-image-mode decompression. + */ + if ((cinfo->global_state == DSTATE_STOPPING || + cinfo->global_state == DSTATE_BUFIMAGE) && cinfo->buffered_image) { + return cinfo->coef->coef_arrays; + } + /* Oops, improper usage */ + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + return NULL; /* keep compiler happy */ +} + + +/* + * Master selection of decompression modules for transcoding. + * This substitutes for jdmaster.c's initialization of the full decompressor. + */ + +LOCAL(void) +transdecode_master_selection (j_decompress_ptr cinfo) +{ + /* This is effectively a buffered-image operation. */ + cinfo->buffered_image = TRUE; + + /* Entropy decoding: either Huffman or arithmetic coding. */ + if (cinfo->arith_code) { + ERREXIT(cinfo, JERR_ARITH_NOTIMPL); + } else { + if (cinfo->progressive_mode) { +#ifdef D_PROGRESSIVE_SUPPORTED + jinit_phuff_decoder(cinfo); +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else + jinit_huff_decoder(cinfo); + } + + /* Always get a full-image coefficient buffer. */ + jinit_d_coef_controller(cinfo, TRUE); + + /* We can now tell the memory manager to allocate virtual arrays. */ + (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo); + + /* Initialize input side of decompressor to consume first scan. */ + (*cinfo->inputctl->start_input_pass) (cinfo); + + /* Initialize progress monitoring. */ + if (cinfo->progress != NULL) { + int nscans; + /* Estimate number of scans to set pass_limit. */ + if (cinfo->progressive_mode) { + /* Arbitrarily estimate 2 interleaved DC scans + 3 AC scans/component. */ + nscans = 2 + 3 * cinfo->num_components; + } else if (cinfo->inputctl->has_multiple_scans) { + /* For a nonprogressive multiscan file, estimate 1 scan per component. */ + nscans = cinfo->num_components; + } else { + nscans = 1; + } + cinfo->progress->pass_counter = 0L; + cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows * nscans; + cinfo->progress->completed_passes = 0; + cinfo->progress->total_passes = 1; + } +} diff --git a/mk4/modimage/jpeg-6b/jerror.c b/mk4/modimage/jpeg-6b/jerror.c new file mode 100644 index 0000000..3da7be8 --- /dev/null +++ b/mk4/modimage/jpeg-6b/jerror.c @@ -0,0 +1,252 @@ +/* + * jerror.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains simple error-reporting and trace-message routines. + * These are suitable for Unix-like systems and others where writing to + * stderr is the right thing to do. Many applications will want to replace + * some or all of these routines. + * + * If you define USE_WINDOWS_MESSAGEBOX in jconfig.h or in the makefile, + * you get a Windows-specific hack to display error messages in a dialog box. + * It ain't much, but it beats dropping error messages into the bit bucket, + * which is what happens to output to stderr under most Windows C compilers. + * + * These routines are used by both the compression and decompression code. + */ + +/* this is not a core library module, so it doesn't define JPEG_INTERNALS */ +#include "jinclude.h" +#include "jpeglib.h" +#include "jversion.h" +#include "jerror.h" + +#ifdef USE_WINDOWS_MESSAGEBOX +#include +#endif + +#ifndef EXIT_FAILURE /* define exit() codes if not provided */ +#define EXIT_FAILURE 1 +#endif + + +/* + * Create the message string table. + * We do this from the master message list in jerror.h by re-reading + * jerror.h with a suitable definition for macro JMESSAGE. + * The message table is made an external symbol just in case any applications + * want to refer to it directly. + */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_std_message_table jMsgTable +#endif + +#define JMESSAGE(code,string) string , + +const char * const jpeg_std_message_table[] = { +#include "jerror.h" + NULL +}; + + +/* + * Error exit handler: must not return to caller. + * + * Applications may override this if they want to get control back after + * an error. Typically one would longjmp somewhere instead of exiting. + * The setjmp buffer can be made a private field within an expanded error + * handler object. Note that the info needed to generate an error message + * is stored in the error object, so you can generate the message now or + * later, at your convenience. + * You should make sure that the JPEG object is cleaned up (with jpeg_abort + * or jpeg_destroy) at some point. + */ + +METHODDEF(void) +error_exit (j_common_ptr cinfo) +{ + /* Always display the message */ + (*cinfo->err->output_message) (cinfo); + + /* Let the memory manager delete any temp files before we die */ + jpeg_destroy(cinfo); + + exit(EXIT_FAILURE); +} + + +/* + * Actual output of an error or trace message. + * Applications may override this method to send JPEG messages somewhere + * other than stderr. + * + * On Windows, printing to stderr is generally completely useless, + * so we provide optional code to produce an error-dialog popup. + * Most Windows applications will still prefer to override this routine, + * but if they don't, it'll do something at least marginally useful. + * + * NOTE: to use the library in an environment that doesn't support the + * C stdio library, you may have to delete the call to fprintf() entirely, + * not just not use this routine. + */ + +METHODDEF(void) +output_message (j_common_ptr cinfo) +{ + char buffer[JMSG_LENGTH_MAX]; + + /* Create the message */ + (*cinfo->err->format_message) (cinfo, buffer); + +#ifdef USE_WINDOWS_MESSAGEBOX + /* Display it in a message dialog box */ + MessageBox(GetActiveWindow(), buffer, "JPEG Library Error", + MB_OK | MB_ICONERROR); +#else + /* Send it to stderr, adding a newline */ + fprintf(stderr, "%s\n", buffer); +#endif +} + + +/* + * Decide whether to emit a trace or warning message. + * msg_level is one of: + * -1: recoverable corrupt-data warning, may want to abort. + * 0: important advisory messages (always display to user). + * 1: first level of tracing detail. + * 2,3,...: successively more detailed tracing messages. + * An application might override this method if it wanted to abort on warnings + * or change the policy about which messages to display. + */ + +METHODDEF(void) +emit_message (j_common_ptr cinfo, int msg_level) +{ + struct jpeg_error_mgr * err = cinfo->err; + + if (msg_level < 0) { + /* It's a warning message. Since corrupt files may generate many warnings, + * the policy implemented here is to show only the first warning, + * unless trace_level >= 3. + */ + if (err->num_warnings == 0 || err->trace_level >= 3) + (*err->output_message) (cinfo); + /* Always count warnings in num_warnings. */ + err->num_warnings++; + } else { + /* It's a trace message. Show it if trace_level >= msg_level. */ + if (err->trace_level >= msg_level) + (*err->output_message) (cinfo); + } +} + + +/* + * Format a message string for the most recent JPEG error or message. + * The message is stored into buffer, which should be at least JMSG_LENGTH_MAX + * characters. Note that no '\n' character is added to the string. + * Few applications should need to override this method. + */ + +METHODDEF(void) +format_message (j_common_ptr cinfo, char * buffer) +{ + struct jpeg_error_mgr * err = cinfo->err; + int msg_code = err->msg_code; + const char * msgtext = NULL; + const char * msgptr; + char ch; + boolean isstring; + + /* Look up message string in proper table */ + if (msg_code > 0 && msg_code <= err->last_jpeg_message) { + msgtext = err->jpeg_message_table[msg_code]; + } else if (err->addon_message_table != NULL && + msg_code >= err->first_addon_message && + msg_code <= err->last_addon_message) { + msgtext = err->addon_message_table[msg_code - err->first_addon_message]; + } + + /* Defend against bogus message number */ + if (msgtext == NULL) { + err->msg_parm.i[0] = msg_code; + msgtext = err->jpeg_message_table[0]; + } + + /* Check for string parameter, as indicated by %s in the message text */ + isstring = FALSE; + msgptr = msgtext; + while ((ch = *msgptr++) != '\0') { + if (ch == '%') { + if (*msgptr == 's') isstring = TRUE; + break; + } + } + + /* Format the message into the passed buffer */ + if (isstring) + sprintf(buffer, msgtext, err->msg_parm.s); + else + sprintf(buffer, msgtext, + err->msg_parm.i[0], err->msg_parm.i[1], + err->msg_parm.i[2], err->msg_parm.i[3], + err->msg_parm.i[4], err->msg_parm.i[5], + err->msg_parm.i[6], err->msg_parm.i[7]); +} + + +/* + * Reset error state variables at start of a new image. + * This is called during compression startup to reset trace/error + * processing to default state, without losing any application-specific + * method pointers. An application might possibly want to override + * this method if it has additional error processing state. + */ + +METHODDEF(void) +reset_error_mgr (j_common_ptr cinfo) +{ + cinfo->err->num_warnings = 0; + /* trace_level is not reset since it is an application-supplied parameter */ + cinfo->err->msg_code = 0; /* may be useful as a flag for "no error" */ +} + + +/* + * Fill in the standard error-handling methods in a jpeg_error_mgr object. + * Typical call is: + * struct jpeg_compress_struct cinfo; + * struct jpeg_error_mgr err; + * + * cinfo.err = jpeg_std_error(&err); + * after which the application may override some of the methods. + */ + +GLOBAL(struct jpeg_error_mgr *) +jpeg_std_error (struct jpeg_error_mgr * err) +{ + err->error_exit = error_exit; + err->emit_message = emit_message; + err->output_message = output_message; + err->format_message = format_message; + err->reset_error_mgr = reset_error_mgr; + + err->trace_level = 0; /* default = no tracing */ + err->num_warnings = 0; /* no warnings emitted yet */ + err->msg_code = 0; /* may be useful as a flag for "no error" */ + + /* Initialize message table pointers */ + err->jpeg_message_table = jpeg_std_message_table; + err->last_jpeg_message = (int) JMSG_LASTMSGCODE - 1; + + err->addon_message_table = NULL; + err->first_addon_message = 0; /* for safety */ + err->last_addon_message = 0; + + return err; +} diff --git a/mk4/modimage/jpeg-6b/jerror.h b/mk4/modimage/jpeg-6b/jerror.h new file mode 100644 index 0000000..fc2fffe --- /dev/null +++ b/mk4/modimage/jpeg-6b/jerror.h @@ -0,0 +1,291 @@ +/* + * jerror.h + * + * Copyright (C) 1994-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file defines the error and message codes for the JPEG library. + * Edit this file to add new codes, or to translate the message strings to + * some other language. + * A set of error-reporting macros are defined too. Some applications using + * the JPEG library may wish to include this file to get the error codes + * and/or the macros. + */ + +/* + * To define the enum list of message codes, include this file without + * defining macro JMESSAGE. To create a message string table, include it + * again with a suitable JMESSAGE definition (see jerror.c for an example). + */ +#ifndef JMESSAGE +#ifndef JERROR_H +/* First time through, define the enum list */ +#define JMAKE_ENUM_LIST +#else +/* Repeated inclusions of this file are no-ops unless JMESSAGE is defined */ +#define JMESSAGE(code,string) +#endif /* JERROR_H */ +#endif /* JMESSAGE */ + +#ifdef JMAKE_ENUM_LIST + +typedef enum { + +#define JMESSAGE(code,string) code , + +#endif /* JMAKE_ENUM_LIST */ + +JMESSAGE(JMSG_NOMESSAGE, "Bogus message code %d") /* Must be first entry! */ + +/* For maintenance convenience, list is alphabetical by message code name */ +JMESSAGE(JERR_ARITH_NOTIMPL, + "Sorry, there are legal restrictions on arithmetic coding") +JMESSAGE(JERR_BAD_ALIGN_TYPE, "ALIGN_TYPE is wrong, please fix") +JMESSAGE(JERR_BAD_ALLOC_CHUNK, "MAX_ALLOC_CHUNK is wrong, please fix") +JMESSAGE(JERR_BAD_BUFFER_MODE, "Bogus buffer control mode") +JMESSAGE(JERR_BAD_COMPONENT_ID, "Invalid component ID %d in SOS") +JMESSAGE(JERR_BAD_DCT_COEF, "DCT coefficient out of range") +JMESSAGE(JERR_BAD_DCTSIZE, "IDCT output block size %d not supported") +JMESSAGE(JERR_BAD_HUFF_TABLE, "Bogus Huffman table definition") +JMESSAGE(JERR_BAD_IN_COLORSPACE, "Bogus input colorspace") +JMESSAGE(JERR_BAD_J_COLORSPACE, "Bogus JPEG colorspace") +JMESSAGE(JERR_BAD_LENGTH, "Bogus marker length") +JMESSAGE(JERR_BAD_LIB_VERSION, + "Wrong JPEG library version: library is %d, caller expects %d") +JMESSAGE(JERR_BAD_MCU_SIZE, "Sampling factors too large for interleaved scan") +JMESSAGE(JERR_BAD_POOL_ID, "Invalid memory pool code %d") +JMESSAGE(JERR_BAD_PRECISION, "Unsupported JPEG data precision %d") +JMESSAGE(JERR_BAD_PROGRESSION, + "Invalid progressive parameters Ss=%d Se=%d Ah=%d Al=%d") +JMESSAGE(JERR_BAD_PROG_SCRIPT, + "Invalid progressive parameters at scan script entry %d") +JMESSAGE(JERR_BAD_SAMPLING, "Bogus sampling factors") +JMESSAGE(JERR_BAD_SCAN_SCRIPT, "Invalid scan script at entry %d") +JMESSAGE(JERR_BAD_STATE, "Improper call to JPEG library in state %d") +JMESSAGE(JERR_BAD_STRUCT_SIZE, + "JPEG parameter struct mismatch: library thinks size is %u, caller expects %u") +JMESSAGE(JERR_BAD_VIRTUAL_ACCESS, "Bogus virtual array access") +JMESSAGE(JERR_BUFFER_SIZE, "Buffer passed to JPEG library is too small") +JMESSAGE(JERR_CANT_SUSPEND, "Suspension not allowed here") +JMESSAGE(JERR_CCIR601_NOTIMPL, "CCIR601 sampling not implemented yet") +JMESSAGE(JERR_COMPONENT_COUNT, "Too many color components: %d, max %d") +JMESSAGE(JERR_CONVERSION_NOTIMPL, "Unsupported color conversion request") +JMESSAGE(JERR_DAC_INDEX, "Bogus DAC index %d") +JMESSAGE(JERR_DAC_VALUE, "Bogus DAC value 0x%x") +JMESSAGE(JERR_DHT_INDEX, "Bogus DHT index %d") +JMESSAGE(JERR_DQT_INDEX, "Bogus DQT index %d") +JMESSAGE(JERR_EMPTY_IMAGE, "Empty JPEG image (DNL not supported)") +JMESSAGE(JERR_EMS_READ, "Read from EMS failed") +JMESSAGE(JERR_EMS_WRITE, "Write to EMS failed") +JMESSAGE(JERR_EOI_EXPECTED, "Didn't expect more than one scan") +JMESSAGE(JERR_FILE_READ, "Input file read error") +JMESSAGE(JERR_FILE_WRITE, "Output file write error --- out of disk space?") +JMESSAGE(JERR_FRACT_SAMPLE_NOTIMPL, "Fractional sampling not implemented yet") +JMESSAGE(JERR_HUFF_CLEN_OVERFLOW, "Huffman code size table overflow") +JMESSAGE(JERR_HUFF_MISSING_CODE, "Missing Huffman code table entry") +JMESSAGE(JERR_IMAGE_TOO_BIG, "Maximum supported image dimension is %u pixels") +JMESSAGE(JERR_INPUT_EMPTY, "Empty input file") +JMESSAGE(JERR_INPUT_EOF, "Premature end of input file") +JMESSAGE(JERR_MISMATCHED_QUANT_TABLE, + "Cannot transcode due to multiple use of quantization table %d") +JMESSAGE(JERR_MISSING_DATA, "Scan script does not transmit all data") +JMESSAGE(JERR_MODE_CHANGE, "Invalid color quantization mode change") +JMESSAGE(JERR_NOTIMPL, "Not implemented yet") +JMESSAGE(JERR_NOT_COMPILED, "Requested feature was omitted at compile time") +JMESSAGE(JERR_NO_BACKING_STORE, "Backing store not supported") +JMESSAGE(JERR_NO_HUFF_TABLE, "Huffman table 0x%02x was not defined") +JMESSAGE(JERR_NO_IMAGE, "JPEG datastream contains no image") +JMESSAGE(JERR_NO_QUANT_TABLE, "Quantization table 0x%02x was not defined") +JMESSAGE(JERR_NO_SOI, "Not a JPEG file: starts with 0x%02x 0x%02x") +JMESSAGE(JERR_OUT_OF_MEMORY, "Insufficient memory (case %d)") +JMESSAGE(JERR_QUANT_COMPONENTS, + "Cannot quantize more than %d color components") +JMESSAGE(JERR_QUANT_FEW_COLORS, "Cannot quantize to fewer than %d colors") +JMESSAGE(JERR_QUANT_MANY_COLORS, "Cannot quantize to more than %d colors") +JMESSAGE(JERR_SOF_DUPLICATE, "Invalid JPEG file structure: two SOF markers") +JMESSAGE(JERR_SOF_NO_SOS, "Invalid JPEG file structure: missing SOS marker") +JMESSAGE(JERR_SOF_UNSUPPORTED, "Unsupported JPEG process: SOF type 0x%02x") +JMESSAGE(JERR_SOI_DUPLICATE, "Invalid JPEG file structure: two SOI markers") +JMESSAGE(JERR_SOS_NO_SOF, "Invalid JPEG file structure: SOS before SOF") +JMESSAGE(JERR_TFILE_CREATE, "Failed to create temporary file %s") +JMESSAGE(JERR_TFILE_READ, "Read failed on temporary file") +JMESSAGE(JERR_TFILE_SEEK, "Seek failed on temporary file") +JMESSAGE(JERR_TFILE_WRITE, + "Write failed on temporary file --- out of disk space?") +JMESSAGE(JERR_TOO_LITTLE_DATA, "Application transferred too few scanlines") +JMESSAGE(JERR_UNKNOWN_MARKER, "Unsupported marker type 0x%02x") +JMESSAGE(JERR_VIRTUAL_BUG, "Virtual array controller messed up") +JMESSAGE(JERR_WIDTH_OVERFLOW, "Image too wide for this implementation") +JMESSAGE(JERR_XMS_READ, "Read from XMS failed") +JMESSAGE(JERR_XMS_WRITE, "Write to XMS failed") +JMESSAGE(JMSG_COPYRIGHT, JCOPYRIGHT) +JMESSAGE(JMSG_VERSION, JVERSION) +JMESSAGE(JTRC_16BIT_TABLES, + "Caution: quantization tables are too coarse for baseline JPEG") +JMESSAGE(JTRC_ADOBE, + "Adobe APP14 marker: version %d, flags 0x%04x 0x%04x, transform %d") +JMESSAGE(JTRC_APP0, "Unknown APP0 marker (not JFIF), length %u") +JMESSAGE(JTRC_APP14, "Unknown APP14 marker (not Adobe), length %u") +JMESSAGE(JTRC_DAC, "Define Arithmetic Table 0x%02x: 0x%02x") +JMESSAGE(JTRC_DHT, "Define Huffman Table 0x%02x") +JMESSAGE(JTRC_DQT, "Define Quantization Table %d precision %d") +JMESSAGE(JTRC_DRI, "Define Restart Interval %u") +JMESSAGE(JTRC_EMS_CLOSE, "Freed EMS handle %u") +JMESSAGE(JTRC_EMS_OPEN, "Obtained EMS handle %u") +JMESSAGE(JTRC_EOI, "End Of Image") +JMESSAGE(JTRC_HUFFBITS, " %3d %3d %3d %3d %3d %3d %3d %3d") +JMESSAGE(JTRC_JFIF, "JFIF APP0 marker: version %d.%02d, density %dx%d %d") +JMESSAGE(JTRC_JFIF_BADTHUMBNAILSIZE, + "Warning: thumbnail image size does not match data length %u") +JMESSAGE(JTRC_JFIF_EXTENSION, + "JFIF extension marker: type 0x%02x, length %u") +JMESSAGE(JTRC_JFIF_THUMBNAIL, " with %d x %d thumbnail image") +JMESSAGE(JTRC_MISC_MARKER, "Miscellaneous marker 0x%02x, length %u") +JMESSAGE(JTRC_PARMLESS_MARKER, "Unexpected marker 0x%02x") +JMESSAGE(JTRC_QUANTVALS, " %4u %4u %4u %4u %4u %4u %4u %4u") +JMESSAGE(JTRC_QUANT_3_NCOLORS, "Quantizing to %d = %d*%d*%d colors") +JMESSAGE(JTRC_QUANT_NCOLORS, "Quantizing to %d colors") +JMESSAGE(JTRC_QUANT_SELECTED, "Selected %d colors for quantization") +JMESSAGE(JTRC_RECOVERY_ACTION, "At marker 0x%02x, recovery action %d") +JMESSAGE(JTRC_RST, "RST%d") +JMESSAGE(JTRC_SMOOTH_NOTIMPL, + "Smoothing not supported with nonstandard sampling ratios") +JMESSAGE(JTRC_SOF, "Start Of Frame 0x%02x: width=%u, height=%u, components=%d") +JMESSAGE(JTRC_SOF_COMPONENT, " Component %d: %dhx%dv q=%d") +JMESSAGE(JTRC_SOI, "Start of Image") +JMESSAGE(JTRC_SOS, "Start Of Scan: %d components") +JMESSAGE(JTRC_SOS_COMPONENT, " Component %d: dc=%d ac=%d") +JMESSAGE(JTRC_SOS_PARAMS, " Ss=%d, Se=%d, Ah=%d, Al=%d") +JMESSAGE(JTRC_TFILE_CLOSE, "Closed temporary file %s") +JMESSAGE(JTRC_TFILE_OPEN, "Opened temporary file %s") +JMESSAGE(JTRC_THUMB_JPEG, + "JFIF extension marker: JPEG-compressed thumbnail image, length %u") +JMESSAGE(JTRC_THUMB_PALETTE, + "JFIF extension marker: palette thumbnail image, length %u") +JMESSAGE(JTRC_THUMB_RGB, + "JFIF extension marker: RGB thumbnail image, length %u") +JMESSAGE(JTRC_UNKNOWN_IDS, + "Unrecognized component IDs %d %d %d, assuming YCbCr") +JMESSAGE(JTRC_XMS_CLOSE, "Freed XMS handle %u") +JMESSAGE(JTRC_XMS_OPEN, "Obtained XMS handle %u") +JMESSAGE(JWRN_ADOBE_XFORM, "Unknown Adobe color transform code %d") +JMESSAGE(JWRN_BOGUS_PROGRESSION, + "Inconsistent progression sequence for component %d coefficient %d") +JMESSAGE(JWRN_EXTRANEOUS_DATA, + "Corrupt JPEG data: %u extraneous bytes before marker 0x%02x") +JMESSAGE(JWRN_HIT_MARKER, "Corrupt JPEG data: premature end of data segment") +JMESSAGE(JWRN_HUFF_BAD_CODE, "Corrupt JPEG data: bad Huffman code") +JMESSAGE(JWRN_JFIF_MAJOR, "Warning: unknown JFIF revision number %d.%02d") +JMESSAGE(JWRN_JPEG_EOF, "Premature end of JPEG file") +JMESSAGE(JWRN_MUST_RESYNC, + "Corrupt JPEG data: found marker 0x%02x instead of RST%d") +JMESSAGE(JWRN_NOT_SEQUENTIAL, "Invalid SOS parameters for sequential JPEG") +JMESSAGE(JWRN_TOO_MUCH_DATA, "Application transferred too many scanlines") + +#ifdef JMAKE_ENUM_LIST + + JMSG_LASTMSGCODE +} J_MESSAGE_CODE; + +#undef JMAKE_ENUM_LIST +#endif /* JMAKE_ENUM_LIST */ + +/* Zap JMESSAGE macro so that future re-inclusions do nothing by default */ +#undef JMESSAGE + + +#ifndef JERROR_H +#define JERROR_H + +/* Macros to simplify using the error and trace message stuff */ +/* The first parameter is either type of cinfo pointer */ + +/* Fatal errors (print message and exit) */ +#define ERREXIT(cinfo,code) \ + ((cinfo)->err->msg_code = (code), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT1(cinfo,code,p1) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT2(cinfo,code,p1,p2) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT3(cinfo,code,p1,p2,p3) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (cinfo)->err->msg_parm.i[2] = (p3), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT4(cinfo,code,p1,p2,p3,p4) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (cinfo)->err->msg_parm.i[2] = (p3), \ + (cinfo)->err->msg_parm.i[3] = (p4), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXITS(cinfo,code,str) \ + ((cinfo)->err->msg_code = (code), \ + strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) + +#define MAKESTMT(stuff) do { stuff } while (0) + +/* Nonfatal errors (we can keep going, but the data is probably corrupt) */ +#define WARNMS(cinfo,code) \ + ((cinfo)->err->msg_code = (code), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1)) +#define WARNMS1(cinfo,code,p1) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1)) +#define WARNMS2(cinfo,code,p1,p2) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1)) + +/* Informational/debugging messages */ +#define TRACEMS(cinfo,lvl,code) \ + ((cinfo)->err->msg_code = (code), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) +#define TRACEMS1(cinfo,lvl,code,p1) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) +#define TRACEMS2(cinfo,lvl,code,p1,p2) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) +#define TRACEMS3(cinfo,lvl,code,p1,p2,p3) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMS4(cinfo,lvl,code,p1,p2,p3,p4) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMS5(cinfo,lvl,code,p1,p2,p3,p4,p5) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \ + _mp[4] = (p5); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMS8(cinfo,lvl,code,p1,p2,p3,p4,p5,p6,p7,p8) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \ + _mp[4] = (p5); _mp[5] = (p6); _mp[6] = (p7); _mp[7] = (p8); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMSS(cinfo,lvl,code,str) \ + ((cinfo)->err->msg_code = (code), \ + strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) + +#endif /* JERROR_H */ diff --git a/mk4/modimage/jpeg-6b/jfdctflt.c b/mk4/modimage/jpeg-6b/jfdctflt.c new file mode 100644 index 0000000..79d7a00 --- /dev/null +++ b/mk4/modimage/jpeg-6b/jfdctflt.c @@ -0,0 +1,168 @@ +/* + * jfdctflt.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a floating-point implementation of the + * forward DCT (Discrete Cosine Transform). + * + * This implementation should be more accurate than either of the integer + * DCT implementations. However, it may not give the same results on all + * machines because of differences in roundoff behavior. Speed will depend + * on the hardware's floating point capacity. + * + * A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT + * on each column. Direct algorithms are also available, but they are + * much more complex and seem not to be any faster when reduced to code. + * + * This implementation is based on Arai, Agui, and Nakajima's algorithm for + * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in + * Japanese, but the algorithm is described in the Pennebaker & Mitchell + * JPEG textbook (see REFERENCES section in file README). The following code + * is based directly on figure 4-8 in P&M. + * While an 8-point DCT cannot be done in less than 11 multiplies, it is + * possible to arrange the computation so that many of the multiplies are + * simple scalings of the final outputs. These multiplies can then be + * folded into the multiplications or divisions by the JPEG quantization + * table entries. The AA&N method leaves only 5 multiplies and 29 adds + * to be done in the DCT itself. + * The primary disadvantage of this method is that with a fixed-point + * implementation, accuracy is lost due to imprecise representation of the + * scaled quantization values. However, that problem does not arise if + * we use floating point arithmetic. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + +#ifdef DCT_FLOAT_SUPPORTED + + +/* + * This module is specialized to the case DCTSIZE = 8. + */ + +#if DCTSIZE != 8 + Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ +#endif + + +/* + * Perform the forward DCT on one block of samples. + */ + +GLOBAL(void) +jpeg_fdct_float (FAST_FLOAT * data) +{ + FAST_FLOAT tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + FAST_FLOAT tmp10, tmp11, tmp12, tmp13; + FAST_FLOAT z1, z2, z3, z4, z5, z11, z13; + FAST_FLOAT *dataptr; + int ctr; + + /* Pass 1: process rows. */ + + dataptr = data; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + tmp0 = dataptr[0] + dataptr[7]; + tmp7 = dataptr[0] - dataptr[7]; + tmp1 = dataptr[1] + dataptr[6]; + tmp6 = dataptr[1] - dataptr[6]; + tmp2 = dataptr[2] + dataptr[5]; + tmp5 = dataptr[2] - dataptr[5]; + tmp3 = dataptr[3] + dataptr[4]; + tmp4 = dataptr[3] - dataptr[4]; + + /* Even part */ + + tmp10 = tmp0 + tmp3; /* phase 2 */ + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + dataptr[0] = tmp10 + tmp11; /* phase 3 */ + dataptr[4] = tmp10 - tmp11; + + z1 = (tmp12 + tmp13) * ((FAST_FLOAT) 0.707106781); /* c4 */ + dataptr[2] = tmp13 + z1; /* phase 5 */ + dataptr[6] = tmp13 - z1; + + /* Odd part */ + + tmp10 = tmp4 + tmp5; /* phase 2 */ + tmp11 = tmp5 + tmp6; + tmp12 = tmp6 + tmp7; + + /* The rotator is modified from fig 4-8 to avoid extra negations. */ + z5 = (tmp10 - tmp12) * ((FAST_FLOAT) 0.382683433); /* c6 */ + z2 = ((FAST_FLOAT) 0.541196100) * tmp10 + z5; /* c2-c6 */ + z4 = ((FAST_FLOAT) 1.306562965) * tmp12 + z5; /* c2+c6 */ + z3 = tmp11 * ((FAST_FLOAT) 0.707106781); /* c4 */ + + z11 = tmp7 + z3; /* phase 5 */ + z13 = tmp7 - z3; + + dataptr[5] = z13 + z2; /* phase 6 */ + dataptr[3] = z13 - z2; + dataptr[1] = z11 + z4; + dataptr[7] = z11 - z4; + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. */ + + dataptr = data; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7]; + tmp7 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7]; + tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6]; + tmp6 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6]; + tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5]; + tmp5 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5]; + tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4]; + tmp4 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4]; + + /* Even part */ + + tmp10 = tmp0 + tmp3; /* phase 2 */ + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + dataptr[DCTSIZE*0] = tmp10 + tmp11; /* phase 3 */ + dataptr[DCTSIZE*4] = tmp10 - tmp11; + + z1 = (tmp12 + tmp13) * ((FAST_FLOAT) 0.707106781); /* c4 */ + dataptr[DCTSIZE*2] = tmp13 + z1; /* phase 5 */ + dataptr[DCTSIZE*6] = tmp13 - z1; + + /* Odd part */ + + tmp10 = tmp4 + tmp5; /* phase 2 */ + tmp11 = tmp5 + tmp6; + tmp12 = tmp6 + tmp7; + + /* The rotator is modified from fig 4-8 to avoid extra negations. */ + z5 = (tmp10 - tmp12) * ((FAST_FLOAT) 0.382683433); /* c6 */ + z2 = ((FAST_FLOAT) 0.541196100) * tmp10 + z5; /* c2-c6 */ + z4 = ((FAST_FLOAT) 1.306562965) * tmp12 + z5; /* c2+c6 */ + z3 = tmp11 * ((FAST_FLOAT) 0.707106781); /* c4 */ + + z11 = tmp7 + z3; /* phase 5 */ + z13 = tmp7 - z3; + + dataptr[DCTSIZE*5] = z13 + z2; /* phase 6 */ + dataptr[DCTSIZE*3] = z13 - z2; + dataptr[DCTSIZE*1] = z11 + z4; + dataptr[DCTSIZE*7] = z11 - z4; + + dataptr++; /* advance pointer to next column */ + } +} + +#endif /* DCT_FLOAT_SUPPORTED */ diff --git a/mk4/modimage/jpeg-6b/jfdctfst.c b/mk4/modimage/jpeg-6b/jfdctfst.c new file mode 100644 index 0000000..ccb378a --- /dev/null +++ b/mk4/modimage/jpeg-6b/jfdctfst.c @@ -0,0 +1,224 @@ +/* + * jfdctfst.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a fast, not so accurate integer implementation of the + * forward DCT (Discrete Cosine Transform). + * + * A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT + * on each column. Direct algorithms are also available, but they are + * much more complex and seem not to be any faster when reduced to code. + * + * This implementation is based on Arai, Agui, and Nakajima's algorithm for + * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in + * Japanese, but the algorithm is described in the Pennebaker & Mitchell + * JPEG textbook (see REFERENCES section in file README). The following code + * is based directly on figure 4-8 in P&M. + * While an 8-point DCT cannot be done in less than 11 multiplies, it is + * possible to arrange the computation so that many of the multiplies are + * simple scalings of the final outputs. These multiplies can then be + * folded into the multiplications or divisions by the JPEG quantization + * table entries. The AA&N method leaves only 5 multiplies and 29 adds + * to be done in the DCT itself. + * The primary disadvantage of this method is that with fixed-point math, + * accuracy is lost due to imprecise representation of the scaled + * quantization values. The smaller the quantization table entry, the less + * precise the scaled value, so this implementation does worse with high- + * quality-setting files than with low-quality ones. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + +#ifdef DCT_IFAST_SUPPORTED + + +/* + * This module is specialized to the case DCTSIZE = 8. + */ + +#if DCTSIZE != 8 + Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ +#endif + + +/* Scaling decisions are generally the same as in the LL&M algorithm; + * see jfdctint.c for more details. However, we choose to descale + * (right shift) multiplication products as soon as they are formed, + * rather than carrying additional fractional bits into subsequent additions. + * This compromises accuracy slightly, but it lets us save a few shifts. + * More importantly, 16-bit arithmetic is then adequate (for 8-bit samples) + * everywhere except in the multiplications proper; this saves a good deal + * of work on 16-bit-int machines. + * + * Again to save a few shifts, the intermediate results between pass 1 and + * pass 2 are not upscaled, but are represented only to integral precision. + * + * A final compromise is to represent the multiplicative constants to only + * 8 fractional bits, rather than 13. This saves some shifting work on some + * machines, and may also reduce the cost of multiplication (since there + * are fewer one-bits in the constants). + */ + +#define CONST_BITS 8 + + +/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus + * causing a lot of useless floating-point operations at run time. + * To get around this we use the following pre-calculated constants. + * If you change CONST_BITS you may want to add appropriate values. + * (With a reasonable C compiler, you can just rely on the FIX() macro...) + */ + +#if CONST_BITS == 8 +#define FIX_0_382683433 ((INT32) 98) /* FIX(0.382683433) */ +#define FIX_0_541196100 ((INT32) 139) /* FIX(0.541196100) */ +#define FIX_0_707106781 ((INT32) 181) /* FIX(0.707106781) */ +#define FIX_1_306562965 ((INT32) 334) /* FIX(1.306562965) */ +#else +#define FIX_0_382683433 FIX(0.382683433) +#define FIX_0_541196100 FIX(0.541196100) +#define FIX_0_707106781 FIX(0.707106781) +#define FIX_1_306562965 FIX(1.306562965) +#endif + + +/* We can gain a little more speed, with a further compromise in accuracy, + * by omitting the addition in a descaling shift. This yields an incorrectly + * rounded result half the time... + */ + +#ifndef USE_ACCURATE_ROUNDING +#undef DESCALE +#define DESCALE(x,n) RIGHT_SHIFT(x, n) +#endif + + +/* Multiply a DCTELEM variable by an INT32 constant, and immediately + * descale to yield a DCTELEM result. + */ + +#define MULTIPLY(var,const) ((DCTELEM) DESCALE((var) * (const), CONST_BITS)) + + +/* + * Perform the forward DCT on one block of samples. + */ + +GLOBAL(void) +jpeg_fdct_ifast (DCTELEM * data) +{ + DCTELEM tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + DCTELEM tmp10, tmp11, tmp12, tmp13; + DCTELEM z1, z2, z3, z4, z5, z11, z13; + DCTELEM *dataptr; + int ctr; + SHIFT_TEMPS + + /* Pass 1: process rows. */ + + dataptr = data; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + tmp0 = dataptr[0] + dataptr[7]; + tmp7 = dataptr[0] - dataptr[7]; + tmp1 = dataptr[1] + dataptr[6]; + tmp6 = dataptr[1] - dataptr[6]; + tmp2 = dataptr[2] + dataptr[5]; + tmp5 = dataptr[2] - dataptr[5]; + tmp3 = dataptr[3] + dataptr[4]; + tmp4 = dataptr[3] - dataptr[4]; + + /* Even part */ + + tmp10 = tmp0 + tmp3; /* phase 2 */ + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + dataptr[0] = tmp10 + tmp11; /* phase 3 */ + dataptr[4] = tmp10 - tmp11; + + z1 = MULTIPLY(tmp12 + tmp13, FIX_0_707106781); /* c4 */ + dataptr[2] = tmp13 + z1; /* phase 5 */ + dataptr[6] = tmp13 - z1; + + /* Odd part */ + + tmp10 = tmp4 + tmp5; /* phase 2 */ + tmp11 = tmp5 + tmp6; + tmp12 = tmp6 + tmp7; + + /* The rotator is modified from fig 4-8 to avoid extra negations. */ + z5 = MULTIPLY(tmp10 - tmp12, FIX_0_382683433); /* c6 */ + z2 = MULTIPLY(tmp10, FIX_0_541196100) + z5; /* c2-c6 */ + z4 = MULTIPLY(tmp12, FIX_1_306562965) + z5; /* c2+c6 */ + z3 = MULTIPLY(tmp11, FIX_0_707106781); /* c4 */ + + z11 = tmp7 + z3; /* phase 5 */ + z13 = tmp7 - z3; + + dataptr[5] = z13 + z2; /* phase 6 */ + dataptr[3] = z13 - z2; + dataptr[1] = z11 + z4; + dataptr[7] = z11 - z4; + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. */ + + dataptr = data; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7]; + tmp7 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7]; + tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6]; + tmp6 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6]; + tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5]; + tmp5 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5]; + tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4]; + tmp4 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4]; + + /* Even part */ + + tmp10 = tmp0 + tmp3; /* phase 2 */ + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + dataptr[DCTSIZE*0] = tmp10 + tmp11; /* phase 3 */ + dataptr[DCTSIZE*4] = tmp10 - tmp11; + + z1 = MULTIPLY(tmp12 + tmp13, FIX_0_707106781); /* c4 */ + dataptr[DCTSIZE*2] = tmp13 + z1; /* phase 5 */ + dataptr[DCTSIZE*6] = tmp13 - z1; + + /* Odd part */ + + tmp10 = tmp4 + tmp5; /* phase 2 */ + tmp11 = tmp5 + tmp6; + tmp12 = tmp6 + tmp7; + + /* The rotator is modified from fig 4-8 to avoid extra negations. */ + z5 = MULTIPLY(tmp10 - tmp12, FIX_0_382683433); /* c6 */ + z2 = MULTIPLY(tmp10, FIX_0_541196100) + z5; /* c2-c6 */ + z4 = MULTIPLY(tmp12, FIX_1_306562965) + z5; /* c2+c6 */ + z3 = MULTIPLY(tmp11, FIX_0_707106781); /* c4 */ + + z11 = tmp7 + z3; /* phase 5 */ + z13 = tmp7 - z3; + + dataptr[DCTSIZE*5] = z13 + z2; /* phase 6 */ + dataptr[DCTSIZE*3] = z13 - z2; + dataptr[DCTSIZE*1] = z11 + z4; + dataptr[DCTSIZE*7] = z11 - z4; + + dataptr++; /* advance pointer to next column */ + } +} + +#endif /* DCT_IFAST_SUPPORTED */ diff --git a/mk4/modimage/jpeg-6b/jfdctint.c b/mk4/modimage/jpeg-6b/jfdctint.c new file mode 100644 index 0000000..0a78b64 --- /dev/null +++ b/mk4/modimage/jpeg-6b/jfdctint.c @@ -0,0 +1,283 @@ +/* + * jfdctint.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a slow-but-accurate integer implementation of the + * forward DCT (Discrete Cosine Transform). + * + * A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT + * on each column. Direct algorithms are also available, but they are + * much more complex and seem not to be any faster when reduced to code. + * + * This implementation is based on an algorithm described in + * C. Loeffler, A. Ligtenberg and G. Moschytz, "Practical Fast 1-D DCT + * Algorithms with 11 Multiplications", Proc. Int'l. Conf. on Acoustics, + * Speech, and Signal Processing 1989 (ICASSP '89), pp. 988-991. + * The primary algorithm described there uses 11 multiplies and 29 adds. + * We use their alternate method with 12 multiplies and 32 adds. + * The advantage of this method is that no data path contains more than one + * multiplication; this allows a very simple and accurate implementation in + * scaled fixed-point arithmetic, with a minimal number of shifts. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + +#ifdef DCT_ISLOW_SUPPORTED + + +/* + * This module is specialized to the case DCTSIZE = 8. + */ + +#if DCTSIZE != 8 + Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ +#endif + + +/* + * The poop on this scaling stuff is as follows: + * + * Each 1-D DCT step produces outputs which are a factor of sqrt(N) + * larger than the true DCT outputs. The final outputs are therefore + * a factor of N larger than desired; since N=8 this can be cured by + * a simple right shift at the end of the algorithm. The advantage of + * this arrangement is that we save two multiplications per 1-D DCT, + * because the y0 and y4 outputs need not be divided by sqrt(N). + * In the IJG code, this factor of 8 is removed by the quantization step + * (in jcdctmgr.c), NOT in this module. + * + * We have to do addition and subtraction of the integer inputs, which + * is no problem, and multiplication by fractional constants, which is + * a problem to do in integer arithmetic. We multiply all the constants + * by CONST_SCALE and convert them to integer constants (thus retaining + * CONST_BITS bits of precision in the constants). After doing a + * multiplication we have to divide the product by CONST_SCALE, with proper + * rounding, to produce the correct output. This division can be done + * cheaply as a right shift of CONST_BITS bits. We postpone shifting + * as long as possible so that partial sums can be added together with + * full fractional precision. + * + * The outputs of the first pass are scaled up by PASS1_BITS bits so that + * they are represented to better-than-integral precision. These outputs + * require BITS_IN_JSAMPLE + PASS1_BITS + 3 bits; this fits in a 16-bit word + * with the recommended scaling. (For 12-bit sample data, the intermediate + * array is INT32 anyway.) + * + * To avoid overflow of the 32-bit intermediate results in pass 2, we must + * have BITS_IN_JSAMPLE + CONST_BITS + PASS1_BITS <= 26. Error analysis + * shows that the values given below are the most effective. + */ + +#if BITS_IN_JSAMPLE == 8 +#define CONST_BITS 13 +#define PASS1_BITS 2 +#else +#define CONST_BITS 13 +#define PASS1_BITS 1 /* lose a little precision to avoid overflow */ +#endif + +/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus + * causing a lot of useless floating-point operations at run time. + * To get around this we use the following pre-calculated constants. + * If you change CONST_BITS you may want to add appropriate values. + * (With a reasonable C compiler, you can just rely on the FIX() macro...) + */ + +#if CONST_BITS == 13 +#define FIX_0_298631336 ((INT32) 2446) /* FIX(0.298631336) */ +#define FIX_0_390180644 ((INT32) 3196) /* FIX(0.390180644) */ +#define FIX_0_541196100 ((INT32) 4433) /* FIX(0.541196100) */ +#define FIX_0_765366865 ((INT32) 6270) /* FIX(0.765366865) */ +#define FIX_0_899976223 ((INT32) 7373) /* FIX(0.899976223) */ +#define FIX_1_175875602 ((INT32) 9633) /* FIX(1.175875602) */ +#define FIX_1_501321110 ((INT32) 12299) /* FIX(1.501321110) */ +#define FIX_1_847759065 ((INT32) 15137) /* FIX(1.847759065) */ +#define FIX_1_961570560 ((INT32) 16069) /* FIX(1.961570560) */ +#define FIX_2_053119869 ((INT32) 16819) /* FIX(2.053119869) */ +#define FIX_2_562915447 ((INT32) 20995) /* FIX(2.562915447) */ +#define FIX_3_072711026 ((INT32) 25172) /* FIX(3.072711026) */ +#else +#define FIX_0_298631336 FIX(0.298631336) +#define FIX_0_390180644 FIX(0.390180644) +#define FIX_0_541196100 FIX(0.541196100) +#define FIX_0_765366865 FIX(0.765366865) +#define FIX_0_899976223 FIX(0.899976223) +#define FIX_1_175875602 FIX(1.175875602) +#define FIX_1_501321110 FIX(1.501321110) +#define FIX_1_847759065 FIX(1.847759065) +#define FIX_1_961570560 FIX(1.961570560) +#define FIX_2_053119869 FIX(2.053119869) +#define FIX_2_562915447 FIX(2.562915447) +#define FIX_3_072711026 FIX(3.072711026) +#endif + + +/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result. + * For 8-bit samples with the recommended scaling, all the variable + * and constant values involved are no more than 16 bits wide, so a + * 16x16->32 bit multiply can be used instead of a full 32x32 multiply. + * For 12-bit samples, a full 32-bit multiplication will be needed. + */ + +#if BITS_IN_JSAMPLE == 8 +#define MULTIPLY(var,const) MULTIPLY16C16(var,const) +#else +#define MULTIPLY(var,const) ((var) * (const)) +#endif + + +/* + * Perform the forward DCT on one block of samples. + */ + +GLOBAL(void) +jpeg_fdct_islow (DCTELEM * data) +{ + INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + INT32 tmp10, tmp11, tmp12, tmp13; + INT32 z1, z2, z3, z4, z5; + DCTELEM *dataptr; + int ctr; + SHIFT_TEMPS + + /* Pass 1: process rows. */ + /* Note results are scaled up by sqrt(8) compared to a true DCT; */ + /* furthermore, we scale the results by 2**PASS1_BITS. */ + + dataptr = data; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + tmp0 = dataptr[0] + dataptr[7]; + tmp7 = dataptr[0] - dataptr[7]; + tmp1 = dataptr[1] + dataptr[6]; + tmp6 = dataptr[1] - dataptr[6]; + tmp2 = dataptr[2] + dataptr[5]; + tmp5 = dataptr[2] - dataptr[5]; + tmp3 = dataptr[3] + dataptr[4]; + tmp4 = dataptr[3] - dataptr[4]; + + /* Even part per LL&M figure 1 --- note that published figure is faulty; + * rotator "sqrt(2)*c1" should be "sqrt(2)*c6". + */ + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + dataptr[0] = (DCTELEM) ((tmp10 + tmp11) << PASS1_BITS); + dataptr[4] = (DCTELEM) ((tmp10 - tmp11) << PASS1_BITS); + + z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100); + dataptr[2] = (DCTELEM) DESCALE(z1 + MULTIPLY(tmp13, FIX_0_765366865), + CONST_BITS-PASS1_BITS); + dataptr[6] = (DCTELEM) DESCALE(z1 + MULTIPLY(tmp12, - FIX_1_847759065), + CONST_BITS-PASS1_BITS); + + /* Odd part per figure 8 --- note paper omits factor of sqrt(2). + * cK represents cos(K*pi/16). + * i0..i3 in the paper are tmp4..tmp7 here. + */ + + z1 = tmp4 + tmp7; + z2 = tmp5 + tmp6; + z3 = tmp4 + tmp6; + z4 = tmp5 + tmp7; + z5 = MULTIPLY(z3 + z4, FIX_1_175875602); /* sqrt(2) * c3 */ + + tmp4 = MULTIPLY(tmp4, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */ + tmp5 = MULTIPLY(tmp5, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */ + tmp6 = MULTIPLY(tmp6, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */ + tmp7 = MULTIPLY(tmp7, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */ + z1 = MULTIPLY(z1, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */ + z2 = MULTIPLY(z2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */ + z3 = MULTIPLY(z3, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */ + z4 = MULTIPLY(z4, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */ + + z3 += z5; + z4 += z5; + + dataptr[7] = (DCTELEM) DESCALE(tmp4 + z1 + z3, CONST_BITS-PASS1_BITS); + dataptr[5] = (DCTELEM) DESCALE(tmp5 + z2 + z4, CONST_BITS-PASS1_BITS); + dataptr[3] = (DCTELEM) DESCALE(tmp6 + z2 + z3, CONST_BITS-PASS1_BITS); + dataptr[1] = (DCTELEM) DESCALE(tmp7 + z1 + z4, CONST_BITS-PASS1_BITS); + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. + * We remove the PASS1_BITS scaling, but leave the results scaled up + * by an overall factor of 8. + */ + + dataptr = data; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7]; + tmp7 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7]; + tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6]; + tmp6 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6]; + tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5]; + tmp5 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5]; + tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4]; + tmp4 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4]; + + /* Even part per LL&M figure 1 --- note that published figure is faulty; + * rotator "sqrt(2)*c1" should be "sqrt(2)*c6". + */ + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + dataptr[DCTSIZE*0] = (DCTELEM) DESCALE(tmp10 + tmp11, PASS1_BITS); + dataptr[DCTSIZE*4] = (DCTELEM) DESCALE(tmp10 - tmp11, PASS1_BITS); + + z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100); + dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(z1 + MULTIPLY(tmp13, FIX_0_765366865), + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*6] = (DCTELEM) DESCALE(z1 + MULTIPLY(tmp12, - FIX_1_847759065), + CONST_BITS+PASS1_BITS); + + /* Odd part per figure 8 --- note paper omits factor of sqrt(2). + * cK represents cos(K*pi/16). + * i0..i3 in the paper are tmp4..tmp7 here. + */ + + z1 = tmp4 + tmp7; + z2 = tmp5 + tmp6; + z3 = tmp4 + tmp6; + z4 = tmp5 + tmp7; + z5 = MULTIPLY(z3 + z4, FIX_1_175875602); /* sqrt(2) * c3 */ + + tmp4 = MULTIPLY(tmp4, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */ + tmp5 = MULTIPLY(tmp5, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */ + tmp6 = MULTIPLY(tmp6, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */ + tmp7 = MULTIPLY(tmp7, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */ + z1 = MULTIPLY(z1, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */ + z2 = MULTIPLY(z2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */ + z3 = MULTIPLY(z3, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */ + z4 = MULTIPLY(z4, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */ + + z3 += z5; + z4 += z5; + + dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp4 + z1 + z3, + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp5 + z2 + z4, + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp6 + z2 + z3, + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp7 + z1 + z4, + CONST_BITS+PASS1_BITS); + + dataptr++; /* advance pointer to next column */ + } +} + +#endif /* DCT_ISLOW_SUPPORTED */ diff --git a/mk4/modimage/jpeg-6b/jidctflt.c b/mk4/modimage/jpeg-6b/jidctflt.c new file mode 100644 index 0000000..0188ce3 --- /dev/null +++ b/mk4/modimage/jpeg-6b/jidctflt.c @@ -0,0 +1,242 @@ +/* + * jidctflt.c + * + * Copyright (C) 1994-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a floating-point implementation of the + * inverse DCT (Discrete Cosine Transform). In the IJG code, this routine + * must also perform dequantization of the input coefficients. + * + * This implementation should be more accurate than either of the integer + * IDCT implementations. However, it may not give the same results on all + * machines because of differences in roundoff behavior. Speed will depend + * on the hardware's floating point capacity. + * + * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT + * on each row (or vice versa, but it's more convenient to emit a row at + * a time). Direct algorithms are also available, but they are much more + * complex and seem not to be any faster when reduced to code. + * + * This implementation is based on Arai, Agui, and Nakajima's algorithm for + * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in + * Japanese, but the algorithm is described in the Pennebaker & Mitchell + * JPEG textbook (see REFERENCES section in file README). The following code + * is based directly on figure 4-8 in P&M. + * While an 8-point DCT cannot be done in less than 11 multiplies, it is + * possible to arrange the computation so that many of the multiplies are + * simple scalings of the final outputs. These multiplies can then be + * folded into the multiplications or divisions by the JPEG quantization + * table entries. The AA&N method leaves only 5 multiplies and 29 adds + * to be done in the DCT itself. + * The primary disadvantage of this method is that with a fixed-point + * implementation, accuracy is lost due to imprecise representation of the + * scaled quantization values. However, that problem does not arise if + * we use floating point arithmetic. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + +#ifdef DCT_FLOAT_SUPPORTED + + +/* + * This module is specialized to the case DCTSIZE = 8. + */ + +#if DCTSIZE != 8 + Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ +#endif + + +/* Dequantize a coefficient by multiplying it by the multiplier-table + * entry; produce a float result. + */ + +#define DEQUANTIZE(coef,quantval) (((FAST_FLOAT) (coef)) * (quantval)) + + +/* + * Perform dequantization and inverse DCT on one block of coefficients. + */ + +GLOBAL(void) +jpeg_idct_float (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + FAST_FLOAT tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + FAST_FLOAT tmp10, tmp11, tmp12, tmp13; + FAST_FLOAT z5, z10, z11, z12, z13; + JCOEFPTR inptr; + FLOAT_MULT_TYPE * quantptr; + FAST_FLOAT * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + FAST_FLOAT workspace[DCTSIZE2]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (FLOAT_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = DCTSIZE; ctr > 0; ctr--) { + /* Due to quantization, we will usually find that many of the input + * coefficients are zero, especially the AC terms. We can exploit this + * by short-circuiting the IDCT calculation for any column in which all + * the AC terms are zero. In that case each output is equal to the + * DC coefficient (with scale factor as needed). + * With typical images and quantization tables, half or more of the + * column DCT calculations can be simplified this way. + */ + + if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 && + inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 && + inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 && + inptr[DCTSIZE*7] == 0) { + /* AC terms all zero */ + FAST_FLOAT dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + + wsptr[DCTSIZE*0] = dcval; + wsptr[DCTSIZE*1] = dcval; + wsptr[DCTSIZE*2] = dcval; + wsptr[DCTSIZE*3] = dcval; + wsptr[DCTSIZE*4] = dcval; + wsptr[DCTSIZE*5] = dcval; + wsptr[DCTSIZE*6] = dcval; + wsptr[DCTSIZE*7] = dcval; + + inptr++; /* advance pointers to next column */ + quantptr++; + wsptr++; + continue; + } + + /* Even part */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + tmp3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + tmp10 = tmp0 + tmp2; /* phase 3 */ + tmp11 = tmp0 - tmp2; + + tmp13 = tmp1 + tmp3; /* phases 5-3 */ + tmp12 = (tmp1 - tmp3) * ((FAST_FLOAT) 1.414213562) - tmp13; /* 2*c4 */ + + tmp0 = tmp10 + tmp13; /* phase 2 */ + tmp3 = tmp10 - tmp13; + tmp1 = tmp11 + tmp12; + tmp2 = tmp11 - tmp12; + + /* Odd part */ + + tmp4 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + tmp5 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + tmp6 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + tmp7 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + + z13 = tmp6 + tmp5; /* phase 6 */ + z10 = tmp6 - tmp5; + z11 = tmp4 + tmp7; + z12 = tmp4 - tmp7; + + tmp7 = z11 + z13; /* phase 5 */ + tmp11 = (z11 - z13) * ((FAST_FLOAT) 1.414213562); /* 2*c4 */ + + z5 = (z10 + z12) * ((FAST_FLOAT) 1.847759065); /* 2*c2 */ + tmp10 = ((FAST_FLOAT) 1.082392200) * z12 - z5; /* 2*(c2-c6) */ + tmp12 = ((FAST_FLOAT) -2.613125930) * z10 + z5; /* -2*(c2+c6) */ + + tmp6 = tmp12 - tmp7; /* phase 2 */ + tmp5 = tmp11 - tmp6; + tmp4 = tmp10 + tmp5; + + wsptr[DCTSIZE*0] = tmp0 + tmp7; + wsptr[DCTSIZE*7] = tmp0 - tmp7; + wsptr[DCTSIZE*1] = tmp1 + tmp6; + wsptr[DCTSIZE*6] = tmp1 - tmp6; + wsptr[DCTSIZE*2] = tmp2 + tmp5; + wsptr[DCTSIZE*5] = tmp2 - tmp5; + wsptr[DCTSIZE*4] = tmp3 + tmp4; + wsptr[DCTSIZE*3] = tmp3 - tmp4; + + inptr++; /* advance pointers to next column */ + quantptr++; + wsptr++; + } + + /* Pass 2: process rows from work array, store into output array. */ + /* Note that we must descale the results by a factor of 8 == 2**3. */ + + wsptr = workspace; + for (ctr = 0; ctr < DCTSIZE; ctr++) { + outptr = output_buf[ctr] + output_col; + /* Rows of zeroes can be exploited in the same way as we did with columns. + * However, the column calculation has created many nonzero AC terms, so + * the simplification applies less often (typically 5% to 10% of the time). + * And testing floats for zero is relatively expensive, so we don't bother. + */ + + /* Even part */ + + tmp10 = wsptr[0] + wsptr[4]; + tmp11 = wsptr[0] - wsptr[4]; + + tmp13 = wsptr[2] + wsptr[6]; + tmp12 = (wsptr[2] - wsptr[6]) * ((FAST_FLOAT) 1.414213562) - tmp13; + + tmp0 = tmp10 + tmp13; + tmp3 = tmp10 - tmp13; + tmp1 = tmp11 + tmp12; + tmp2 = tmp11 - tmp12; + + /* Odd part */ + + z13 = wsptr[5] + wsptr[3]; + z10 = wsptr[5] - wsptr[3]; + z11 = wsptr[1] + wsptr[7]; + z12 = wsptr[1] - wsptr[7]; + + tmp7 = z11 + z13; + tmp11 = (z11 - z13) * ((FAST_FLOAT) 1.414213562); + + z5 = (z10 + z12) * ((FAST_FLOAT) 1.847759065); /* 2*c2 */ + tmp10 = ((FAST_FLOAT) 1.082392200) * z12 - z5; /* 2*(c2-c6) */ + tmp12 = ((FAST_FLOAT) -2.613125930) * z10 + z5; /* -2*(c2+c6) */ + + tmp6 = tmp12 - tmp7; + tmp5 = tmp11 - tmp6; + tmp4 = tmp10 + tmp5; + + /* Final output stage: scale down by a factor of 8 and range-limit */ + + outptr[0] = range_limit[(int) DESCALE((INT32) (tmp0 + tmp7), 3) + & RANGE_MASK]; + outptr[7] = range_limit[(int) DESCALE((INT32) (tmp0 - tmp7), 3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) DESCALE((INT32) (tmp1 + tmp6), 3) + & RANGE_MASK]; + outptr[6] = range_limit[(int) DESCALE((INT32) (tmp1 - tmp6), 3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) DESCALE((INT32) (tmp2 + tmp5), 3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) DESCALE((INT32) (tmp2 - tmp5), 3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) DESCALE((INT32) (tmp3 + tmp4), 3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) DESCALE((INT32) (tmp3 - tmp4), 3) + & RANGE_MASK]; + + wsptr += DCTSIZE; /* advance pointer to next row */ + } +} + +#endif /* DCT_FLOAT_SUPPORTED */ diff --git a/mk4/modimage/jpeg-6b/jidctfst.c b/mk4/modimage/jpeg-6b/jidctfst.c new file mode 100644 index 0000000..dba4216 --- /dev/null +++ b/mk4/modimage/jpeg-6b/jidctfst.c @@ -0,0 +1,368 @@ +/* + * jidctfst.c + * + * Copyright (C) 1994-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a fast, not so accurate integer implementation of the + * inverse DCT (Discrete Cosine Transform). In the IJG code, this routine + * must also perform dequantization of the input coefficients. + * + * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT + * on each row (or vice versa, but it's more convenient to emit a row at + * a time). Direct algorithms are also available, but they are much more + * complex and seem not to be any faster when reduced to code. + * + * This implementation is based on Arai, Agui, and Nakajima's algorithm for + * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in + * Japanese, but the algorithm is described in the Pennebaker & Mitchell + * JPEG textbook (see REFERENCES section in file README). The following code + * is based directly on figure 4-8 in P&M. + * While an 8-point DCT cannot be done in less than 11 multiplies, it is + * possible to arrange the computation so that many of the multiplies are + * simple scalings of the final outputs. These multiplies can then be + * folded into the multiplications or divisions by the JPEG quantization + * table entries. The AA&N method leaves only 5 multiplies and 29 adds + * to be done in the DCT itself. + * The primary disadvantage of this method is that with fixed-point math, + * accuracy is lost due to imprecise representation of the scaled + * quantization values. The smaller the quantization table entry, the less + * precise the scaled value, so this implementation does worse with high- + * quality-setting files than with low-quality ones. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + +#ifdef DCT_IFAST_SUPPORTED + + +/* + * This module is specialized to the case DCTSIZE = 8. + */ + +#if DCTSIZE != 8 + Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ +#endif + + +/* Scaling decisions are generally the same as in the LL&M algorithm; + * see jidctint.c for more details. However, we choose to descale + * (right shift) multiplication products as soon as they are formed, + * rather than carrying additional fractional bits into subsequent additions. + * This compromises accuracy slightly, but it lets us save a few shifts. + * More importantly, 16-bit arithmetic is then adequate (for 8-bit samples) + * everywhere except in the multiplications proper; this saves a good deal + * of work on 16-bit-int machines. + * + * The dequantized coefficients are not integers because the AA&N scaling + * factors have been incorporated. We represent them scaled up by PASS1_BITS, + * so that the first and second IDCT rounds have the same input scaling. + * For 8-bit JSAMPLEs, we choose IFAST_SCALE_BITS = PASS1_BITS so as to + * avoid a descaling shift; this compromises accuracy rather drastically + * for small quantization table entries, but it saves a lot of shifts. + * For 12-bit JSAMPLEs, there's no hope of using 16x16 multiplies anyway, + * so we use a much larger scaling factor to preserve accuracy. + * + * A final compromise is to represent the multiplicative constants to only + * 8 fractional bits, rather than 13. This saves some shifting work on some + * machines, and may also reduce the cost of multiplication (since there + * are fewer one-bits in the constants). + */ + +#if BITS_IN_JSAMPLE == 8 +#define CONST_BITS 8 +#define PASS1_BITS 2 +#else +#define CONST_BITS 8 +#define PASS1_BITS 1 /* lose a little precision to avoid overflow */ +#endif + +/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus + * causing a lot of useless floating-point operations at run time. + * To get around this we use the following pre-calculated constants. + * If you change CONST_BITS you may want to add appropriate values. + * (With a reasonable C compiler, you can just rely on the FIX() macro...) + */ + +#if CONST_BITS == 8 +#define FIX_1_082392200 ((INT32) 277) /* FIX(1.082392200) */ +#define FIX_1_414213562 ((INT32) 362) /* FIX(1.414213562) */ +#define FIX_1_847759065 ((INT32) 473) /* FIX(1.847759065) */ +#define FIX_2_613125930 ((INT32) 669) /* FIX(2.613125930) */ +#else +#define FIX_1_082392200 FIX(1.082392200) +#define FIX_1_414213562 FIX(1.414213562) +#define FIX_1_847759065 FIX(1.847759065) +#define FIX_2_613125930 FIX(2.613125930) +#endif + + +/* We can gain a little more speed, with a further compromise in accuracy, + * by omitting the addition in a descaling shift. This yields an incorrectly + * rounded result half the time... + */ + +#ifndef USE_ACCURATE_ROUNDING +#undef DESCALE +#define DESCALE(x,n) RIGHT_SHIFT(x, n) +#endif + + +/* Multiply a DCTELEM variable by an INT32 constant, and immediately + * descale to yield a DCTELEM result. + */ + +#define MULTIPLY(var,const) ((DCTELEM) DESCALE((var) * (const), CONST_BITS)) + + +/* Dequantize a coefficient by multiplying it by the multiplier-table + * entry; produce a DCTELEM result. For 8-bit data a 16x16->16 + * multiplication will do. For 12-bit data, the multiplier table is + * declared INT32, so a 32-bit multiply will be used. + */ + +#if BITS_IN_JSAMPLE == 8 +#define DEQUANTIZE(coef,quantval) (((IFAST_MULT_TYPE) (coef)) * (quantval)) +#else +#define DEQUANTIZE(coef,quantval) \ + DESCALE((coef)*(quantval), IFAST_SCALE_BITS-PASS1_BITS) +#endif + + +/* Like DESCALE, but applies to a DCTELEM and produces an int. + * We assume that int right shift is unsigned if INT32 right shift is. + */ + +#ifdef RIGHT_SHIFT_IS_UNSIGNED +#define ISHIFT_TEMPS DCTELEM ishift_temp; +#if BITS_IN_JSAMPLE == 8 +#define DCTELEMBITS 16 /* DCTELEM may be 16 or 32 bits */ +#else +#define DCTELEMBITS 32 /* DCTELEM must be 32 bits */ +#endif +#define IRIGHT_SHIFT(x,shft) \ + ((ishift_temp = (x)) < 0 ? \ + (ishift_temp >> (shft)) | ((~((DCTELEM) 0)) << (DCTELEMBITS-(shft))) : \ + (ishift_temp >> (shft))) +#else +#define ISHIFT_TEMPS +#define IRIGHT_SHIFT(x,shft) ((x) >> (shft)) +#endif + +#ifdef USE_ACCURATE_ROUNDING +#define IDESCALE(x,n) ((int) IRIGHT_SHIFT((x) + (1 << ((n)-1)), n)) +#else +#define IDESCALE(x,n) ((int) IRIGHT_SHIFT(x, n)) +#endif + + +/* + * Perform dequantization and inverse DCT on one block of coefficients. + */ + +GLOBAL(void) +jpeg_idct_ifast (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + DCTELEM tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + DCTELEM tmp10, tmp11, tmp12, tmp13; + DCTELEM z5, z10, z11, z12, z13; + JCOEFPTR inptr; + IFAST_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[DCTSIZE2]; /* buffers data between passes */ + SHIFT_TEMPS /* for DESCALE */ + ISHIFT_TEMPS /* for IDESCALE */ + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (IFAST_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = DCTSIZE; ctr > 0; ctr--) { + /* Due to quantization, we will usually find that many of the input + * coefficients are zero, especially the AC terms. We can exploit this + * by short-circuiting the IDCT calculation for any column in which all + * the AC terms are zero. In that case each output is equal to the + * DC coefficient (with scale factor as needed). + * With typical images and quantization tables, half or more of the + * column DCT calculations can be simplified this way. + */ + + if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 && + inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 && + inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 && + inptr[DCTSIZE*7] == 0) { + /* AC terms all zero */ + int dcval = (int) DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + + wsptr[DCTSIZE*0] = dcval; + wsptr[DCTSIZE*1] = dcval; + wsptr[DCTSIZE*2] = dcval; + wsptr[DCTSIZE*3] = dcval; + wsptr[DCTSIZE*4] = dcval; + wsptr[DCTSIZE*5] = dcval; + wsptr[DCTSIZE*6] = dcval; + wsptr[DCTSIZE*7] = dcval; + + inptr++; /* advance pointers to next column */ + quantptr++; + wsptr++; + continue; + } + + /* Even part */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + tmp3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + tmp10 = tmp0 + tmp2; /* phase 3 */ + tmp11 = tmp0 - tmp2; + + tmp13 = tmp1 + tmp3; /* phases 5-3 */ + tmp12 = MULTIPLY(tmp1 - tmp3, FIX_1_414213562) - tmp13; /* 2*c4 */ + + tmp0 = tmp10 + tmp13; /* phase 2 */ + tmp3 = tmp10 - tmp13; + tmp1 = tmp11 + tmp12; + tmp2 = tmp11 - tmp12; + + /* Odd part */ + + tmp4 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + tmp5 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + tmp6 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + tmp7 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + + z13 = tmp6 + tmp5; /* phase 6 */ + z10 = tmp6 - tmp5; + z11 = tmp4 + tmp7; + z12 = tmp4 - tmp7; + + tmp7 = z11 + z13; /* phase 5 */ + tmp11 = MULTIPLY(z11 - z13, FIX_1_414213562); /* 2*c4 */ + + z5 = MULTIPLY(z10 + z12, FIX_1_847759065); /* 2*c2 */ + tmp10 = MULTIPLY(z12, FIX_1_082392200) - z5; /* 2*(c2-c6) */ + tmp12 = MULTIPLY(z10, - FIX_2_613125930) + z5; /* -2*(c2+c6) */ + + tmp6 = tmp12 - tmp7; /* phase 2 */ + tmp5 = tmp11 - tmp6; + tmp4 = tmp10 + tmp5; + + wsptr[DCTSIZE*0] = (int) (tmp0 + tmp7); + wsptr[DCTSIZE*7] = (int) (tmp0 - tmp7); + wsptr[DCTSIZE*1] = (int) (tmp1 + tmp6); + wsptr[DCTSIZE*6] = (int) (tmp1 - tmp6); + wsptr[DCTSIZE*2] = (int) (tmp2 + tmp5); + wsptr[DCTSIZE*5] = (int) (tmp2 - tmp5); + wsptr[DCTSIZE*4] = (int) (tmp3 + tmp4); + wsptr[DCTSIZE*3] = (int) (tmp3 - tmp4); + + inptr++; /* advance pointers to next column */ + quantptr++; + wsptr++; + } + + /* Pass 2: process rows from work array, store into output array. */ + /* Note that we must descale the results by a factor of 8 == 2**3, */ + /* and also undo the PASS1_BITS scaling. */ + + wsptr = workspace; + for (ctr = 0; ctr < DCTSIZE; ctr++) { + outptr = output_buf[ctr] + output_col; + /* Rows of zeroes can be exploited in the same way as we did with columns. + * However, the column calculation has created many nonzero AC terms, so + * the simplification applies less often (typically 5% to 10% of the time). + * On machines with very fast multiplication, it's possible that the + * test takes more time than it's worth. In that case this section + * may be commented out. + */ + +#ifndef NO_ZERO_ROW_TEST + if (wsptr[1] == 0 && wsptr[2] == 0 && wsptr[3] == 0 && wsptr[4] == 0 && + wsptr[5] == 0 && wsptr[6] == 0 && wsptr[7] == 0) { + /* AC terms all zero */ + JSAMPLE dcval = range_limit[IDESCALE(wsptr[0], PASS1_BITS+3) + & RANGE_MASK]; + + outptr[0] = dcval; + outptr[1] = dcval; + outptr[2] = dcval; + outptr[3] = dcval; + outptr[4] = dcval; + outptr[5] = dcval; + outptr[6] = dcval; + outptr[7] = dcval; + + wsptr += DCTSIZE; /* advance pointer to next row */ + continue; + } +#endif + + /* Even part */ + + tmp10 = ((DCTELEM) wsptr[0] + (DCTELEM) wsptr[4]); + tmp11 = ((DCTELEM) wsptr[0] - (DCTELEM) wsptr[4]); + + tmp13 = ((DCTELEM) wsptr[2] + (DCTELEM) wsptr[6]); + tmp12 = MULTIPLY((DCTELEM) wsptr[2] - (DCTELEM) wsptr[6], FIX_1_414213562) + - tmp13; + + tmp0 = tmp10 + tmp13; + tmp3 = tmp10 - tmp13; + tmp1 = tmp11 + tmp12; + tmp2 = tmp11 - tmp12; + + /* Odd part */ + + z13 = (DCTELEM) wsptr[5] + (DCTELEM) wsptr[3]; + z10 = (DCTELEM) wsptr[5] - (DCTELEM) wsptr[3]; + z11 = (DCTELEM) wsptr[1] + (DCTELEM) wsptr[7]; + z12 = (DCTELEM) wsptr[1] - (DCTELEM) wsptr[7]; + + tmp7 = z11 + z13; /* phase 5 */ + tmp11 = MULTIPLY(z11 - z13, FIX_1_414213562); /* 2*c4 */ + + z5 = MULTIPLY(z10 + z12, FIX_1_847759065); /* 2*c2 */ + tmp10 = MULTIPLY(z12, FIX_1_082392200) - z5; /* 2*(c2-c6) */ + tmp12 = MULTIPLY(z10, - FIX_2_613125930) + z5; /* -2*(c2+c6) */ + + tmp6 = tmp12 - tmp7; /* phase 2 */ + tmp5 = tmp11 - tmp6; + tmp4 = tmp10 + tmp5; + + /* Final output stage: scale down by a factor of 8 and range-limit */ + + outptr[0] = range_limit[IDESCALE(tmp0 + tmp7, PASS1_BITS+3) + & RANGE_MASK]; + outptr[7] = range_limit[IDESCALE(tmp0 - tmp7, PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[IDESCALE(tmp1 + tmp6, PASS1_BITS+3) + & RANGE_MASK]; + outptr[6] = range_limit[IDESCALE(tmp1 - tmp6, PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[IDESCALE(tmp2 + tmp5, PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[IDESCALE(tmp2 - tmp5, PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[IDESCALE(tmp3 + tmp4, PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[IDESCALE(tmp3 - tmp4, PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += DCTSIZE; /* advance pointer to next row */ + } +} + +#endif /* DCT_IFAST_SUPPORTED */ diff --git a/mk4/modimage/jpeg-6b/jidctint.c b/mk4/modimage/jpeg-6b/jidctint.c new file mode 100644 index 0000000..a72b320 --- /dev/null +++ b/mk4/modimage/jpeg-6b/jidctint.c @@ -0,0 +1,389 @@ +/* + * jidctint.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a slow-but-accurate integer implementation of the + * inverse DCT (Discrete Cosine Transform). In the IJG code, this routine + * must also perform dequantization of the input coefficients. + * + * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT + * on each row (or vice versa, but it's more convenient to emit a row at + * a time). Direct algorithms are also available, but they are much more + * complex and seem not to be any faster when reduced to code. + * + * This implementation is based on an algorithm described in + * C. Loeffler, A. Ligtenberg and G. Moschytz, "Practical Fast 1-D DCT + * Algorithms with 11 Multiplications", Proc. Int'l. Conf. on Acoustics, + * Speech, and Signal Processing 1989 (ICASSP '89), pp. 988-991. + * The primary algorithm described there uses 11 multiplies and 29 adds. + * We use their alternate method with 12 multiplies and 32 adds. + * The advantage of this method is that no data path contains more than one + * multiplication; this allows a very simple and accurate implementation in + * scaled fixed-point arithmetic, with a minimal number of shifts. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + +#ifdef DCT_ISLOW_SUPPORTED + + +/* + * This module is specialized to the case DCTSIZE = 8. + */ + +#if DCTSIZE != 8 + Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ +#endif + + +/* + * The poop on this scaling stuff is as follows: + * + * Each 1-D IDCT step produces outputs which are a factor of sqrt(N) + * larger than the true IDCT outputs. The final outputs are therefore + * a factor of N larger than desired; since N=8 this can be cured by + * a simple right shift at the end of the algorithm. The advantage of + * this arrangement is that we save two multiplications per 1-D IDCT, + * because the y0 and y4 inputs need not be divided by sqrt(N). + * + * We have to do addition and subtraction of the integer inputs, which + * is no problem, and multiplication by fractional constants, which is + * a problem to do in integer arithmetic. We multiply all the constants + * by CONST_SCALE and convert them to integer constants (thus retaining + * CONST_BITS bits of precision in the constants). After doing a + * multiplication we have to divide the product by CONST_SCALE, with proper + * rounding, to produce the correct output. This division can be done + * cheaply as a right shift of CONST_BITS bits. We postpone shifting + * as long as possible so that partial sums can be added together with + * full fractional precision. + * + * The outputs of the first pass are scaled up by PASS1_BITS bits so that + * they are represented to better-than-integral precision. These outputs + * require BITS_IN_JSAMPLE + PASS1_BITS + 3 bits; this fits in a 16-bit word + * with the recommended scaling. (To scale up 12-bit sample data further, an + * intermediate INT32 array would be needed.) + * + * To avoid overflow of the 32-bit intermediate results in pass 2, we must + * have BITS_IN_JSAMPLE + CONST_BITS + PASS1_BITS <= 26. Error analysis + * shows that the values given below are the most effective. + */ + +#if BITS_IN_JSAMPLE == 8 +#define CONST_BITS 13 +#define PASS1_BITS 2 +#else +#define CONST_BITS 13 +#define PASS1_BITS 1 /* lose a little precision to avoid overflow */ +#endif + +/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus + * causing a lot of useless floating-point operations at run time. + * To get around this we use the following pre-calculated constants. + * If you change CONST_BITS you may want to add appropriate values. + * (With a reasonable C compiler, you can just rely on the FIX() macro...) + */ + +#if CONST_BITS == 13 +#define FIX_0_298631336 ((INT32) 2446) /* FIX(0.298631336) */ +#define FIX_0_390180644 ((INT32) 3196) /* FIX(0.390180644) */ +#define FIX_0_541196100 ((INT32) 4433) /* FIX(0.541196100) */ +#define FIX_0_765366865 ((INT32) 6270) /* FIX(0.765366865) */ +#define FIX_0_899976223 ((INT32) 7373) /* FIX(0.899976223) */ +#define FIX_1_175875602 ((INT32) 9633) /* FIX(1.175875602) */ +#define FIX_1_501321110 ((INT32) 12299) /* FIX(1.501321110) */ +#define FIX_1_847759065 ((INT32) 15137) /* FIX(1.847759065) */ +#define FIX_1_961570560 ((INT32) 16069) /* FIX(1.961570560) */ +#define FIX_2_053119869 ((INT32) 16819) /* FIX(2.053119869) */ +#define FIX_2_562915447 ((INT32) 20995) /* FIX(2.562915447) */ +#define FIX_3_072711026 ((INT32) 25172) /* FIX(3.072711026) */ +#else +#define FIX_0_298631336 FIX(0.298631336) +#define FIX_0_390180644 FIX(0.390180644) +#define FIX_0_541196100 FIX(0.541196100) +#define FIX_0_765366865 FIX(0.765366865) +#define FIX_0_899976223 FIX(0.899976223) +#define FIX_1_175875602 FIX(1.175875602) +#define FIX_1_501321110 FIX(1.501321110) +#define FIX_1_847759065 FIX(1.847759065) +#define FIX_1_961570560 FIX(1.961570560) +#define FIX_2_053119869 FIX(2.053119869) +#define FIX_2_562915447 FIX(2.562915447) +#define FIX_3_072711026 FIX(3.072711026) +#endif + + +/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result. + * For 8-bit samples with the recommended scaling, all the variable + * and constant values involved are no more than 16 bits wide, so a + * 16x16->32 bit multiply can be used instead of a full 32x32 multiply. + * For 12-bit samples, a full 32-bit multiplication will be needed. + */ + +#if BITS_IN_JSAMPLE == 8 +#define MULTIPLY(var,const) MULTIPLY16C16(var,const) +#else +#define MULTIPLY(var,const) ((var) * (const)) +#endif + + +/* Dequantize a coefficient by multiplying it by the multiplier-table + * entry; produce an int result. In this module, both inputs and result + * are 16 bits or less, so either int or short multiply will work. + */ + +#define DEQUANTIZE(coef,quantval) (((ISLOW_MULT_TYPE) (coef)) * (quantval)) + + +/* + * Perform dequantization and inverse DCT on one block of coefficients. + */ + +GLOBAL(void) +jpeg_idct_islow (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3; + INT32 tmp10, tmp11, tmp12, tmp13; + INT32 z1, z2, z3, z4, z5; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[DCTSIZE2]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + /* Note results are scaled up by sqrt(8) compared to a true IDCT; */ + /* furthermore, we scale the results by 2**PASS1_BITS. */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = DCTSIZE; ctr > 0; ctr--) { + /* Due to quantization, we will usually find that many of the input + * coefficients are zero, especially the AC terms. We can exploit this + * by short-circuiting the IDCT calculation for any column in which all + * the AC terms are zero. In that case each output is equal to the + * DC coefficient (with scale factor as needed). + * With typical images and quantization tables, half or more of the + * column DCT calculations can be simplified this way. + */ + + if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 && + inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 && + inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 && + inptr[DCTSIZE*7] == 0) { + /* AC terms all zero */ + int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS; + + wsptr[DCTSIZE*0] = dcval; + wsptr[DCTSIZE*1] = dcval; + wsptr[DCTSIZE*2] = dcval; + wsptr[DCTSIZE*3] = dcval; + wsptr[DCTSIZE*4] = dcval; + wsptr[DCTSIZE*5] = dcval; + wsptr[DCTSIZE*6] = dcval; + wsptr[DCTSIZE*7] = dcval; + + inptr++; /* advance pointers to next column */ + quantptr++; + wsptr++; + continue; + } + + /* Even part: reverse the even part of the forward DCT. */ + /* The rotator is sqrt(2)*c(-6). */ + + z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + z1 = MULTIPLY(z2 + z3, FIX_0_541196100); + tmp2 = z1 + MULTIPLY(z3, - FIX_1_847759065); + tmp3 = z1 + MULTIPLY(z2, FIX_0_765366865); + + z2 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + z3 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + + tmp0 = (z2 + z3) << CONST_BITS; + tmp1 = (z2 - z3) << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + /* Odd part per figure 8; the matrix is unitary and hence its + * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. + */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + tmp1 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + tmp2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + tmp3 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + + z1 = tmp0 + tmp3; + z2 = tmp1 + tmp2; + z3 = tmp0 + tmp2; + z4 = tmp1 + tmp3; + z5 = MULTIPLY(z3 + z4, FIX_1_175875602); /* sqrt(2) * c3 */ + + tmp0 = MULTIPLY(tmp0, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */ + tmp1 = MULTIPLY(tmp1, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */ + tmp2 = MULTIPLY(tmp2, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */ + tmp3 = MULTIPLY(tmp3, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */ + z1 = MULTIPLY(z1, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */ + z2 = MULTIPLY(z2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */ + z3 = MULTIPLY(z3, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */ + z4 = MULTIPLY(z4, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */ + + z3 += z5; + z4 += z5; + + tmp0 += z1 + z3; + tmp1 += z2 + z4; + tmp2 += z2 + z3; + tmp3 += z1 + z4; + + /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ + + wsptr[DCTSIZE*0] = (int) DESCALE(tmp10 + tmp3, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*7] = (int) DESCALE(tmp10 - tmp3, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*1] = (int) DESCALE(tmp11 + tmp2, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*6] = (int) DESCALE(tmp11 - tmp2, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*2] = (int) DESCALE(tmp12 + tmp1, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*5] = (int) DESCALE(tmp12 - tmp1, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*3] = (int) DESCALE(tmp13 + tmp0, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*4] = (int) DESCALE(tmp13 - tmp0, CONST_BITS-PASS1_BITS); + + inptr++; /* advance pointers to next column */ + quantptr++; + wsptr++; + } + + /* Pass 2: process rows from work array, store into output array. */ + /* Note that we must descale the results by a factor of 8 == 2**3, */ + /* and also undo the PASS1_BITS scaling. */ + + wsptr = workspace; + for (ctr = 0; ctr < DCTSIZE; ctr++) { + outptr = output_buf[ctr] + output_col; + /* Rows of zeroes can be exploited in the same way as we did with columns. + * However, the column calculation has created many nonzero AC terms, so + * the simplification applies less often (typically 5% to 10% of the time). + * On machines with very fast multiplication, it's possible that the + * test takes more time than it's worth. In that case this section + * may be commented out. + */ + +#ifndef NO_ZERO_ROW_TEST + if (wsptr[1] == 0 && wsptr[2] == 0 && wsptr[3] == 0 && wsptr[4] == 0 && + wsptr[5] == 0 && wsptr[6] == 0 && wsptr[7] == 0) { + /* AC terms all zero */ + JSAMPLE dcval = range_limit[(int) DESCALE((INT32) wsptr[0], PASS1_BITS+3) + & RANGE_MASK]; + + outptr[0] = dcval; + outptr[1] = dcval; + outptr[2] = dcval; + outptr[3] = dcval; + outptr[4] = dcval; + outptr[5] = dcval; + outptr[6] = dcval; + outptr[7] = dcval; + + wsptr += DCTSIZE; /* advance pointer to next row */ + continue; + } +#endif + + /* Even part: reverse the even part of the forward DCT. */ + /* The rotator is sqrt(2)*c(-6). */ + + z2 = (INT32) wsptr[2]; + z3 = (INT32) wsptr[6]; + + z1 = MULTIPLY(z2 + z3, FIX_0_541196100); + tmp2 = z1 + MULTIPLY(z3, - FIX_1_847759065); + tmp3 = z1 + MULTIPLY(z2, FIX_0_765366865); + + tmp0 = ((INT32) wsptr[0] + (INT32) wsptr[4]) << CONST_BITS; + tmp1 = ((INT32) wsptr[0] - (INT32) wsptr[4]) << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + /* Odd part per figure 8; the matrix is unitary and hence its + * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. + */ + + tmp0 = (INT32) wsptr[7]; + tmp1 = (INT32) wsptr[5]; + tmp2 = (INT32) wsptr[3]; + tmp3 = (INT32) wsptr[1]; + + z1 = tmp0 + tmp3; + z2 = tmp1 + tmp2; + z3 = tmp0 + tmp2; + z4 = tmp1 + tmp3; + z5 = MULTIPLY(z3 + z4, FIX_1_175875602); /* sqrt(2) * c3 */ + + tmp0 = MULTIPLY(tmp0, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */ + tmp1 = MULTIPLY(tmp1, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */ + tmp2 = MULTIPLY(tmp2, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */ + tmp3 = MULTIPLY(tmp3, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */ + z1 = MULTIPLY(z1, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */ + z2 = MULTIPLY(z2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */ + z3 = MULTIPLY(z3, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */ + z4 = MULTIPLY(z4, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */ + + z3 += z5; + z4 += z5; + + tmp0 += z1 + z3; + tmp1 += z2 + z4; + tmp2 += z2 + z3; + tmp3 += z1 + z4; + + /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ + + outptr[0] = range_limit[(int) DESCALE(tmp10 + tmp3, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[7] = range_limit[(int) DESCALE(tmp10 - tmp3, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) DESCALE(tmp11 + tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[6] = range_limit[(int) DESCALE(tmp11 - tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) DESCALE(tmp12 + tmp1, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) DESCALE(tmp12 - tmp1, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) DESCALE(tmp13 + tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) DESCALE(tmp13 - tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += DCTSIZE; /* advance pointer to next row */ + } +} + +#endif /* DCT_ISLOW_SUPPORTED */ diff --git a/mk4/modimage/jpeg-6b/jidctred.c b/mk4/modimage/jpeg-6b/jidctred.c new file mode 100644 index 0000000..421f3c7 --- /dev/null +++ b/mk4/modimage/jpeg-6b/jidctred.c @@ -0,0 +1,398 @@ +/* + * jidctred.c + * + * Copyright (C) 1994-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains inverse-DCT routines that produce reduced-size output: + * either 4x4, 2x2, or 1x1 pixels from an 8x8 DCT block. + * + * The implementation is based on the Loeffler, Ligtenberg and Moschytz (LL&M) + * algorithm used in jidctint.c. We simply replace each 8-to-8 1-D IDCT step + * with an 8-to-4 step that produces the four averages of two adjacent outputs + * (or an 8-to-2 step producing two averages of four outputs, for 2x2 output). + * These steps were derived by computing the corresponding values at the end + * of the normal LL&M code, then simplifying as much as possible. + * + * 1x1 is trivial: just take the DC coefficient divided by 8. + * + * See jidctint.c for additional comments. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + +#ifdef IDCT_SCALING_SUPPORTED + + +/* + * This module is specialized to the case DCTSIZE = 8. + */ + +#if DCTSIZE != 8 + Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ +#endif + + +/* Scaling is the same as in jidctint.c. */ + +#if BITS_IN_JSAMPLE == 8 +#define CONST_BITS 13 +#define PASS1_BITS 2 +#else +#define CONST_BITS 13 +#define PASS1_BITS 1 /* lose a little precision to avoid overflow */ +#endif + +/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus + * causing a lot of useless floating-point operations at run time. + * To get around this we use the following pre-calculated constants. + * If you change CONST_BITS you may want to add appropriate values. + * (With a reasonable C compiler, you can just rely on the FIX() macro...) + */ + +#if CONST_BITS == 13 +#define FIX_0_211164243 ((INT32) 1730) /* FIX(0.211164243) */ +#define FIX_0_509795579 ((INT32) 4176) /* FIX(0.509795579) */ +#define FIX_0_601344887 ((INT32) 4926) /* FIX(0.601344887) */ +#define FIX_0_720959822 ((INT32) 5906) /* FIX(0.720959822) */ +#define FIX_0_765366865 ((INT32) 6270) /* FIX(0.765366865) */ +#define FIX_0_850430095 ((INT32) 6967) /* FIX(0.850430095) */ +#define FIX_0_899976223 ((INT32) 7373) /* FIX(0.899976223) */ +#define FIX_1_061594337 ((INT32) 8697) /* FIX(1.061594337) */ +#define FIX_1_272758580 ((INT32) 10426) /* FIX(1.272758580) */ +#define FIX_1_451774981 ((INT32) 11893) /* FIX(1.451774981) */ +#define FIX_1_847759065 ((INT32) 15137) /* FIX(1.847759065) */ +#define FIX_2_172734803 ((INT32) 17799) /* FIX(2.172734803) */ +#define FIX_2_562915447 ((INT32) 20995) /* FIX(2.562915447) */ +#define FIX_3_624509785 ((INT32) 29692) /* FIX(3.624509785) */ +#else +#define FIX_0_211164243 FIX(0.211164243) +#define FIX_0_509795579 FIX(0.509795579) +#define FIX_0_601344887 FIX(0.601344887) +#define FIX_0_720959822 FIX(0.720959822) +#define FIX_0_765366865 FIX(0.765366865) +#define FIX_0_850430095 FIX(0.850430095) +#define FIX_0_899976223 FIX(0.899976223) +#define FIX_1_061594337 FIX(1.061594337) +#define FIX_1_272758580 FIX(1.272758580) +#define FIX_1_451774981 FIX(1.451774981) +#define FIX_1_847759065 FIX(1.847759065) +#define FIX_2_172734803 FIX(2.172734803) +#define FIX_2_562915447 FIX(2.562915447) +#define FIX_3_624509785 FIX(3.624509785) +#endif + + +/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result. + * For 8-bit samples with the recommended scaling, all the variable + * and constant values involved are no more than 16 bits wide, so a + * 16x16->32 bit multiply can be used instead of a full 32x32 multiply. + * For 12-bit samples, a full 32-bit multiplication will be needed. + */ + +#if BITS_IN_JSAMPLE == 8 +#define MULTIPLY(var,const) MULTIPLY16C16(var,const) +#else +#define MULTIPLY(var,const) ((var) * (const)) +#endif + + +/* Dequantize a coefficient by multiplying it by the multiplier-table + * entry; produce an int result. In this module, both inputs and result + * are 16 bits or less, so either int or short multiply will work. + */ + +#define DEQUANTIZE(coef,quantval) (((ISLOW_MULT_TYPE) (coef)) * (quantval)) + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a reduced-size 4x4 output block. + */ + +GLOBAL(void) +jpeg_idct_4x4 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp0, tmp2, tmp10, tmp12; + INT32 z1, z2, z3, z4; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[DCTSIZE*4]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = DCTSIZE; ctr > 0; inptr++, quantptr++, wsptr++, ctr--) { + /* Don't bother to process column 4, because second pass won't use it */ + if (ctr == DCTSIZE-4) + continue; + if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 && + inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*5] == 0 && + inptr[DCTSIZE*6] == 0 && inptr[DCTSIZE*7] == 0) { + /* AC terms all zero; we need not examine term 4 for 4x4 output */ + int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS; + + wsptr[DCTSIZE*0] = dcval; + wsptr[DCTSIZE*1] = dcval; + wsptr[DCTSIZE*2] = dcval; + wsptr[DCTSIZE*3] = dcval; + + continue; + } + + /* Even part */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp0 <<= (CONST_BITS+1); + + z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + tmp2 = MULTIPLY(z2, FIX_1_847759065) + MULTIPLY(z3, - FIX_0_765366865); + + tmp10 = tmp0 + tmp2; + tmp12 = tmp0 - tmp2; + + /* Odd part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + z2 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + z3 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + z4 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + + tmp0 = MULTIPLY(z1, - FIX_0_211164243) /* sqrt(2) * (c3-c1) */ + + MULTIPLY(z2, FIX_1_451774981) /* sqrt(2) * (c3+c7) */ + + MULTIPLY(z3, - FIX_2_172734803) /* sqrt(2) * (-c1-c5) */ + + MULTIPLY(z4, FIX_1_061594337); /* sqrt(2) * (c5+c7) */ + + tmp2 = MULTIPLY(z1, - FIX_0_509795579) /* sqrt(2) * (c7-c5) */ + + MULTIPLY(z2, - FIX_0_601344887) /* sqrt(2) * (c5-c1) */ + + MULTIPLY(z3, FIX_0_899976223) /* sqrt(2) * (c3-c7) */ + + MULTIPLY(z4, FIX_2_562915447); /* sqrt(2) * (c1+c3) */ + + /* Final output stage */ + + wsptr[DCTSIZE*0] = (int) DESCALE(tmp10 + tmp2, CONST_BITS-PASS1_BITS+1); + wsptr[DCTSIZE*3] = (int) DESCALE(tmp10 - tmp2, CONST_BITS-PASS1_BITS+1); + wsptr[DCTSIZE*1] = (int) DESCALE(tmp12 + tmp0, CONST_BITS-PASS1_BITS+1); + wsptr[DCTSIZE*2] = (int) DESCALE(tmp12 - tmp0, CONST_BITS-PASS1_BITS+1); + } + + /* Pass 2: process 4 rows from work array, store into output array. */ + + wsptr = workspace; + for (ctr = 0; ctr < 4; ctr++) { + outptr = output_buf[ctr] + output_col; + /* It's not clear whether a zero row test is worthwhile here ... */ + +#ifndef NO_ZERO_ROW_TEST + if (wsptr[1] == 0 && wsptr[2] == 0 && wsptr[3] == 0 && + wsptr[5] == 0 && wsptr[6] == 0 && wsptr[7] == 0) { + /* AC terms all zero */ + JSAMPLE dcval = range_limit[(int) DESCALE((INT32) wsptr[0], PASS1_BITS+3) + & RANGE_MASK]; + + outptr[0] = dcval; + outptr[1] = dcval; + outptr[2] = dcval; + outptr[3] = dcval; + + wsptr += DCTSIZE; /* advance pointer to next row */ + continue; + } +#endif + + /* Even part */ + + tmp0 = ((INT32) wsptr[0]) << (CONST_BITS+1); + + tmp2 = MULTIPLY((INT32) wsptr[2], FIX_1_847759065) + + MULTIPLY((INT32) wsptr[6], - FIX_0_765366865); + + tmp10 = tmp0 + tmp2; + tmp12 = tmp0 - tmp2; + + /* Odd part */ + + z1 = (INT32) wsptr[7]; + z2 = (INT32) wsptr[5]; + z3 = (INT32) wsptr[3]; + z4 = (INT32) wsptr[1]; + + tmp0 = MULTIPLY(z1, - FIX_0_211164243) /* sqrt(2) * (c3-c1) */ + + MULTIPLY(z2, FIX_1_451774981) /* sqrt(2) * (c3+c7) */ + + MULTIPLY(z3, - FIX_2_172734803) /* sqrt(2) * (-c1-c5) */ + + MULTIPLY(z4, FIX_1_061594337); /* sqrt(2) * (c5+c7) */ + + tmp2 = MULTIPLY(z1, - FIX_0_509795579) /* sqrt(2) * (c7-c5) */ + + MULTIPLY(z2, - FIX_0_601344887) /* sqrt(2) * (c5-c1) */ + + MULTIPLY(z3, FIX_0_899976223) /* sqrt(2) * (c3-c7) */ + + MULTIPLY(z4, FIX_2_562915447); /* sqrt(2) * (c1+c3) */ + + /* Final output stage */ + + outptr[0] = range_limit[(int) DESCALE(tmp10 + tmp2, + CONST_BITS+PASS1_BITS+3+1) + & RANGE_MASK]; + outptr[3] = range_limit[(int) DESCALE(tmp10 - tmp2, + CONST_BITS+PASS1_BITS+3+1) + & RANGE_MASK]; + outptr[1] = range_limit[(int) DESCALE(tmp12 + tmp0, + CONST_BITS+PASS1_BITS+3+1) + & RANGE_MASK]; + outptr[2] = range_limit[(int) DESCALE(tmp12 - tmp0, + CONST_BITS+PASS1_BITS+3+1) + & RANGE_MASK]; + + wsptr += DCTSIZE; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a reduced-size 2x2 output block. + */ + +GLOBAL(void) +jpeg_idct_2x2 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp0, tmp10, z1; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[DCTSIZE*2]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = DCTSIZE; ctr > 0; inptr++, quantptr++, wsptr++, ctr--) { + /* Don't bother to process columns 2,4,6 */ + if (ctr == DCTSIZE-2 || ctr == DCTSIZE-4 || ctr == DCTSIZE-6) + continue; + if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*3] == 0 && + inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*7] == 0) { + /* AC terms all zero; we need not examine terms 2,4,6 for 2x2 output */ + int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS; + + wsptr[DCTSIZE*0] = dcval; + wsptr[DCTSIZE*1] = dcval; + + continue; + } + + /* Even part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp10 = z1 << (CONST_BITS+2); + + /* Odd part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + tmp0 = MULTIPLY(z1, - FIX_0_720959822); /* sqrt(2) * (c7-c5+c3-c1) */ + z1 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + tmp0 += MULTIPLY(z1, FIX_0_850430095); /* sqrt(2) * (-c1+c3+c5+c7) */ + z1 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + tmp0 += MULTIPLY(z1, - FIX_1_272758580); /* sqrt(2) * (-c1+c3-c5-c7) */ + z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + tmp0 += MULTIPLY(z1, FIX_3_624509785); /* sqrt(2) * (c1+c3+c5+c7) */ + + /* Final output stage */ + + wsptr[DCTSIZE*0] = (int) DESCALE(tmp10 + tmp0, CONST_BITS-PASS1_BITS+2); + wsptr[DCTSIZE*1] = (int) DESCALE(tmp10 - tmp0, CONST_BITS-PASS1_BITS+2); + } + + /* Pass 2: process 2 rows from work array, store into output array. */ + + wsptr = workspace; + for (ctr = 0; ctr < 2; ctr++) { + outptr = output_buf[ctr] + output_col; + /* It's not clear whether a zero row test is worthwhile here ... */ + +#ifndef NO_ZERO_ROW_TEST + if (wsptr[1] == 0 && wsptr[3] == 0 && wsptr[5] == 0 && wsptr[7] == 0) { + /* AC terms all zero */ + JSAMPLE dcval = range_limit[(int) DESCALE((INT32) wsptr[0], PASS1_BITS+3) + & RANGE_MASK]; + + outptr[0] = dcval; + outptr[1] = dcval; + + wsptr += DCTSIZE; /* advance pointer to next row */ + continue; + } +#endif + + /* Even part */ + + tmp10 = ((INT32) wsptr[0]) << (CONST_BITS+2); + + /* Odd part */ + + tmp0 = MULTIPLY((INT32) wsptr[7], - FIX_0_720959822) /* sqrt(2) * (c7-c5+c3-c1) */ + + MULTIPLY((INT32) wsptr[5], FIX_0_850430095) /* sqrt(2) * (-c1+c3+c5+c7) */ + + MULTIPLY((INT32) wsptr[3], - FIX_1_272758580) /* sqrt(2) * (-c1+c3-c5-c7) */ + + MULTIPLY((INT32) wsptr[1], FIX_3_624509785); /* sqrt(2) * (c1+c3+c5+c7) */ + + /* Final output stage */ + + outptr[0] = range_limit[(int) DESCALE(tmp10 + tmp0, + CONST_BITS+PASS1_BITS+3+2) + & RANGE_MASK]; + outptr[1] = range_limit[(int) DESCALE(tmp10 - tmp0, + CONST_BITS+PASS1_BITS+3+2) + & RANGE_MASK]; + + wsptr += DCTSIZE; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a reduced-size 1x1 output block. + */ + +GLOBAL(void) +jpeg_idct_1x1 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + int dcval; + ISLOW_MULT_TYPE * quantptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + SHIFT_TEMPS + + /* We hardly need an inverse DCT routine for this: just take the + * average pixel value, which is one-eighth of the DC coefficient. + */ + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + dcval = DEQUANTIZE(coef_block[0], quantptr[0]); + dcval = (int) DESCALE((INT32) dcval, 3); + + output_buf[0][output_col] = range_limit[dcval & RANGE_MASK]; +} + +#endif /* IDCT_SCALING_SUPPORTED */ diff --git a/mk4/modimage/jpeg-6b/jinclude.h b/mk4/modimage/jpeg-6b/jinclude.h new file mode 100644 index 0000000..0a4f151 --- /dev/null +++ b/mk4/modimage/jpeg-6b/jinclude.h @@ -0,0 +1,91 @@ +/* + * jinclude.h + * + * Copyright (C) 1991-1994, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file exists to provide a single place to fix any problems with + * including the wrong system include files. (Common problems are taken + * care of by the standard jconfig symbols, but on really weird systems + * you may have to edit this file.) + * + * NOTE: this file is NOT intended to be included by applications using the + * JPEG library. Most applications need only include jpeglib.h. + */ + + +/* Include auto-config file to find out which system include files we need. */ + +#include "jconfig.h" /* auto configuration options */ +#define JCONFIG_INCLUDED /* so that jpeglib.h doesn't do it again */ + +/* + * We need the NULL macro and size_t typedef. + * On an ANSI-conforming system it is sufficient to include . + * Otherwise, we get them from or ; we may have to + * pull in as well. + * Note that the core JPEG library does not require ; + * only the default error handler and data source/destination modules do. + * But we must pull it in because of the references to FILE in jpeglib.h. + * You can remove those references if you want to compile without . + */ + +#ifdef HAVE_STDDEF_H +#include +#endif + +#ifdef HAVE_STDLIB_H +#include +#endif + +#ifdef NEED_SYS_TYPES_H +#include +#endif + +#include + +/* + * We need memory copying and zeroing functions, plus strncpy(). + * ANSI and System V implementations declare these in . + * BSD doesn't have the mem() functions, but it does have bcopy()/bzero(). + * Some systems may declare memset and memcpy in . + * + * NOTE: we assume the size parameters to these functions are of type size_t. + * Change the casts in these macros if not! + */ + +#ifdef NEED_BSD_STRINGS + +#include +#define MEMZERO(target,size) bzero((void *)(target), (size_t)(size)) +#define MEMCOPY(dest,src,size) bcopy((const void *)(src), (void *)(dest), (size_t)(size)) + +#else /* not BSD, assume ANSI/SysV string lib */ + +#include +#define MEMZERO(target,size) memset((void *)(target), 0, (size_t)(size)) +#define MEMCOPY(dest,src,size) memcpy((void *)(dest), (const void *)(src), (size_t)(size)) + +#endif + +/* + * In ANSI C, and indeed any rational implementation, size_t is also the + * type returned by sizeof(). However, it seems there are some irrational + * implementations out there, in which sizeof() returns an int even though + * size_t is defined as long or unsigned long. To ensure consistent results + * we always use this SIZEOF() macro in place of using sizeof() directly. + */ + +#define SIZEOF(object) ((size_t) sizeof(object)) + +/* + * The modules that use fread() and fwrite() always invoke them through + * these macros. On some systems you may need to twiddle the argument casts. + * CAUTION: argument order is different from underlying functions! + */ + +#define JFREAD(file,buf,sizeofbuf) \ + ((size_t) fread((void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) +#define JFWRITE(file,buf,sizeofbuf) \ + ((size_t) fwrite((const void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) diff --git a/mk4/modimage/jpeg-6b/jmemansi.c b/mk4/modimage/jpeg-6b/jmemansi.c new file mode 100644 index 0000000..2d93e49 --- /dev/null +++ b/mk4/modimage/jpeg-6b/jmemansi.c @@ -0,0 +1,167 @@ +/* + * jmemansi.c + * + * Copyright (C) 1992-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file provides a simple generic implementation of the system- + * dependent portion of the JPEG memory manager. This implementation + * assumes that you have the ANSI-standard library routine tmpfile(). + * Also, the problem of determining the amount of memory available + * is shoved onto the user. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jmemsys.h" /* import the system-dependent declarations */ + +#ifndef HAVE_STDLIB_H /* should declare malloc(),free() */ +extern void * malloc JPP((size_t size)); +extern void free JPP((void *ptr)); +#endif + +#ifndef SEEK_SET /* pre-ANSI systems may not define this; */ +#define SEEK_SET 0 /* if not, assume 0 is correct */ +#endif + + +/* + * Memory allocation and freeing are controlled by the regular library + * routines malloc() and free(). + */ + +GLOBAL(void *) +jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject) +{ + return (void *) malloc(sizeofobject); +} + +GLOBAL(void) +jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject) +{ + free(object); +} + + +/* + * "Large" objects are treated the same as "small" ones. + * NB: although we include FAR keywords in the routine declarations, + * this file won't actually work in 80x86 small/medium model; at least, + * you probably won't be able to process useful-size images in only 64KB. + */ + +GLOBAL(void FAR *) +jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject) +{ + return (void FAR *) malloc(sizeofobject); +} + +GLOBAL(void) +jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject) +{ + free(object); +} + + +/* + * This routine computes the total memory space available for allocation. + * It's impossible to do this in a portable way; our current solution is + * to make the user tell us (with a default value set at compile time). + * If you can actually get the available space, it's a good idea to subtract + * a slop factor of 5% or so. + */ + +#ifndef DEFAULT_MAX_MEM /* so can override from makefile */ +#define DEFAULT_MAX_MEM 1000000L /* default: one megabyte */ +#endif + +GLOBAL(long) +jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed, + long max_bytes_needed, long already_allocated) +{ + return cinfo->mem->max_memory_to_use - already_allocated; +} + + +/* + * Backing store (temporary file) management. + * Backing store objects are only used when the value returned by + * jpeg_mem_available is less than the total space needed. You can dispense + * with these routines if you have plenty of virtual memory; see jmemnobs.c. + */ + + +METHODDEF(void) +read_backing_store (j_common_ptr cinfo, backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count) +{ + if (fseek(info->temp_file, file_offset, SEEK_SET)) + ERREXIT(cinfo, JERR_TFILE_SEEK); + if (JFREAD(info->temp_file, buffer_address, byte_count) + != (size_t) byte_count) + ERREXIT(cinfo, JERR_TFILE_READ); +} + + +METHODDEF(void) +write_backing_store (j_common_ptr cinfo, backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count) +{ + if (fseek(info->temp_file, file_offset, SEEK_SET)) + ERREXIT(cinfo, JERR_TFILE_SEEK); + if (JFWRITE(info->temp_file, buffer_address, byte_count) + != (size_t) byte_count) + ERREXIT(cinfo, JERR_TFILE_WRITE); +} + + +METHODDEF(void) +close_backing_store (j_common_ptr cinfo, backing_store_ptr info) +{ + fclose(info->temp_file); + /* Since this implementation uses tmpfile() to create the file, + * no explicit file deletion is needed. + */ +} + + +/* + * Initial opening of a backing-store object. + * + * This version uses tmpfile(), which constructs a suitable file name + * behind the scenes. We don't have to use info->temp_name[] at all; + * indeed, we can't even find out the actual name of the temp file. + */ + +GLOBAL(void) +jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info, + long total_bytes_needed) +{ + if ((info->temp_file = tmpfile()) == NULL) + ERREXITS(cinfo, JERR_TFILE_CREATE, ""); + info->read_backing_store = read_backing_store; + info->write_backing_store = write_backing_store; + info->close_backing_store = close_backing_store; +} + + +/* + * These routines take care of any system-dependent initialization and + * cleanup required. + */ + +GLOBAL(long) +jpeg_mem_init (j_common_ptr cinfo) +{ + return DEFAULT_MAX_MEM; /* default for max_memory_to_use */ +} + +GLOBAL(void) +jpeg_mem_term (j_common_ptr cinfo) +{ + /* no work */ +} diff --git a/mk4/modimage/jpeg-6b/jmemdos.c b/mk4/modimage/jpeg-6b/jmemdos.c new file mode 100644 index 0000000..60b45c6 --- /dev/null +++ b/mk4/modimage/jpeg-6b/jmemdos.c @@ -0,0 +1,638 @@ +/* + * jmemdos.c + * + * Copyright (C) 1992-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file provides an MS-DOS-compatible implementation of the system- + * dependent portion of the JPEG memory manager. Temporary data can be + * stored in extended or expanded memory as well as in regular DOS files. + * + * If you use this file, you must be sure that NEED_FAR_POINTERS is defined + * if you compile in a small-data memory model; it should NOT be defined if + * you use a large-data memory model. This file is not recommended if you + * are using a flat-memory-space 386 environment such as DJGCC or Watcom C. + * Also, this code will NOT work if struct fields are aligned on greater than + * 2-byte boundaries. + * + * Based on code contributed by Ge' Weijers. + */ + +/* + * If you have both extended and expanded memory, you may want to change the + * order in which they are tried in jopen_backing_store. On a 286 machine + * expanded memory is usually faster, since extended memory access involves + * an expensive protected-mode-and-back switch. On 386 and better, extended + * memory is usually faster. As distributed, the code tries extended memory + * first (what? not everyone has a 386? :-). + * + * You can disable use of extended/expanded memory entirely by altering these + * definitions or overriding them from the Makefile (eg, -DEMS_SUPPORTED=0). + */ + +#ifndef XMS_SUPPORTED +#define XMS_SUPPORTED 1 +#endif +#ifndef EMS_SUPPORTED +#define EMS_SUPPORTED 1 +#endif + + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jmemsys.h" /* import the system-dependent declarations */ + +#ifndef HAVE_STDLIB_H /* should declare these */ +extern void * malloc JPP((size_t size)); +extern void free JPP((void *ptr)); +extern char * getenv JPP((const char * name)); +#endif + +#ifdef NEED_FAR_POINTERS + +#ifdef __TURBOC__ +/* These definitions work for Borland C (Turbo C) */ +#include /* need farmalloc(), farfree() */ +#define far_malloc(x) farmalloc(x) +#define far_free(x) farfree(x) +#else +/* These definitions work for Microsoft C and compatible compilers */ +#include /* need _fmalloc(), _ffree() */ +#define far_malloc(x) _fmalloc(x) +#define far_free(x) _ffree(x) +#endif + +#else /* not NEED_FAR_POINTERS */ + +#define far_malloc(x) malloc(x) +#define far_free(x) free(x) + +#endif /* NEED_FAR_POINTERS */ + +#ifdef DONT_USE_B_MODE /* define mode parameters for fopen() */ +#define READ_BINARY "r" +#else +#define READ_BINARY "rb" +#endif + +#ifndef USE_MSDOS_MEMMGR /* make sure user got configuration right */ + You forgot to define USE_MSDOS_MEMMGR in jconfig.h. /* deliberate syntax error */ +#endif + +#if MAX_ALLOC_CHUNK >= 65535L /* make sure jconfig.h got this right */ + MAX_ALLOC_CHUNK should be less than 64K. /* deliberate syntax error */ +#endif + + +/* + * Declarations for assembly-language support routines (see jmemdosa.asm). + * + * The functions are declared "far" as are all their pointer arguments; + * this ensures the assembly source code will work regardless of the + * compiler memory model. We assume "short" is 16 bits, "long" is 32. + */ + +typedef void far * XMSDRIVER; /* actually a pointer to code */ +typedef struct { /* registers for calling XMS driver */ + unsigned short ax, dx, bx; + void far * ds_si; + } XMScontext; +typedef struct { /* registers for calling EMS driver */ + unsigned short ax, dx, bx; + void far * ds_si; + } EMScontext; + +extern short far jdos_open JPP((short far * handle, char far * filename)); +extern short far jdos_close JPP((short handle)); +extern short far jdos_seek JPP((short handle, long offset)); +extern short far jdos_read JPP((short handle, void far * buffer, + unsigned short count)); +extern short far jdos_write JPP((short handle, void far * buffer, + unsigned short count)); +extern void far jxms_getdriver JPP((XMSDRIVER far *)); +extern void far jxms_calldriver JPP((XMSDRIVER, XMScontext far *)); +extern short far jems_available JPP((void)); +extern void far jems_calldriver JPP((EMScontext far *)); + + +/* + * Selection of a file name for a temporary file. + * This is highly system-dependent, and you may want to customize it. + */ + +static int next_file_num; /* to distinguish among several temp files */ + +LOCAL(void) +select_file_name (char * fname) +{ + const char * env; + char * ptr; + FILE * tfile; + + /* Keep generating file names till we find one that's not in use */ + for (;;) { + /* Get temp directory name from environment TMP or TEMP variable; + * if none, use "." + */ + if ((env = (const char *) getenv("TMP")) == NULL) + if ((env = (const char *) getenv("TEMP")) == NULL) + env = "."; + if (*env == '\0') /* null string means "." */ + env = "."; + ptr = fname; /* copy name to fname */ + while (*env != '\0') + *ptr++ = *env++; + if (ptr[-1] != '\\' && ptr[-1] != '/') + *ptr++ = '\\'; /* append backslash if not in env variable */ + /* Append a suitable file name */ + next_file_num++; /* advance counter */ + sprintf(ptr, "JPG%03d.TMP", next_file_num); + /* Probe to see if file name is already in use */ + if ((tfile = fopen(fname, READ_BINARY)) == NULL) + break; + fclose(tfile); /* oops, it's there; close tfile & try again */ + } +} + + +/* + * Near-memory allocation and freeing are controlled by the regular library + * routines malloc() and free(). + */ + +GLOBAL(void *) +jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject) +{ + return (void *) malloc(sizeofobject); +} + +GLOBAL(void) +jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject) +{ + free(object); +} + + +/* + * "Large" objects are allocated in far memory, if possible + */ + +GLOBAL(void FAR *) +jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject) +{ + return (void FAR *) far_malloc(sizeofobject); +} + +GLOBAL(void) +jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject) +{ + far_free(object); +} + + +/* + * This routine computes the total memory space available for allocation. + * It's impossible to do this in a portable way; our current solution is + * to make the user tell us (with a default value set at compile time). + * If you can actually get the available space, it's a good idea to subtract + * a slop factor of 5% or so. + */ + +#ifndef DEFAULT_MAX_MEM /* so can override from makefile */ +#define DEFAULT_MAX_MEM 300000L /* for total usage about 450K */ +#endif + +GLOBAL(long) +jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed, + long max_bytes_needed, long already_allocated) +{ + return cinfo->mem->max_memory_to_use - already_allocated; +} + + +/* + * Backing store (temporary file) management. + * Backing store objects are only used when the value returned by + * jpeg_mem_available is less than the total space needed. You can dispense + * with these routines if you have plenty of virtual memory; see jmemnobs.c. + */ + +/* + * For MS-DOS we support three types of backing storage: + * 1. Conventional DOS files. We access these by direct DOS calls rather + * than via the stdio package. This provides a bit better performance, + * but the real reason is that the buffers to be read or written are FAR. + * The stdio library for small-data memory models can't cope with that. + * 2. Extended memory, accessed per the XMS V2.0 specification. + * 3. Expanded memory, accessed per the LIM/EMS 4.0 specification. + * You'll need copies of those specs to make sense of the related code. + * The specs are available by Internet FTP from the SIMTEL archives + * (oak.oakland.edu and its various mirror sites). See files + * pub/msdos/microsoft/xms20.arc and pub/msdos/info/limems41.zip. + */ + + +/* + * Access methods for a DOS file. + */ + + +METHODDEF(void) +read_file_store (j_common_ptr cinfo, backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count) +{ + if (jdos_seek(info->handle.file_handle, file_offset)) + ERREXIT(cinfo, JERR_TFILE_SEEK); + /* Since MAX_ALLOC_CHUNK is less than 64K, byte_count will be too. */ + if (byte_count > 65535L) /* safety check */ + ERREXIT(cinfo, JERR_BAD_ALLOC_CHUNK); + if (jdos_read(info->handle.file_handle, buffer_address, + (unsigned short) byte_count)) + ERREXIT(cinfo, JERR_TFILE_READ); +} + + +METHODDEF(void) +write_file_store (j_common_ptr cinfo, backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count) +{ + if (jdos_seek(info->handle.file_handle, file_offset)) + ERREXIT(cinfo, JERR_TFILE_SEEK); + /* Since MAX_ALLOC_CHUNK is less than 64K, byte_count will be too. */ + if (byte_count > 65535L) /* safety check */ + ERREXIT(cinfo, JERR_BAD_ALLOC_CHUNK); + if (jdos_write(info->handle.file_handle, buffer_address, + (unsigned short) byte_count)) + ERREXIT(cinfo, JERR_TFILE_WRITE); +} + + +METHODDEF(void) +close_file_store (j_common_ptr cinfo, backing_store_ptr info) +{ + jdos_close(info->handle.file_handle); /* close the file */ + remove(info->temp_name); /* delete the file */ +/* If your system doesn't have remove(), try unlink() instead. + * remove() is the ANSI-standard name for this function, but + * unlink() was more common in pre-ANSI systems. + */ + TRACEMSS(cinfo, 1, JTRC_TFILE_CLOSE, info->temp_name); +} + + +LOCAL(boolean) +open_file_store (j_common_ptr cinfo, backing_store_ptr info, + long total_bytes_needed) +{ + short handle; + + select_file_name(info->temp_name); + if (jdos_open((short far *) & handle, (char far *) info->temp_name)) { + /* might as well exit since jpeg_open_backing_store will fail anyway */ + ERREXITS(cinfo, JERR_TFILE_CREATE, info->temp_name); + return FALSE; + } + info->handle.file_handle = handle; + info->read_backing_store = read_file_store; + info->write_backing_store = write_file_store; + info->close_backing_store = close_file_store; + TRACEMSS(cinfo, 1, JTRC_TFILE_OPEN, info->temp_name); + return TRUE; /* succeeded */ +} + + +/* + * Access methods for extended memory. + */ + +#if XMS_SUPPORTED + +static XMSDRIVER xms_driver; /* saved address of XMS driver */ + +typedef union { /* either long offset or real-mode pointer */ + long offset; + void far * ptr; + } XMSPTR; + +typedef struct { /* XMS move specification structure */ + long length; + XMSH src_handle; + XMSPTR src; + XMSH dst_handle; + XMSPTR dst; + } XMSspec; + +#define ODD(X) (((X) & 1L) != 0) + + +METHODDEF(void) +read_xms_store (j_common_ptr cinfo, backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count) +{ + XMScontext ctx; + XMSspec spec; + char endbuffer[2]; + + /* The XMS driver can't cope with an odd length, so handle the last byte + * specially if byte_count is odd. We don't expect this to be common. + */ + + spec.length = byte_count & (~ 1L); + spec.src_handle = info->handle.xms_handle; + spec.src.offset = file_offset; + spec.dst_handle = 0; + spec.dst.ptr = buffer_address; + + ctx.ds_si = (void far *) & spec; + ctx.ax = 0x0b00; /* EMB move */ + jxms_calldriver(xms_driver, (XMScontext far *) & ctx); + if (ctx.ax != 1) + ERREXIT(cinfo, JERR_XMS_READ); + + if (ODD(byte_count)) { + read_xms_store(cinfo, info, (void FAR *) endbuffer, + file_offset + byte_count - 1L, 2L); + ((char FAR *) buffer_address)[byte_count - 1L] = endbuffer[0]; + } +} + + +METHODDEF(void) +write_xms_store (j_common_ptr cinfo, backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count) +{ + XMScontext ctx; + XMSspec spec; + char endbuffer[2]; + + /* The XMS driver can't cope with an odd length, so handle the last byte + * specially if byte_count is odd. We don't expect this to be common. + */ + + spec.length = byte_count & (~ 1L); + spec.src_handle = 0; + spec.src.ptr = buffer_address; + spec.dst_handle = info->handle.xms_handle; + spec.dst.offset = file_offset; + + ctx.ds_si = (void far *) & spec; + ctx.ax = 0x0b00; /* EMB move */ + jxms_calldriver(xms_driver, (XMScontext far *) & ctx); + if (ctx.ax != 1) + ERREXIT(cinfo, JERR_XMS_WRITE); + + if (ODD(byte_count)) { + read_xms_store(cinfo, info, (void FAR *) endbuffer, + file_offset + byte_count - 1L, 2L); + endbuffer[0] = ((char FAR *) buffer_address)[byte_count - 1L]; + write_xms_store(cinfo, info, (void FAR *) endbuffer, + file_offset + byte_count - 1L, 2L); + } +} + + +METHODDEF(void) +close_xms_store (j_common_ptr cinfo, backing_store_ptr info) +{ + XMScontext ctx; + + ctx.dx = info->handle.xms_handle; + ctx.ax = 0x0a00; + jxms_calldriver(xms_driver, (XMScontext far *) & ctx); + TRACEMS1(cinfo, 1, JTRC_XMS_CLOSE, info->handle.xms_handle); + /* we ignore any error return from the driver */ +} + + +LOCAL(boolean) +open_xms_store (j_common_ptr cinfo, backing_store_ptr info, + long total_bytes_needed) +{ + XMScontext ctx; + + /* Get address of XMS driver */ + jxms_getdriver((XMSDRIVER far *) & xms_driver); + if (xms_driver == NULL) + return FALSE; /* no driver to be had */ + + /* Get version number, must be >= 2.00 */ + ctx.ax = 0x0000; + jxms_calldriver(xms_driver, (XMScontext far *) & ctx); + if (ctx.ax < (unsigned short) 0x0200) + return FALSE; + + /* Try to get space (expressed in kilobytes) */ + ctx.dx = (unsigned short) ((total_bytes_needed + 1023L) >> 10); + ctx.ax = 0x0900; + jxms_calldriver(xms_driver, (XMScontext far *) & ctx); + if (ctx.ax != 1) + return FALSE; + + /* Succeeded, save the handle and away we go */ + info->handle.xms_handle = ctx.dx; + info->read_backing_store = read_xms_store; + info->write_backing_store = write_xms_store; + info->close_backing_store = close_xms_store; + TRACEMS1(cinfo, 1, JTRC_XMS_OPEN, ctx.dx); + return TRUE; /* succeeded */ +} + +#endif /* XMS_SUPPORTED */ + + +/* + * Access methods for expanded memory. + */ + +#if EMS_SUPPORTED + +/* The EMS move specification structure requires word and long fields aligned + * at odd byte boundaries. Some compilers will align struct fields at even + * byte boundaries. While it's usually possible to force byte alignment, + * that causes an overall performance penalty and may pose problems in merging + * JPEG into a larger application. Instead we accept some rather dirty code + * here. Note this code would fail if the hardware did not allow odd-byte + * word & long accesses, but all 80x86 CPUs do. + */ + +typedef void far * EMSPTR; + +typedef union { /* EMS move specification structure */ + long length; /* It's easy to access first 4 bytes */ + char bytes[18]; /* Misaligned fields in here! */ + } EMSspec; + +/* Macros for accessing misaligned fields */ +#define FIELD_AT(spec,offset,type) (*((type *) &(spec.bytes[offset]))) +#define SRC_TYPE(spec) FIELD_AT(spec,4,char) +#define SRC_HANDLE(spec) FIELD_AT(spec,5,EMSH) +#define SRC_OFFSET(spec) FIELD_AT(spec,7,unsigned short) +#define SRC_PAGE(spec) FIELD_AT(spec,9,unsigned short) +#define SRC_PTR(spec) FIELD_AT(spec,7,EMSPTR) +#define DST_TYPE(spec) FIELD_AT(spec,11,char) +#define DST_HANDLE(spec) FIELD_AT(spec,12,EMSH) +#define DST_OFFSET(spec) FIELD_AT(spec,14,unsigned short) +#define DST_PAGE(spec) FIELD_AT(spec,16,unsigned short) +#define DST_PTR(spec) FIELD_AT(spec,14,EMSPTR) + +#define EMSPAGESIZE 16384L /* gospel, see the EMS specs */ + +#define HIBYTE(W) (((W) >> 8) & 0xFF) +#define LOBYTE(W) ((W) & 0xFF) + + +METHODDEF(void) +read_ems_store (j_common_ptr cinfo, backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count) +{ + EMScontext ctx; + EMSspec spec; + + spec.length = byte_count; + SRC_TYPE(spec) = 1; + SRC_HANDLE(spec) = info->handle.ems_handle; + SRC_PAGE(spec) = (unsigned short) (file_offset / EMSPAGESIZE); + SRC_OFFSET(spec) = (unsigned short) (file_offset % EMSPAGESIZE); + DST_TYPE(spec) = 0; + DST_HANDLE(spec) = 0; + DST_PTR(spec) = buffer_address; + + ctx.ds_si = (void far *) & spec; + ctx.ax = 0x5700; /* move memory region */ + jems_calldriver((EMScontext far *) & ctx); + if (HIBYTE(ctx.ax) != 0) + ERREXIT(cinfo, JERR_EMS_READ); +} + + +METHODDEF(void) +write_ems_store (j_common_ptr cinfo, backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count) +{ + EMScontext ctx; + EMSspec spec; + + spec.length = byte_count; + SRC_TYPE(spec) = 0; + SRC_HANDLE(spec) = 0; + SRC_PTR(spec) = buffer_address; + DST_TYPE(spec) = 1; + DST_HANDLE(spec) = info->handle.ems_handle; + DST_PAGE(spec) = (unsigned short) (file_offset / EMSPAGESIZE); + DST_OFFSET(spec) = (unsigned short) (file_offset % EMSPAGESIZE); + + ctx.ds_si = (void far *) & spec; + ctx.ax = 0x5700; /* move memory region */ + jems_calldriver((EMScontext far *) & ctx); + if (HIBYTE(ctx.ax) != 0) + ERREXIT(cinfo, JERR_EMS_WRITE); +} + + +METHODDEF(void) +close_ems_store (j_common_ptr cinfo, backing_store_ptr info) +{ + EMScontext ctx; + + ctx.ax = 0x4500; + ctx.dx = info->handle.ems_handle; + jems_calldriver((EMScontext far *) & ctx); + TRACEMS1(cinfo, 1, JTRC_EMS_CLOSE, info->handle.ems_handle); + /* we ignore any error return from the driver */ +} + + +LOCAL(boolean) +open_ems_store (j_common_ptr cinfo, backing_store_ptr info, + long total_bytes_needed) +{ + EMScontext ctx; + + /* Is EMS driver there? */ + if (! jems_available()) + return FALSE; + + /* Get status, make sure EMS is OK */ + ctx.ax = 0x4000; + jems_calldriver((EMScontext far *) & ctx); + if (HIBYTE(ctx.ax) != 0) + return FALSE; + + /* Get version, must be >= 4.0 */ + ctx.ax = 0x4600; + jems_calldriver((EMScontext far *) & ctx); + if (HIBYTE(ctx.ax) != 0 || LOBYTE(ctx.ax) < 0x40) + return FALSE; + + /* Try to allocate requested space */ + ctx.ax = 0x4300; + ctx.bx = (unsigned short) ((total_bytes_needed + EMSPAGESIZE-1L) / EMSPAGESIZE); + jems_calldriver((EMScontext far *) & ctx); + if (HIBYTE(ctx.ax) != 0) + return FALSE; + + /* Succeeded, save the handle and away we go */ + info->handle.ems_handle = ctx.dx; + info->read_backing_store = read_ems_store; + info->write_backing_store = write_ems_store; + info->close_backing_store = close_ems_store; + TRACEMS1(cinfo, 1, JTRC_EMS_OPEN, ctx.dx); + return TRUE; /* succeeded */ +} + +#endif /* EMS_SUPPORTED */ + + +/* + * Initial opening of a backing-store object. + */ + +GLOBAL(void) +jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info, + long total_bytes_needed) +{ + /* Try extended memory, then expanded memory, then regular file. */ +#if XMS_SUPPORTED + if (open_xms_store(cinfo, info, total_bytes_needed)) + return; +#endif +#if EMS_SUPPORTED + if (open_ems_store(cinfo, info, total_bytes_needed)) + return; +#endif + if (open_file_store(cinfo, info, total_bytes_needed)) + return; + ERREXITS(cinfo, JERR_TFILE_CREATE, ""); +} + + +/* + * These routines take care of any system-dependent initialization and + * cleanup required. + */ + +GLOBAL(long) +jpeg_mem_init (j_common_ptr cinfo) +{ + next_file_num = 0; /* initialize temp file name generator */ + return DEFAULT_MAX_MEM; /* default for max_memory_to_use */ +} + +GLOBAL(void) +jpeg_mem_term (j_common_ptr cinfo) +{ + /* Microsoft C, at least in v6.00A, will not successfully reclaim freed + * blocks of size > 32Kbytes unless we give it a kick in the rear, like so: + */ +#ifdef NEED_FHEAPMIN + _fheapmin(); +#endif +} diff --git a/mk4/modimage/jpeg-6b/jmemdosa.asm b/mk4/modimage/jpeg-6b/jmemdosa.asm new file mode 100644 index 0000000..ecd4372 --- /dev/null +++ b/mk4/modimage/jpeg-6b/jmemdosa.asm @@ -0,0 +1,379 @@ +; +; jmemdosa.asm +; +; Copyright (C) 1992, Thomas G. Lane. +; This file is part of the Independent JPEG Group's software. +; For conditions of distribution and use, see the accompanying README file. +; +; This file contains low-level interface routines to support the MS-DOS +; backing store manager (jmemdos.c). Routines are provided to access disk +; files through direct DOS calls, and to access XMS and EMS drivers. +; +; This file should assemble with Microsoft's MASM or any compatible +; assembler (including Borland's Turbo Assembler). If you haven't got +; a compatible assembler, better fall back to jmemansi.c or jmemname.c. +; +; To minimize dependence on the C compiler's register usage conventions, +; we save and restore all 8086 registers, even though most compilers only +; require SI,DI,DS to be preserved. Also, we use only 16-bit-wide return +; values, which everybody returns in AX. +; +; Based on code contributed by Ge' Weijers. +; + +JMEMDOSA_TXT segment byte public 'CODE' + + assume cs:JMEMDOSA_TXT + + public _jdos_open + public _jdos_close + public _jdos_seek + public _jdos_read + public _jdos_write + public _jxms_getdriver + public _jxms_calldriver + public _jems_available + public _jems_calldriver + +; +; short far jdos_open (short far * handle, char far * filename) +; +; Create and open a temporary file +; +_jdos_open proc far + push bp ; linkage + mov bp,sp + push si ; save all registers for safety + push di + push bx + push cx + push dx + push es + push ds + mov cx,0 ; normal file attributes + lds dx,dword ptr [bp+10] ; get filename pointer + mov ah,3ch ; create file + int 21h + jc open_err ; if failed, return error code + lds bx,dword ptr [bp+6] ; get handle pointer + mov word ptr [bx],ax ; save the handle + xor ax,ax ; return zero for OK +open_err: pop ds ; restore registers and exit + pop es + pop dx + pop cx + pop bx + pop di + pop si + pop bp + ret +_jdos_open endp + + +; +; short far jdos_close (short handle) +; +; Close the file handle +; +_jdos_close proc far + push bp ; linkage + mov bp,sp + push si ; save all registers for safety + push di + push bx + push cx + push dx + push es + push ds + mov bx,word ptr [bp+6] ; file handle + mov ah,3eh ; close file + int 21h + jc close_err ; if failed, return error code + xor ax,ax ; return zero for OK +close_err: pop ds ; restore registers and exit + pop es + pop dx + pop cx + pop bx + pop di + pop si + pop bp + ret +_jdos_close endp + + +; +; short far jdos_seek (short handle, long offset) +; +; Set file position +; +_jdos_seek proc far + push bp ; linkage + mov bp,sp + push si ; save all registers for safety + push di + push bx + push cx + push dx + push es + push ds + mov bx,word ptr [bp+6] ; file handle + mov dx,word ptr [bp+8] ; LS offset + mov cx,word ptr [bp+10] ; MS offset + mov ax,4200h ; absolute seek + int 21h + jc seek_err ; if failed, return error code + xor ax,ax ; return zero for OK +seek_err: pop ds ; restore registers and exit + pop es + pop dx + pop cx + pop bx + pop di + pop si + pop bp + ret +_jdos_seek endp + + +; +; short far jdos_read (short handle, void far * buffer, unsigned short count) +; +; Read from file +; +_jdos_read proc far + push bp ; linkage + mov bp,sp + push si ; save all registers for safety + push di + push bx + push cx + push dx + push es + push ds + mov bx,word ptr [bp+6] ; file handle + lds dx,dword ptr [bp+8] ; buffer address + mov cx,word ptr [bp+12] ; number of bytes + mov ah,3fh ; read file + int 21h + jc read_err ; if failed, return error code + cmp ax,word ptr [bp+12] ; make sure all bytes were read + je read_ok + mov ax,1 ; else return 1 for not OK + jmp short read_err +read_ok: xor ax,ax ; return zero for OK +read_err: pop ds ; restore registers and exit + pop es + pop dx + pop cx + pop bx + pop di + pop si + pop bp + ret +_jdos_read endp + + +; +; short far jdos_write (short handle, void far * buffer, unsigned short count) +; +; Write to file +; +_jdos_write proc far + push bp ; linkage + mov bp,sp + push si ; save all registers for safety + push di + push bx + push cx + push dx + push es + push ds + mov bx,word ptr [bp+6] ; file handle + lds dx,dword ptr [bp+8] ; buffer address + mov cx,word ptr [bp+12] ; number of bytes + mov ah,40h ; write file + int 21h + jc write_err ; if failed, return error code + cmp ax,word ptr [bp+12] ; make sure all bytes written + je write_ok + mov ax,1 ; else return 1 for not OK + jmp short write_err +write_ok: xor ax,ax ; return zero for OK +write_err: pop ds ; restore registers and exit + pop es + pop dx + pop cx + pop bx + pop di + pop si + pop bp + ret +_jdos_write endp + + +; +; void far jxms_getdriver (XMSDRIVER far *) +; +; Get the address of the XMS driver, or NULL if not available +; +_jxms_getdriver proc far + push bp ; linkage + mov bp,sp + push si ; save all registers for safety + push di + push bx + push cx + push dx + push es + push ds + mov ax,4300h ; call multiplex interrupt with + int 2fh ; a magic cookie, hex 4300 + cmp al,80h ; AL should contain hex 80 + je xmsavail + xor dx,dx ; no XMS driver available + xor ax,ax ; return a nil pointer + jmp short xmsavail_done +xmsavail: mov ax,4310h ; fetch driver address with + int 2fh ; another magic cookie + mov dx,es ; copy address to dx:ax + mov ax,bx +xmsavail_done: les bx,dword ptr [bp+6] ; get pointer to return value + mov word ptr es:[bx],ax + mov word ptr es:[bx+2],dx + pop ds ; restore registers and exit + pop es + pop dx + pop cx + pop bx + pop di + pop si + pop bp + ret +_jxms_getdriver endp + + +; +; void far jxms_calldriver (XMSDRIVER, XMScontext far *) +; +; The XMScontext structure contains values for the AX,DX,BX,SI,DS registers. +; These are loaded, the XMS call is performed, and the new values of the +; AX,DX,BX registers are written back to the context structure. +; +_jxms_calldriver proc far + push bp ; linkage + mov bp,sp + push si ; save all registers for safety + push di + push bx + push cx + push dx + push es + push ds + les bx,dword ptr [bp+10] ; get XMScontext pointer + mov ax,word ptr es:[bx] ; load registers + mov dx,word ptr es:[bx+2] + mov si,word ptr es:[bx+6] + mov ds,word ptr es:[bx+8] + mov bx,word ptr es:[bx+4] + call dword ptr [bp+6] ; call the driver + mov cx,bx ; save returned BX for a sec + les bx,dword ptr [bp+10] ; get XMScontext pointer + mov word ptr es:[bx],ax ; put back ax,dx,bx + mov word ptr es:[bx+2],dx + mov word ptr es:[bx+4],cx + pop ds ; restore registers and exit + pop es + pop dx + pop cx + pop bx + pop di + pop si + pop bp + ret +_jxms_calldriver endp + + +; +; short far jems_available (void) +; +; Have we got an EMS driver? (this comes straight from the EMS 4.0 specs) +; +_jems_available proc far + push si ; save all registers for safety + push di + push bx + push cx + push dx + push es + push ds + mov ax,3567h ; get interrupt vector 67h + int 21h + push cs + pop ds + mov di,000ah ; check offs 10 in returned seg + lea si,ASCII_device_name ; against literal string + mov cx,8 + cld + repe cmpsb + jne no_ems + mov ax,1 ; match, it's there + jmp short avail_done +no_ems: xor ax,ax ; it's not there +avail_done: pop ds ; restore registers and exit + pop es + pop dx + pop cx + pop bx + pop di + pop si + ret + +ASCII_device_name db "EMMXXXX0" + +_jems_available endp + + +; +; void far jems_calldriver (EMScontext far *) +; +; The EMScontext structure contains values for the AX,DX,BX,SI,DS registers. +; These are loaded, the EMS trap is performed, and the new values of the +; AX,DX,BX registers are written back to the context structure. +; +_jems_calldriver proc far + push bp ; linkage + mov bp,sp + push si ; save all registers for safety + push di + push bx + push cx + push dx + push es + push ds + les bx,dword ptr [bp+6] ; get EMScontext pointer + mov ax,word ptr es:[bx] ; load registers + mov dx,word ptr es:[bx+2] + mov si,word ptr es:[bx+6] + mov ds,word ptr es:[bx+8] + mov bx,word ptr es:[bx+4] + int 67h ; call the EMS driver + mov cx,bx ; save returned BX for a sec + les bx,dword ptr [bp+6] ; get EMScontext pointer + mov word ptr es:[bx],ax ; put back ax,dx,bx + mov word ptr es:[bx+2],dx + mov word ptr es:[bx+4],cx + pop ds ; restore registers and exit + pop es + pop dx + pop cx + pop bx + pop di + pop si + pop bp + ret +_jems_calldriver endp + +JMEMDOSA_TXT ends + + end diff --git a/mk4/modimage/jpeg-6b/jmemmac.c b/mk4/modimage/jpeg-6b/jmemmac.c new file mode 100644 index 0000000..106f9be --- /dev/null +++ b/mk4/modimage/jpeg-6b/jmemmac.c @@ -0,0 +1,289 @@ +/* + * jmemmac.c + * + * Copyright (C) 1992-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * jmemmac.c provides an Apple Macintosh implementation of the system- + * dependent portion of the JPEG memory manager. + * + * If you use jmemmac.c, then you must define USE_MAC_MEMMGR in the + * JPEG_INTERNALS part of jconfig.h. + * + * jmemmac.c uses the Macintosh toolbox routines NewPtr and DisposePtr + * instead of malloc and free. It accurately determines the amount of + * memory available by using CompactMem. Notice that if left to its + * own devices, this code can chew up all available space in the + * application's zone, with the exception of the rather small "slop" + * factor computed in jpeg_mem_available(). The application can ensure + * that more space is left over by reducing max_memory_to_use. + * + * Large images are swapped to disk using temporary files and System 7.0+'s + * temporary folder functionality. + * + * Note that jmemmac.c depends on two features of MacOS that were first + * introduced in System 7: FindFolder and the FSSpec-based calls. + * If your application uses jmemmac.c and is run under System 6 or earlier, + * and the jpeg library decides it needs a temporary file, it will abort, + * printing error messages about requiring System 7. (If no temporary files + * are created, it will run fine.) + * + * If you want to use jmemmac.c in an application that might be used with + * System 6 or earlier, then you should remove dependencies on FindFolder + * and the FSSpec calls. You will need to replace FindFolder with some + * other mechanism for finding a place to put temporary files, and you + * should replace the FSSpec calls with their HFS equivalents: + * + * FSpDelete -> HDelete + * FSpGetFInfo -> HGetFInfo + * FSpCreate -> HCreate + * FSpOpenDF -> HOpen *** Note: not HOpenDF *** + * FSMakeFSSpec -> (fill in spec by hand.) + * + * (Use HOpen instead of HOpenDF. HOpen is just a glue-interface to PBHOpen, + * which is on all HFS macs. HOpenDF is a System 7 addition which avoids the + * ages-old problem of names starting with a period.) + * + * Contributed by Sam Bushell (jsam@iagu.on.net) and + * Dan Gildor (gyld@in-touch.com). + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jmemsys.h" /* import the system-dependent declarations */ + +#ifndef USE_MAC_MEMMGR /* make sure user got configuration right */ + You forgot to define USE_MAC_MEMMGR in jconfig.h. /* deliberate syntax error */ +#endif + +#include /* we use the MacOS memory manager */ +#include /* we use the MacOS File stuff */ +#include /* we use the MacOS HFS stuff */ +#include /* for smSystemScript */ +#include /* we use Gestalt to test for specific functionality */ + +#ifndef TEMP_FILE_NAME /* can override from jconfig.h or Makefile */ +#define TEMP_FILE_NAME "JPG%03d.TMP" +#endif + +static int next_file_num; /* to distinguish among several temp files */ + + +/* + * Memory allocation and freeing are controlled by the MacOS library + * routines NewPtr() and DisposePtr(), which allocate fixed-address + * storage. Unfortunately, the IJG library isn't smart enough to cope + * with relocatable storage. + */ + +GLOBAL(void *) +jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject) +{ + return (void *) NewPtr(sizeofobject); +} + +GLOBAL(void) +jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject) +{ + DisposePtr((Ptr) object); +} + + +/* + * "Large" objects are treated the same as "small" ones. + * NB: we include FAR keywords in the routine declarations simply for + * consistency with the rest of the IJG code; FAR should expand to empty + * on rational architectures like the Mac. + */ + +GLOBAL(void FAR *) +jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject) +{ + return (void FAR *) NewPtr(sizeofobject); +} + +GLOBAL(void) +jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject) +{ + DisposePtr((Ptr) object); +} + + +/* + * This routine computes the total memory space available for allocation. + */ + +GLOBAL(long) +jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed, + long max_bytes_needed, long already_allocated) +{ + long limit = cinfo->mem->max_memory_to_use - already_allocated; + long slop, mem; + + /* Don't ask for more than what application has told us we may use */ + if (max_bytes_needed > limit && limit > 0) + max_bytes_needed = limit; + /* Find whether there's a big enough free block in the heap. + * CompactMem tries to create a contiguous block of the requested size, + * and then returns the size of the largest free block (which could be + * much more or much less than we asked for). + * We add some slop to ensure we don't use up all available memory. + */ + slop = max_bytes_needed / 16 + 32768L; + mem = CompactMem(max_bytes_needed + slop) - slop; + if (mem < 0) + mem = 0; /* sigh, couldn't even get the slop */ + /* Don't take more than the application says we can have */ + if (mem > limit && limit > 0) + mem = limit; + return mem; +} + + +/* + * Backing store (temporary file) management. + * Backing store objects are only used when the value returned by + * jpeg_mem_available is less than the total space needed. You can dispense + * with these routines if you have plenty of virtual memory; see jmemnobs.c. + */ + + +METHODDEF(void) +read_backing_store (j_common_ptr cinfo, backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count) +{ + long bytes = byte_count; + long retVal; + + if ( SetFPos ( info->temp_file, fsFromStart, file_offset ) != noErr ) + ERREXIT(cinfo, JERR_TFILE_SEEK); + + retVal = FSRead ( info->temp_file, &bytes, + (unsigned char *) buffer_address ); + if ( retVal != noErr || bytes != byte_count ) + ERREXIT(cinfo, JERR_TFILE_READ); +} + + +METHODDEF(void) +write_backing_store (j_common_ptr cinfo, backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count) +{ + long bytes = byte_count; + long retVal; + + if ( SetFPos ( info->temp_file, fsFromStart, file_offset ) != noErr ) + ERREXIT(cinfo, JERR_TFILE_SEEK); + + retVal = FSWrite ( info->temp_file, &bytes, + (unsigned char *) buffer_address ); + if ( retVal != noErr || bytes != byte_count ) + ERREXIT(cinfo, JERR_TFILE_WRITE); +} + + +METHODDEF(void) +close_backing_store (j_common_ptr cinfo, backing_store_ptr info) +{ + FSClose ( info->temp_file ); + FSpDelete ( &(info->tempSpec) ); +} + + +/* + * Initial opening of a backing-store object. + * + * This version uses FindFolder to find the Temporary Items folder, + * and puts the temporary file in there. + */ + +GLOBAL(void) +jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info, + long total_bytes_needed) +{ + short tmpRef, vRefNum; + long dirID; + FInfo finderInfo; + FSSpec theSpec; + Str255 fName; + OSErr osErr; + long gestaltResponse = 0; + + /* Check that FSSpec calls are available. */ + osErr = Gestalt( gestaltFSAttr, &gestaltResponse ); + if ( ( osErr != noErr ) + || !( gestaltResponse & (1<temp_name, TEMP_FILE_NAME, next_file_num); + strcpy ( (Ptr)fName+1, info->temp_name ); + *fName = strlen (info->temp_name); + osErr = FSMakeFSSpec ( vRefNum, dirID, fName, &theSpec ); + + if ( (osErr = FSpGetFInfo ( &theSpec, &finderInfo ) ) != noErr ) + break; + } + + osErr = FSpCreate ( &theSpec, '????', '????', smSystemScript ); + if ( osErr != noErr ) + ERREXITS(cinfo, JERR_TFILE_CREATE, info->temp_name); + + osErr = FSpOpenDF ( &theSpec, fsRdWrPerm, &(info->temp_file) ); + if ( osErr != noErr ) + ERREXITS(cinfo, JERR_TFILE_CREATE, info->temp_name); + + info->tempSpec = theSpec; + + info->read_backing_store = read_backing_store; + info->write_backing_store = write_backing_store; + info->close_backing_store = close_backing_store; + TRACEMSS(cinfo, 1, JTRC_TFILE_OPEN, info->temp_name); +} + + +/* + * These routines take care of any system-dependent initialization and + * cleanup required. + */ + +GLOBAL(long) +jpeg_mem_init (j_common_ptr cinfo) +{ + next_file_num = 0; + + /* max_memory_to_use will be initialized to FreeMem()'s result; + * the calling application might later reduce it, for example + * to leave room to invoke multiple JPEG objects. + * Note that FreeMem returns the total number of free bytes; + * it may not be possible to allocate a single block of this size. + */ + return FreeMem(); +} + +GLOBAL(void) +jpeg_mem_term (j_common_ptr cinfo) +{ + /* no work */ +} diff --git a/mk4/modimage/jpeg-6b/jmemmgr.c b/mk4/modimage/jpeg-6b/jmemmgr.c new file mode 100644 index 0000000..d801b32 --- /dev/null +++ b/mk4/modimage/jpeg-6b/jmemmgr.c @@ -0,0 +1,1118 @@ +/* + * jmemmgr.c + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the JPEG system-independent memory management + * routines. This code is usable across a wide variety of machines; most + * of the system dependencies have been isolated in a separate file. + * The major functions provided here are: + * * pool-based allocation and freeing of memory; + * * policy decisions about how to divide available memory among the + * virtual arrays; + * * control logic for swapping virtual arrays between main memory and + * backing storage. + * The separate system-dependent file provides the actual backing-storage + * access code, and it contains the policy decision about how much total + * main memory to use. + * This file is system-dependent in the sense that some of its functions + * are unnecessary in some systems. For example, if there is enough virtual + * memory so that backing storage will never be used, much of the virtual + * array control logic could be removed. (Of course, if you have that much + * memory then you shouldn't care about a little bit of unused code...) + */ + +#define JPEG_INTERNALS +#define AM_MEMORY_MANAGER /* we define jvirt_Xarray_control structs */ +#include "jinclude.h" +#include "jpeglib.h" +#include "jmemsys.h" /* import the system-dependent declarations */ + +#ifndef NO_GETENV +#ifndef HAVE_STDLIB_H /* should declare getenv() */ +extern char * getenv JPP((const char * name)); +#endif +#endif + + +/* + * Some important notes: + * The allocation routines provided here must never return NULL. + * They should exit to error_exit if unsuccessful. + * + * It's not a good idea to try to merge the sarray and barray routines, + * even though they are textually almost the same, because samples are + * usually stored as bytes while coefficients are shorts or ints. Thus, + * in machines where byte pointers have a different representation from + * word pointers, the resulting machine code could not be the same. + */ + + +/* + * Many machines require storage alignment: longs must start on 4-byte + * boundaries, doubles on 8-byte boundaries, etc. On such machines, malloc() + * always returns pointers that are multiples of the worst-case alignment + * requirement, and we had better do so too. + * There isn't any really portable way to determine the worst-case alignment + * requirement. This module assumes that the alignment requirement is + * multiples of sizeof(ALIGN_TYPE). + * By default, we define ALIGN_TYPE as double. This is necessary on some + * workstations (where doubles really do need 8-byte alignment) and will work + * fine on nearly everything. If your machine has lesser alignment needs, + * you can save a few bytes by making ALIGN_TYPE smaller. + * The only place I know of where this will NOT work is certain Macintosh + * 680x0 compilers that define double as a 10-byte IEEE extended float. + * Doing 10-byte alignment is counterproductive because longwords won't be + * aligned well. Put "#define ALIGN_TYPE long" in jconfig.h if you have + * such a compiler. + */ + +#ifndef ALIGN_TYPE /* so can override from jconfig.h */ +#define ALIGN_TYPE double +#endif + + +/* + * We allocate objects from "pools", where each pool is gotten with a single + * request to jpeg_get_small() or jpeg_get_large(). There is no per-object + * overhead within a pool, except for alignment padding. Each pool has a + * header with a link to the next pool of the same class. + * Small and large pool headers are identical except that the latter's + * link pointer must be FAR on 80x86 machines. + * Notice that the "real" header fields are union'ed with a dummy ALIGN_TYPE + * field. This forces the compiler to make SIZEOF(small_pool_hdr) a multiple + * of the alignment requirement of ALIGN_TYPE. + */ + +typedef union small_pool_struct * small_pool_ptr; + +typedef union small_pool_struct { + struct { + small_pool_ptr next; /* next in list of pools */ + size_t bytes_used; /* how many bytes already used within pool */ + size_t bytes_left; /* bytes still available in this pool */ + } hdr; + ALIGN_TYPE dummy; /* included in union to ensure alignment */ +} small_pool_hdr; + +typedef union large_pool_struct FAR * large_pool_ptr; + +typedef union large_pool_struct { + struct { + large_pool_ptr next; /* next in list of pools */ + size_t bytes_used; /* how many bytes already used within pool */ + size_t bytes_left; /* bytes still available in this pool */ + } hdr; + ALIGN_TYPE dummy; /* included in union to ensure alignment */ +} large_pool_hdr; + + +/* + * Here is the full definition of a memory manager object. + */ + +typedef struct { + struct jpeg_memory_mgr pub; /* public fields */ + + /* Each pool identifier (lifetime class) names a linked list of pools. */ + small_pool_ptr small_list[JPOOL_NUMPOOLS]; + large_pool_ptr large_list[JPOOL_NUMPOOLS]; + + /* Since we only have one lifetime class of virtual arrays, only one + * linked list is necessary (for each datatype). Note that the virtual + * array control blocks being linked together are actually stored somewhere + * in the small-pool list. + */ + jvirt_sarray_ptr virt_sarray_list; + jvirt_barray_ptr virt_barray_list; + + /* This counts total space obtained from jpeg_get_small/large */ + long total_space_allocated; + + /* alloc_sarray and alloc_barray set this value for use by virtual + * array routines. + */ + JDIMENSION last_rowsperchunk; /* from most recent alloc_sarray/barray */ +} my_memory_mgr; + +typedef my_memory_mgr * my_mem_ptr; + + +/* + * The control blocks for virtual arrays. + * Note that these blocks are allocated in the "small" pool area. + * System-dependent info for the associated backing store (if any) is hidden + * inside the backing_store_info struct. + */ + +struct jvirt_sarray_control { + JSAMPARRAY mem_buffer; /* => the in-memory buffer */ + JDIMENSION rows_in_array; /* total virtual array height */ + JDIMENSION samplesperrow; /* width of array (and of memory buffer) */ + JDIMENSION maxaccess; /* max rows accessed by access_virt_sarray */ + JDIMENSION rows_in_mem; /* height of memory buffer */ + JDIMENSION rowsperchunk; /* allocation chunk size in mem_buffer */ + JDIMENSION cur_start_row; /* first logical row # in the buffer */ + JDIMENSION first_undef_row; /* row # of first uninitialized row */ + boolean pre_zero; /* pre-zero mode requested? */ + boolean dirty; /* do current buffer contents need written? */ + boolean b_s_open; /* is backing-store data valid? */ + jvirt_sarray_ptr next; /* link to next virtual sarray control block */ + backing_store_info b_s_info; /* System-dependent control info */ +}; + +struct jvirt_barray_control { + JBLOCKARRAY mem_buffer; /* => the in-memory buffer */ + JDIMENSION rows_in_array; /* total virtual array height */ + JDIMENSION blocksperrow; /* width of array (and of memory buffer) */ + JDIMENSION maxaccess; /* max rows accessed by access_virt_barray */ + JDIMENSION rows_in_mem; /* height of memory buffer */ + JDIMENSION rowsperchunk; /* allocation chunk size in mem_buffer */ + JDIMENSION cur_start_row; /* first logical row # in the buffer */ + JDIMENSION first_undef_row; /* row # of first uninitialized row */ + boolean pre_zero; /* pre-zero mode requested? */ + boolean dirty; /* do current buffer contents need written? */ + boolean b_s_open; /* is backing-store data valid? */ + jvirt_barray_ptr next; /* link to next virtual barray control block */ + backing_store_info b_s_info; /* System-dependent control info */ +}; + + +#ifdef MEM_STATS /* optional extra stuff for statistics */ + +LOCAL(void) +print_mem_stats (j_common_ptr cinfo, int pool_id) +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + small_pool_ptr shdr_ptr; + large_pool_ptr lhdr_ptr; + + /* Since this is only a debugging stub, we can cheat a little by using + * fprintf directly rather than going through the trace message code. + * This is helpful because message parm array can't handle longs. + */ + fprintf(stderr, "Freeing pool %d, total space = %ld\n", + pool_id, mem->total_space_allocated); + + for (lhdr_ptr = mem->large_list[pool_id]; lhdr_ptr != NULL; + lhdr_ptr = lhdr_ptr->hdr.next) { + fprintf(stderr, " Large chunk used %ld\n", + (long) lhdr_ptr->hdr.bytes_used); + } + + for (shdr_ptr = mem->small_list[pool_id]; shdr_ptr != NULL; + shdr_ptr = shdr_ptr->hdr.next) { + fprintf(stderr, " Small chunk used %ld free %ld\n", + (long) shdr_ptr->hdr.bytes_used, + (long) shdr_ptr->hdr.bytes_left); + } +} + +#endif /* MEM_STATS */ + + +LOCAL(void) +out_of_memory (j_common_ptr cinfo, int which) +/* Report an out-of-memory error and stop execution */ +/* If we compiled MEM_STATS support, report alloc requests before dying */ +{ +#ifdef MEM_STATS + cinfo->err->trace_level = 2; /* force self_destruct to report stats */ +#endif + ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, which); +} + + +/* + * Allocation of "small" objects. + * + * For these, we use pooled storage. When a new pool must be created, + * we try to get enough space for the current request plus a "slop" factor, + * where the slop will be the amount of leftover space in the new pool. + * The speed vs. space tradeoff is largely determined by the slop values. + * A different slop value is provided for each pool class (lifetime), + * and we also distinguish the first pool of a class from later ones. + * NOTE: the values given work fairly well on both 16- and 32-bit-int + * machines, but may be too small if longs are 64 bits or more. + */ + +static const size_t first_pool_slop[JPOOL_NUMPOOLS] = +{ + 1600, /* first PERMANENT pool */ + 16000 /* first IMAGE pool */ +}; + +static const size_t extra_pool_slop[JPOOL_NUMPOOLS] = +{ + 0, /* additional PERMANENT pools */ + 5000 /* additional IMAGE pools */ +}; + +#define MIN_SLOP 50 /* greater than 0 to avoid futile looping */ + + +METHODDEF(void *) +alloc_small (j_common_ptr cinfo, int pool_id, size_t sizeofobject) +/* Allocate a "small" object */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + small_pool_ptr hdr_ptr, prev_hdr_ptr; + char * data_ptr; + size_t odd_bytes, min_request, slop; + + /* Check for unsatisfiable request (do now to ensure no overflow below) */ + if (sizeofobject > (size_t) (MAX_ALLOC_CHUNK-SIZEOF(small_pool_hdr))) + out_of_memory(cinfo, 1); /* request exceeds malloc's ability */ + + /* Round up the requested size to a multiple of SIZEOF(ALIGN_TYPE) */ + odd_bytes = sizeofobject % SIZEOF(ALIGN_TYPE); + if (odd_bytes > 0) + sizeofobject += SIZEOF(ALIGN_TYPE) - odd_bytes; + + /* See if space is available in any existing pool */ + if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS) + ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ + prev_hdr_ptr = NULL; + hdr_ptr = mem->small_list[pool_id]; + while (hdr_ptr != NULL) { + if (hdr_ptr->hdr.bytes_left >= sizeofobject) + break; /* found pool with enough space */ + prev_hdr_ptr = hdr_ptr; + hdr_ptr = hdr_ptr->hdr.next; + } + + /* Time to make a new pool? */ + if (hdr_ptr == NULL) { + /* min_request is what we need now, slop is what will be leftover */ + min_request = sizeofobject + SIZEOF(small_pool_hdr); + if (prev_hdr_ptr == NULL) /* first pool in class? */ + slop = first_pool_slop[pool_id]; + else + slop = extra_pool_slop[pool_id]; + /* Don't ask for more than MAX_ALLOC_CHUNK */ + if (slop > (size_t) (MAX_ALLOC_CHUNK-min_request)) + slop = (size_t) (MAX_ALLOC_CHUNK-min_request); + /* Try to get space, if fail reduce slop and try again */ + for (;;) { + hdr_ptr = (small_pool_ptr) jpeg_get_small(cinfo, min_request + slop); + if (hdr_ptr != NULL) + break; + slop /= 2; + if (slop < MIN_SLOP) /* give up when it gets real small */ + out_of_memory(cinfo, 2); /* jpeg_get_small failed */ + } + mem->total_space_allocated += min_request + slop; + /* Success, initialize the new pool header and add to end of list */ + hdr_ptr->hdr.next = NULL; + hdr_ptr->hdr.bytes_used = 0; + hdr_ptr->hdr.bytes_left = sizeofobject + slop; + if (prev_hdr_ptr == NULL) /* first pool in class? */ + mem->small_list[pool_id] = hdr_ptr; + else + prev_hdr_ptr->hdr.next = hdr_ptr; + } + + /* OK, allocate the object from the current pool */ + data_ptr = (char *) (hdr_ptr + 1); /* point to first data byte in pool */ + data_ptr += hdr_ptr->hdr.bytes_used; /* point to place for object */ + hdr_ptr->hdr.bytes_used += sizeofobject; + hdr_ptr->hdr.bytes_left -= sizeofobject; + + return (void *) data_ptr; +} + + +/* + * Allocation of "large" objects. + * + * The external semantics of these are the same as "small" objects, + * except that FAR pointers are used on 80x86. However the pool + * management heuristics are quite different. We assume that each + * request is large enough that it may as well be passed directly to + * jpeg_get_large; the pool management just links everything together + * so that we can free it all on demand. + * Note: the major use of "large" objects is in JSAMPARRAY and JBLOCKARRAY + * structures. The routines that create these structures (see below) + * deliberately bunch rows together to ensure a large request size. + */ + +METHODDEF(void FAR *) +alloc_large (j_common_ptr cinfo, int pool_id, size_t sizeofobject) +/* Allocate a "large" object */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + large_pool_ptr hdr_ptr; + size_t odd_bytes; + + /* Check for unsatisfiable request (do now to ensure no overflow below) */ + if (sizeofobject > (size_t) (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr))) + out_of_memory(cinfo, 3); /* request exceeds malloc's ability */ + + /* Round up the requested size to a multiple of SIZEOF(ALIGN_TYPE) */ + odd_bytes = sizeofobject % SIZEOF(ALIGN_TYPE); + if (odd_bytes > 0) + sizeofobject += SIZEOF(ALIGN_TYPE) - odd_bytes; + + /* Always make a new pool */ + if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS) + ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ + + hdr_ptr = (large_pool_ptr) jpeg_get_large(cinfo, sizeofobject + + SIZEOF(large_pool_hdr)); + if (hdr_ptr == NULL) + out_of_memory(cinfo, 4); /* jpeg_get_large failed */ + mem->total_space_allocated += sizeofobject + SIZEOF(large_pool_hdr); + + /* Success, initialize the new pool header and add to list */ + hdr_ptr->hdr.next = mem->large_list[pool_id]; + /* We maintain space counts in each pool header for statistical purposes, + * even though they are not needed for allocation. + */ + hdr_ptr->hdr.bytes_used = sizeofobject; + hdr_ptr->hdr.bytes_left = 0; + mem->large_list[pool_id] = hdr_ptr; + + return (void FAR *) (hdr_ptr + 1); /* point to first data byte in pool */ +} + + +/* + * Creation of 2-D sample arrays. + * The pointers are in near heap, the samples themselves in FAR heap. + * + * To minimize allocation overhead and to allow I/O of large contiguous + * blocks, we allocate the sample rows in groups of as many rows as possible + * without exceeding MAX_ALLOC_CHUNK total bytes per allocation request. + * NB: the virtual array control routines, later in this file, know about + * this chunking of rows. The rowsperchunk value is left in the mem manager + * object so that it can be saved away if this sarray is the workspace for + * a virtual array. + */ + +METHODDEF(JSAMPARRAY) +alloc_sarray (j_common_ptr cinfo, int pool_id, + JDIMENSION samplesperrow, JDIMENSION numrows) +/* Allocate a 2-D sample array */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + JSAMPARRAY result; + JSAMPROW workspace; + JDIMENSION rowsperchunk, currow, i; + long ltemp; + + /* Calculate max # of rows allowed in one allocation chunk */ + ltemp = (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)) / + ((long) samplesperrow * SIZEOF(JSAMPLE)); + if (ltemp <= 0) + ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); + if (ltemp < (long) numrows) + rowsperchunk = (JDIMENSION) ltemp; + else + rowsperchunk = numrows; + mem->last_rowsperchunk = rowsperchunk; + + /* Get space for row pointers (small object) */ + result = (JSAMPARRAY) alloc_small(cinfo, pool_id, + (size_t) (numrows * SIZEOF(JSAMPROW))); + + /* Get the rows themselves (large objects) */ + currow = 0; + while (currow < numrows) { + rowsperchunk = MIN(rowsperchunk, numrows - currow); + workspace = (JSAMPROW) alloc_large(cinfo, pool_id, + (size_t) ((size_t) rowsperchunk * (size_t) samplesperrow + * SIZEOF(JSAMPLE))); + for (i = rowsperchunk; i > 0; i--) { + result[currow++] = workspace; + workspace += samplesperrow; + } + } + + return result; +} + + +/* + * Creation of 2-D coefficient-block arrays. + * This is essentially the same as the code for sample arrays, above. + */ + +METHODDEF(JBLOCKARRAY) +alloc_barray (j_common_ptr cinfo, int pool_id, + JDIMENSION blocksperrow, JDIMENSION numrows) +/* Allocate a 2-D coefficient-block array */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + JBLOCKARRAY result; + JBLOCKROW workspace; + JDIMENSION rowsperchunk, currow, i; + long ltemp; + + /* Calculate max # of rows allowed in one allocation chunk */ + ltemp = (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)) / + ((long) blocksperrow * SIZEOF(JBLOCK)); + if (ltemp <= 0) + ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); + if (ltemp < (long) numrows) + rowsperchunk = (JDIMENSION) ltemp; + else + rowsperchunk = numrows; + mem->last_rowsperchunk = rowsperchunk; + + /* Get space for row pointers (small object) */ + result = (JBLOCKARRAY) alloc_small(cinfo, pool_id, + (size_t) (numrows * SIZEOF(JBLOCKROW))); + + /* Get the rows themselves (large objects) */ + currow = 0; + while (currow < numrows) { + rowsperchunk = MIN(rowsperchunk, numrows - currow); + workspace = (JBLOCKROW) alloc_large(cinfo, pool_id, + (size_t) ((size_t) rowsperchunk * (size_t) blocksperrow + * SIZEOF(JBLOCK))); + for (i = rowsperchunk; i > 0; i--) { + result[currow++] = workspace; + workspace += blocksperrow; + } + } + + return result; +} + + +/* + * About virtual array management: + * + * The above "normal" array routines are only used to allocate strip buffers + * (as wide as the image, but just a few rows high). Full-image-sized buffers + * are handled as "virtual" arrays. The array is still accessed a strip at a + * time, but the memory manager must save the whole array for repeated + * accesses. The intended implementation is that there is a strip buffer in + * memory (as high as is possible given the desired memory limit), plus a + * backing file that holds the rest of the array. + * + * The request_virt_array routines are told the total size of the image and + * the maximum number of rows that will be accessed at once. The in-memory + * buffer must be at least as large as the maxaccess value. + * + * The request routines create control blocks but not the in-memory buffers. + * That is postponed until realize_virt_arrays is called. At that time the + * total amount of space needed is known (approximately, anyway), so free + * memory can be divided up fairly. + * + * The access_virt_array routines are responsible for making a specific strip + * area accessible (after reading or writing the backing file, if necessary). + * Note that the access routines are told whether the caller intends to modify + * the accessed strip; during a read-only pass this saves having to rewrite + * data to disk. The access routines are also responsible for pre-zeroing + * any newly accessed rows, if pre-zeroing was requested. + * + * In current usage, the access requests are usually for nonoverlapping + * strips; that is, successive access start_row numbers differ by exactly + * num_rows = maxaccess. This means we can get good performance with simple + * buffer dump/reload logic, by making the in-memory buffer be a multiple + * of the access height; then there will never be accesses across bufferload + * boundaries. The code will still work with overlapping access requests, + * but it doesn't handle bufferload overlaps very efficiently. + */ + + +METHODDEF(jvirt_sarray_ptr) +request_virt_sarray (j_common_ptr cinfo, int pool_id, boolean pre_zero, + JDIMENSION samplesperrow, JDIMENSION numrows, + JDIMENSION maxaccess) +/* Request a virtual 2-D sample array */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + jvirt_sarray_ptr result; + + /* Only IMAGE-lifetime virtual arrays are currently supported */ + if (pool_id != JPOOL_IMAGE) + ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ + + /* get control block */ + result = (jvirt_sarray_ptr) alloc_small(cinfo, pool_id, + SIZEOF(struct jvirt_sarray_control)); + + result->mem_buffer = NULL; /* marks array not yet realized */ + result->rows_in_array = numrows; + result->samplesperrow = samplesperrow; + result->maxaccess = maxaccess; + result->pre_zero = pre_zero; + result->b_s_open = FALSE; /* no associated backing-store object */ + result->next = mem->virt_sarray_list; /* add to list of virtual arrays */ + mem->virt_sarray_list = result; + + return result; +} + + +METHODDEF(jvirt_barray_ptr) +request_virt_barray (j_common_ptr cinfo, int pool_id, boolean pre_zero, + JDIMENSION blocksperrow, JDIMENSION numrows, + JDIMENSION maxaccess) +/* Request a virtual 2-D coefficient-block array */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + jvirt_barray_ptr result; + + /* Only IMAGE-lifetime virtual arrays are currently supported */ + if (pool_id != JPOOL_IMAGE) + ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ + + /* get control block */ + result = (jvirt_barray_ptr) alloc_small(cinfo, pool_id, + SIZEOF(struct jvirt_barray_control)); + + result->mem_buffer = NULL; /* marks array not yet realized */ + result->rows_in_array = numrows; + result->blocksperrow = blocksperrow; + result->maxaccess = maxaccess; + result->pre_zero = pre_zero; + result->b_s_open = FALSE; /* no associated backing-store object */ + result->next = mem->virt_barray_list; /* add to list of virtual arrays */ + mem->virt_barray_list = result; + + return result; +} + + +METHODDEF(void) +realize_virt_arrays (j_common_ptr cinfo) +/* Allocate the in-memory buffers for any unrealized virtual arrays */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + long space_per_minheight, maximum_space, avail_mem; + long minheights, max_minheights; + jvirt_sarray_ptr sptr; + jvirt_barray_ptr bptr; + + /* Compute the minimum space needed (maxaccess rows in each buffer) + * and the maximum space needed (full image height in each buffer). + * These may be of use to the system-dependent jpeg_mem_available routine. + */ + space_per_minheight = 0; + maximum_space = 0; + for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) { + if (sptr->mem_buffer == NULL) { /* if not realized yet */ + space_per_minheight += (long) sptr->maxaccess * + (long) sptr->samplesperrow * SIZEOF(JSAMPLE); + maximum_space += (long) sptr->rows_in_array * + (long) sptr->samplesperrow * SIZEOF(JSAMPLE); + } + } + for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) { + if (bptr->mem_buffer == NULL) { /* if not realized yet */ + space_per_minheight += (long) bptr->maxaccess * + (long) bptr->blocksperrow * SIZEOF(JBLOCK); + maximum_space += (long) bptr->rows_in_array * + (long) bptr->blocksperrow * SIZEOF(JBLOCK); + } + } + + if (space_per_minheight <= 0) + return; /* no unrealized arrays, no work */ + + /* Determine amount of memory to actually use; this is system-dependent. */ + avail_mem = jpeg_mem_available(cinfo, space_per_minheight, maximum_space, + mem->total_space_allocated); + + /* If the maximum space needed is available, make all the buffers full + * height; otherwise parcel it out with the same number of minheights + * in each buffer. + */ + if (avail_mem >= maximum_space) + max_minheights = 1000000000L; + else { + max_minheights = avail_mem / space_per_minheight; + /* If there doesn't seem to be enough space, try to get the minimum + * anyway. This allows a "stub" implementation of jpeg_mem_available(). + */ + if (max_minheights <= 0) + max_minheights = 1; + } + + /* Allocate the in-memory buffers and initialize backing store as needed. */ + + for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) { + if (sptr->mem_buffer == NULL) { /* if not realized yet */ + minheights = ((long) sptr->rows_in_array - 1L) / sptr->maxaccess + 1L; + if (minheights <= max_minheights) { + /* This buffer fits in memory */ + sptr->rows_in_mem = sptr->rows_in_array; + } else { + /* It doesn't fit in memory, create backing store. */ + sptr->rows_in_mem = (JDIMENSION) (max_minheights * sptr->maxaccess); + jpeg_open_backing_store(cinfo, & sptr->b_s_info, + (long) sptr->rows_in_array * + (long) sptr->samplesperrow * + (long) SIZEOF(JSAMPLE)); + sptr->b_s_open = TRUE; + } + sptr->mem_buffer = alloc_sarray(cinfo, JPOOL_IMAGE, + sptr->samplesperrow, sptr->rows_in_mem); + sptr->rowsperchunk = mem->last_rowsperchunk; + sptr->cur_start_row = 0; + sptr->first_undef_row = 0; + sptr->dirty = FALSE; + } + } + + for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) { + if (bptr->mem_buffer == NULL) { /* if not realized yet */ + minheights = ((long) bptr->rows_in_array - 1L) / bptr->maxaccess + 1L; + if (minheights <= max_minheights) { + /* This buffer fits in memory */ + bptr->rows_in_mem = bptr->rows_in_array; + } else { + /* It doesn't fit in memory, create backing store. */ + bptr->rows_in_mem = (JDIMENSION) (max_minheights * bptr->maxaccess); + jpeg_open_backing_store(cinfo, & bptr->b_s_info, + (long) bptr->rows_in_array * + (long) bptr->blocksperrow * + (long) SIZEOF(JBLOCK)); + bptr->b_s_open = TRUE; + } + bptr->mem_buffer = alloc_barray(cinfo, JPOOL_IMAGE, + bptr->blocksperrow, bptr->rows_in_mem); + bptr->rowsperchunk = mem->last_rowsperchunk; + bptr->cur_start_row = 0; + bptr->first_undef_row = 0; + bptr->dirty = FALSE; + } + } +} + + +LOCAL(void) +do_sarray_io (j_common_ptr cinfo, jvirt_sarray_ptr ptr, boolean writing) +/* Do backing store read or write of a virtual sample array */ +{ + long bytesperrow, file_offset, byte_count, rows, thisrow, i; + + bytesperrow = (long) ptr->samplesperrow * SIZEOF(JSAMPLE); + file_offset = ptr->cur_start_row * bytesperrow; + /* Loop to read or write each allocation chunk in mem_buffer */ + for (i = 0; i < (long) ptr->rows_in_mem; i += ptr->rowsperchunk) { + /* One chunk, but check for short chunk at end of buffer */ + rows = MIN((long) ptr->rowsperchunk, (long) ptr->rows_in_mem - i); + /* Transfer no more than is currently defined */ + thisrow = (long) ptr->cur_start_row + i; + rows = MIN(rows, (long) ptr->first_undef_row - thisrow); + /* Transfer no more than fits in file */ + rows = MIN(rows, (long) ptr->rows_in_array - thisrow); + if (rows <= 0) /* this chunk might be past end of file! */ + break; + byte_count = rows * bytesperrow; + if (writing) + (*ptr->b_s_info.write_backing_store) (cinfo, & ptr->b_s_info, + (void FAR *) ptr->mem_buffer[i], + file_offset, byte_count); + else + (*ptr->b_s_info.read_backing_store) (cinfo, & ptr->b_s_info, + (void FAR *) ptr->mem_buffer[i], + file_offset, byte_count); + file_offset += byte_count; + } +} + + +LOCAL(void) +do_barray_io (j_common_ptr cinfo, jvirt_barray_ptr ptr, boolean writing) +/* Do backing store read or write of a virtual coefficient-block array */ +{ + long bytesperrow, file_offset, byte_count, rows, thisrow, i; + + bytesperrow = (long) ptr->blocksperrow * SIZEOF(JBLOCK); + file_offset = ptr->cur_start_row * bytesperrow; + /* Loop to read or write each allocation chunk in mem_buffer */ + for (i = 0; i < (long) ptr->rows_in_mem; i += ptr->rowsperchunk) { + /* One chunk, but check for short chunk at end of buffer */ + rows = MIN((long) ptr->rowsperchunk, (long) ptr->rows_in_mem - i); + /* Transfer no more than is currently defined */ + thisrow = (long) ptr->cur_start_row + i; + rows = MIN(rows, (long) ptr->first_undef_row - thisrow); + /* Transfer no more than fits in file */ + rows = MIN(rows, (long) ptr->rows_in_array - thisrow); + if (rows <= 0) /* this chunk might be past end of file! */ + break; + byte_count = rows * bytesperrow; + if (writing) + (*ptr->b_s_info.write_backing_store) (cinfo, & ptr->b_s_info, + (void FAR *) ptr->mem_buffer[i], + file_offset, byte_count); + else + (*ptr->b_s_info.read_backing_store) (cinfo, & ptr->b_s_info, + (void FAR *) ptr->mem_buffer[i], + file_offset, byte_count); + file_offset += byte_count; + } +} + + +METHODDEF(JSAMPARRAY) +access_virt_sarray (j_common_ptr cinfo, jvirt_sarray_ptr ptr, + JDIMENSION start_row, JDIMENSION num_rows, + boolean writable) +/* Access the part of a virtual sample array starting at start_row */ +/* and extending for num_rows rows. writable is true if */ +/* caller intends to modify the accessed area. */ +{ + JDIMENSION end_row = start_row + num_rows; + JDIMENSION undef_row; + + /* debugging check */ + if (end_row > ptr->rows_in_array || num_rows > ptr->maxaccess || + ptr->mem_buffer == NULL) + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + + /* Make the desired part of the virtual array accessible */ + if (start_row < ptr->cur_start_row || + end_row > ptr->cur_start_row+ptr->rows_in_mem) { + if (! ptr->b_s_open) + ERREXIT(cinfo, JERR_VIRTUAL_BUG); + /* Flush old buffer contents if necessary */ + if (ptr->dirty) { + do_sarray_io(cinfo, ptr, TRUE); + ptr->dirty = FALSE; + } + /* Decide what part of virtual array to access. + * Algorithm: if target address > current window, assume forward scan, + * load starting at target address. If target address < current window, + * assume backward scan, load so that target area is top of window. + * Note that when switching from forward write to forward read, will have + * start_row = 0, so the limiting case applies and we load from 0 anyway. + */ + if (start_row > ptr->cur_start_row) { + ptr->cur_start_row = start_row; + } else { + /* use long arithmetic here to avoid overflow & unsigned problems */ + long ltemp; + + ltemp = (long) end_row - (long) ptr->rows_in_mem; + if (ltemp < 0) + ltemp = 0; /* don't fall off front end of file */ + ptr->cur_start_row = (JDIMENSION) ltemp; + } + /* Read in the selected part of the array. + * During the initial write pass, we will do no actual read + * because the selected part is all undefined. + */ + do_sarray_io(cinfo, ptr, FALSE); + } + /* Ensure the accessed part of the array is defined; prezero if needed. + * To improve locality of access, we only prezero the part of the array + * that the caller is about to access, not the entire in-memory array. + */ + if (ptr->first_undef_row < end_row) { + if (ptr->first_undef_row < start_row) { + if (writable) /* writer skipped over a section of array */ + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + undef_row = start_row; /* but reader is allowed to read ahead */ + } else { + undef_row = ptr->first_undef_row; + } + if (writable) + ptr->first_undef_row = end_row; + if (ptr->pre_zero) { + size_t bytesperrow = (size_t) ptr->samplesperrow * SIZEOF(JSAMPLE); + undef_row -= ptr->cur_start_row; /* make indexes relative to buffer */ + end_row -= ptr->cur_start_row; + while (undef_row < end_row) { + jzero_far((void FAR *) ptr->mem_buffer[undef_row], bytesperrow); + undef_row++; + } + } else { + if (! writable) /* reader looking at undefined data */ + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + } + } + /* Flag the buffer dirty if caller will write in it */ + if (writable) + ptr->dirty = TRUE; + /* Return address of proper part of the buffer */ + return ptr->mem_buffer + (start_row - ptr->cur_start_row); +} + + +METHODDEF(JBLOCKARRAY) +access_virt_barray (j_common_ptr cinfo, jvirt_barray_ptr ptr, + JDIMENSION start_row, JDIMENSION num_rows, + boolean writable) +/* Access the part of a virtual block array starting at start_row */ +/* and extending for num_rows rows. writable is true if */ +/* caller intends to modify the accessed area. */ +{ + JDIMENSION end_row = start_row + num_rows; + JDIMENSION undef_row; + + /* debugging check */ + if (end_row > ptr->rows_in_array || num_rows > ptr->maxaccess || + ptr->mem_buffer == NULL) + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + + /* Make the desired part of the virtual array accessible */ + if (start_row < ptr->cur_start_row || + end_row > ptr->cur_start_row+ptr->rows_in_mem) { + if (! ptr->b_s_open) + ERREXIT(cinfo, JERR_VIRTUAL_BUG); + /* Flush old buffer contents if necessary */ + if (ptr->dirty) { + do_barray_io(cinfo, ptr, TRUE); + ptr->dirty = FALSE; + } + /* Decide what part of virtual array to access. + * Algorithm: if target address > current window, assume forward scan, + * load starting at target address. If target address < current window, + * assume backward scan, load so that target area is top of window. + * Note that when switching from forward write to forward read, will have + * start_row = 0, so the limiting case applies and we load from 0 anyway. + */ + if (start_row > ptr->cur_start_row) { + ptr->cur_start_row = start_row; + } else { + /* use long arithmetic here to avoid overflow & unsigned problems */ + long ltemp; + + ltemp = (long) end_row - (long) ptr->rows_in_mem; + if (ltemp < 0) + ltemp = 0; /* don't fall off front end of file */ + ptr->cur_start_row = (JDIMENSION) ltemp; + } + /* Read in the selected part of the array. + * During the initial write pass, we will do no actual read + * because the selected part is all undefined. + */ + do_barray_io(cinfo, ptr, FALSE); + } + /* Ensure the accessed part of the array is defined; prezero if needed. + * To improve locality of access, we only prezero the part of the array + * that the caller is about to access, not the entire in-memory array. + */ + if (ptr->first_undef_row < end_row) { + if (ptr->first_undef_row < start_row) { + if (writable) /* writer skipped over a section of array */ + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + undef_row = start_row; /* but reader is allowed to read ahead */ + } else { + undef_row = ptr->first_undef_row; + } + if (writable) + ptr->first_undef_row = end_row; + if (ptr->pre_zero) { + size_t bytesperrow = (size_t) ptr->blocksperrow * SIZEOF(JBLOCK); + undef_row -= ptr->cur_start_row; /* make indexes relative to buffer */ + end_row -= ptr->cur_start_row; + while (undef_row < end_row) { + jzero_far((void FAR *) ptr->mem_buffer[undef_row], bytesperrow); + undef_row++; + } + } else { + if (! writable) /* reader looking at undefined data */ + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + } + } + /* Flag the buffer dirty if caller will write in it */ + if (writable) + ptr->dirty = TRUE; + /* Return address of proper part of the buffer */ + return ptr->mem_buffer + (start_row - ptr->cur_start_row); +} + + +/* + * Release all objects belonging to a specified pool. + */ + +METHODDEF(void) +free_pool (j_common_ptr cinfo, int pool_id) +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + small_pool_ptr shdr_ptr; + large_pool_ptr lhdr_ptr; + size_t space_freed; + + if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS) + ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ + +#ifdef MEM_STATS + if (cinfo->err->trace_level > 1) + print_mem_stats(cinfo, pool_id); /* print pool's memory usage statistics */ +#endif + + /* If freeing IMAGE pool, close any virtual arrays first */ + if (pool_id == JPOOL_IMAGE) { + jvirt_sarray_ptr sptr; + jvirt_barray_ptr bptr; + + for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) { + if (sptr->b_s_open) { /* there may be no backing store */ + sptr->b_s_open = FALSE; /* prevent recursive close if error */ + (*sptr->b_s_info.close_backing_store) (cinfo, & sptr->b_s_info); + } + } + mem->virt_sarray_list = NULL; + for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) { + if (bptr->b_s_open) { /* there may be no backing store */ + bptr->b_s_open = FALSE; /* prevent recursive close if error */ + (*bptr->b_s_info.close_backing_store) (cinfo, & bptr->b_s_info); + } + } + mem->virt_barray_list = NULL; + } + + /* Release large objects */ + lhdr_ptr = mem->large_list[pool_id]; + mem->large_list[pool_id] = NULL; + + while (lhdr_ptr != NULL) { + large_pool_ptr next_lhdr_ptr = lhdr_ptr->hdr.next; + space_freed = lhdr_ptr->hdr.bytes_used + + lhdr_ptr->hdr.bytes_left + + SIZEOF(large_pool_hdr); + jpeg_free_large(cinfo, (void FAR *) lhdr_ptr, space_freed); + mem->total_space_allocated -= space_freed; + lhdr_ptr = next_lhdr_ptr; + } + + /* Release small objects */ + shdr_ptr = mem->small_list[pool_id]; + mem->small_list[pool_id] = NULL; + + while (shdr_ptr != NULL) { + small_pool_ptr next_shdr_ptr = shdr_ptr->hdr.next; + space_freed = shdr_ptr->hdr.bytes_used + + shdr_ptr->hdr.bytes_left + + SIZEOF(small_pool_hdr); + jpeg_free_small(cinfo, (void *) shdr_ptr, space_freed); + mem->total_space_allocated -= space_freed; + shdr_ptr = next_shdr_ptr; + } +} + + +/* + * Close up shop entirely. + * Note that this cannot be called unless cinfo->mem is non-NULL. + */ + +METHODDEF(void) +self_destruct (j_common_ptr cinfo) +{ + int pool; + + /* Close all backing store, release all memory. + * Releasing pools in reverse order might help avoid fragmentation + * with some (brain-damaged) malloc libraries. + */ + for (pool = JPOOL_NUMPOOLS-1; pool >= JPOOL_PERMANENT; pool--) { + free_pool(cinfo, pool); + } + + /* Release the memory manager control block too. */ + jpeg_free_small(cinfo, (void *) cinfo->mem, SIZEOF(my_memory_mgr)); + cinfo->mem = NULL; /* ensures I will be called only once */ + + jpeg_mem_term(cinfo); /* system-dependent cleanup */ +} + + +/* + * Memory manager initialization. + * When this is called, only the error manager pointer is valid in cinfo! + */ + +GLOBAL(void) +jinit_memory_mgr (j_common_ptr cinfo) +{ + my_mem_ptr mem; + long max_to_use; + int pool; + size_t test_mac; + + cinfo->mem = NULL; /* for safety if init fails */ + + /* Check for configuration errors. + * SIZEOF(ALIGN_TYPE) should be a power of 2; otherwise, it probably + * doesn't reflect any real hardware alignment requirement. + * The test is a little tricky: for X>0, X and X-1 have no one-bits + * in common if and only if X is a power of 2, ie has only one one-bit. + * Some compilers may give an "unreachable code" warning here; ignore it. + */ + if ((SIZEOF(ALIGN_TYPE) & (SIZEOF(ALIGN_TYPE)-1)) != 0) + ERREXIT(cinfo, JERR_BAD_ALIGN_TYPE); + /* MAX_ALLOC_CHUNK must be representable as type size_t, and must be + * a multiple of SIZEOF(ALIGN_TYPE). + * Again, an "unreachable code" warning may be ignored here. + * But a "constant too large" warning means you need to fix MAX_ALLOC_CHUNK. + */ + test_mac = (size_t) MAX_ALLOC_CHUNK; + if ((long) test_mac != MAX_ALLOC_CHUNK || + (MAX_ALLOC_CHUNK % SIZEOF(ALIGN_TYPE)) != 0) + ERREXIT(cinfo, JERR_BAD_ALLOC_CHUNK); + + max_to_use = jpeg_mem_init(cinfo); /* system-dependent initialization */ + + /* Attempt to allocate memory manager's control block */ + mem = (my_mem_ptr) jpeg_get_small(cinfo, SIZEOF(my_memory_mgr)); + + if (mem == NULL) { + jpeg_mem_term(cinfo); /* system-dependent cleanup */ + ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 0); + } + + /* OK, fill in the method pointers */ + mem->pub.alloc_small = alloc_small; + mem->pub.alloc_large = alloc_large; + mem->pub.alloc_sarray = alloc_sarray; + mem->pub.alloc_barray = alloc_barray; + mem->pub.request_virt_sarray = request_virt_sarray; + mem->pub.request_virt_barray = request_virt_barray; + mem->pub.realize_virt_arrays = realize_virt_arrays; + mem->pub.access_virt_sarray = access_virt_sarray; + mem->pub.access_virt_barray = access_virt_barray; + mem->pub.free_pool = free_pool; + mem->pub.self_destruct = self_destruct; + + /* Make MAX_ALLOC_CHUNK accessible to other modules */ + mem->pub.max_alloc_chunk = MAX_ALLOC_CHUNK; + + /* Initialize working state */ + mem->pub.max_memory_to_use = max_to_use; + + for (pool = JPOOL_NUMPOOLS-1; pool >= JPOOL_PERMANENT; pool--) { + mem->small_list[pool] = NULL; + mem->large_list[pool] = NULL; + } + mem->virt_sarray_list = NULL; + mem->virt_barray_list = NULL; + + mem->total_space_allocated = SIZEOF(my_memory_mgr); + + /* Declare ourselves open for business */ + cinfo->mem = & mem->pub; + + /* Check for an environment variable JPEGMEM; if found, override the + * default max_memory setting from jpeg_mem_init. Note that the + * surrounding application may again override this value. + * If your system doesn't support getenv(), define NO_GETENV to disable + * this feature. + */ +#ifndef NO_GETENV + { char * memenv; + + if ((memenv = getenv("JPEGMEM")) != NULL) { + char ch = 'x'; + + if (sscanf(memenv, "%ld%c", &max_to_use, &ch) > 0) { + if (ch == 'm' || ch == 'M') + max_to_use *= 1000L; + mem->pub.max_memory_to_use = max_to_use * 1000L; + } + } + } +#endif + +} diff --git a/mk4/modimage/jpeg-6b/jmemname.c b/mk4/modimage/jpeg-6b/jmemname.c new file mode 100644 index 0000000..ed96dee --- /dev/null +++ b/mk4/modimage/jpeg-6b/jmemname.c @@ -0,0 +1,276 @@ +/* + * jmemname.c + * + * Copyright (C) 1992-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file provides a generic implementation of the system-dependent + * portion of the JPEG memory manager. This implementation assumes that + * you must explicitly construct a name for each temp file. + * Also, the problem of determining the amount of memory available + * is shoved onto the user. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jmemsys.h" /* import the system-dependent declarations */ + +#ifndef HAVE_STDLIB_H /* should declare malloc(),free() */ +extern void * malloc JPP((size_t size)); +extern void free JPP((void *ptr)); +#endif + +#ifndef SEEK_SET /* pre-ANSI systems may not define this; */ +#define SEEK_SET 0 /* if not, assume 0 is correct */ +#endif + +#ifdef DONT_USE_B_MODE /* define mode parameters for fopen() */ +#define READ_BINARY "r" +#define RW_BINARY "w+" +#else +#ifdef VMS /* VMS is very nonstandard */ +#define READ_BINARY "rb", "ctx=stm" +#define RW_BINARY "w+b", "ctx=stm" +#else /* standard ANSI-compliant case */ +#define READ_BINARY "rb" +#define RW_BINARY "w+b" +#endif +#endif + + +/* + * Selection of a file name for a temporary file. + * This is system-dependent! + * + * The code as given is suitable for most Unix systems, and it is easily + * modified for most non-Unix systems. Some notes: + * 1. The temp file is created in the directory named by TEMP_DIRECTORY. + * The default value is /usr/tmp, which is the conventional place for + * creating large temp files on Unix. On other systems you'll probably + * want to change the file location. You can do this by editing the + * #define, or (preferred) by defining TEMP_DIRECTORY in jconfig.h. + * + * 2. If you need to change the file name as well as its location, + * you can override the TEMP_FILE_NAME macro. (Note that this is + * actually a printf format string; it must contain %s and %d.) + * Few people should need to do this. + * + * 3. mktemp() is used to ensure that multiple processes running + * simultaneously won't select the same file names. If your system + * doesn't have mktemp(), define NO_MKTEMP to do it the hard way. + * (If you don't have , also define NO_ERRNO_H.) + * + * 4. You probably want to define NEED_SIGNAL_CATCHER so that cjpeg.c/djpeg.c + * will cause the temp files to be removed if you stop the program early. + */ + +#ifndef TEMP_DIRECTORY /* can override from jconfig.h or Makefile */ +#define TEMP_DIRECTORY "/usr/tmp/" /* recommended setting for Unix */ +#endif + +static int next_file_num; /* to distinguish among several temp files */ + +#ifdef NO_MKTEMP + +#ifndef TEMP_FILE_NAME /* can override from jconfig.h or Makefile */ +#define TEMP_FILE_NAME "%sJPG%03d.TMP" +#endif + +#ifndef NO_ERRNO_H +#include /* to define ENOENT */ +#endif + +/* ANSI C specifies that errno is a macro, but on older systems it's more + * likely to be a plain int variable. And not all versions of errno.h + * bother to declare it, so we have to in order to be most portable. Thus: + */ +#ifndef errno +extern int errno; +#endif + + +LOCAL(void) +select_file_name (char * fname) +{ + FILE * tfile; + + /* Keep generating file names till we find one that's not in use */ + for (;;) { + next_file_num++; /* advance counter */ + sprintf(fname, TEMP_FILE_NAME, TEMP_DIRECTORY, next_file_num); + if ((tfile = fopen(fname, READ_BINARY)) == NULL) { + /* fopen could have failed for a reason other than the file not + * being there; for example, file there but unreadable. + * If isn't available, then we cannot test the cause. + */ +#ifdef ENOENT + if (errno != ENOENT) + continue; +#endif + break; + } + fclose(tfile); /* oops, it's there; close tfile & try again */ + } +} + +#else /* ! NO_MKTEMP */ + +/* Note that mktemp() requires the initial filename to end in six X's */ +#ifndef TEMP_FILE_NAME /* can override from jconfig.h or Makefile */ +#define TEMP_FILE_NAME "%sJPG%dXXXXXX" +#endif + +LOCAL(void) +select_file_name (char * fname) +{ + next_file_num++; /* advance counter */ + sprintf(fname, TEMP_FILE_NAME, TEMP_DIRECTORY, next_file_num); + mktemp(fname); /* make sure file name is unique */ + /* mktemp replaces the trailing XXXXXX with a unique string of characters */ +} + +#endif /* NO_MKTEMP */ + + +/* + * Memory allocation and freeing are controlled by the regular library + * routines malloc() and free(). + */ + +GLOBAL(void *) +jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject) +{ + return (void *) malloc(sizeofobject); +} + +GLOBAL(void) +jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject) +{ + free(object); +} + + +/* + * "Large" objects are treated the same as "small" ones. + * NB: although we include FAR keywords in the routine declarations, + * this file won't actually work in 80x86 small/medium model; at least, + * you probably won't be able to process useful-size images in only 64KB. + */ + +GLOBAL(void FAR *) +jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject) +{ + return (void FAR *) malloc(sizeofobject); +} + +GLOBAL(void) +jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject) +{ + free(object); +} + + +/* + * This routine computes the total memory space available for allocation. + * It's impossible to do this in a portable way; our current solution is + * to make the user tell us (with a default value set at compile time). + * If you can actually get the available space, it's a good idea to subtract + * a slop factor of 5% or so. + */ + +#ifndef DEFAULT_MAX_MEM /* so can override from makefile */ +#define DEFAULT_MAX_MEM 1000000L /* default: one megabyte */ +#endif + +GLOBAL(long) +jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed, + long max_bytes_needed, long already_allocated) +{ + return cinfo->mem->max_memory_to_use - already_allocated; +} + + +/* + * Backing store (temporary file) management. + * Backing store objects are only used when the value returned by + * jpeg_mem_available is less than the total space needed. You can dispense + * with these routines if you have plenty of virtual memory; see jmemnobs.c. + */ + + +METHODDEF(void) +read_backing_store (j_common_ptr cinfo, backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count) +{ + if (fseek(info->temp_file, file_offset, SEEK_SET)) + ERREXIT(cinfo, JERR_TFILE_SEEK); + if (JFREAD(info->temp_file, buffer_address, byte_count) + != (size_t) byte_count) + ERREXIT(cinfo, JERR_TFILE_READ); +} + + +METHODDEF(void) +write_backing_store (j_common_ptr cinfo, backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count) +{ + if (fseek(info->temp_file, file_offset, SEEK_SET)) + ERREXIT(cinfo, JERR_TFILE_SEEK); + if (JFWRITE(info->temp_file, buffer_address, byte_count) + != (size_t) byte_count) + ERREXIT(cinfo, JERR_TFILE_WRITE); +} + + +METHODDEF(void) +close_backing_store (j_common_ptr cinfo, backing_store_ptr info) +{ + fclose(info->temp_file); /* close the file */ + unlink(info->temp_name); /* delete the file */ +/* If your system doesn't have unlink(), use remove() instead. + * remove() is the ANSI-standard name for this function, but if + * your system was ANSI you'd be using jmemansi.c, right? + */ + TRACEMSS(cinfo, 1, JTRC_TFILE_CLOSE, info->temp_name); +} + + +/* + * Initial opening of a backing-store object. + */ + +GLOBAL(void) +jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info, + long total_bytes_needed) +{ + select_file_name(info->temp_name); + if ((info->temp_file = fopen(info->temp_name, RW_BINARY)) == NULL) + ERREXITS(cinfo, JERR_TFILE_CREATE, info->temp_name); + info->read_backing_store = read_backing_store; + info->write_backing_store = write_backing_store; + info->close_backing_store = close_backing_store; + TRACEMSS(cinfo, 1, JTRC_TFILE_OPEN, info->temp_name); +} + + +/* + * These routines take care of any system-dependent initialization and + * cleanup required. + */ + +GLOBAL(long) +jpeg_mem_init (j_common_ptr cinfo) +{ + next_file_num = 0; /* initialize temp file name generator */ + return DEFAULT_MAX_MEM; /* default for max_memory_to_use */ +} + +GLOBAL(void) +jpeg_mem_term (j_common_ptr cinfo) +{ + /* no work */ +} diff --git a/mk4/modimage/jpeg-6b/jmemnobs.c b/mk4/modimage/jpeg-6b/jmemnobs.c new file mode 100644 index 0000000..eb8c337 --- /dev/null +++ b/mk4/modimage/jpeg-6b/jmemnobs.c @@ -0,0 +1,109 @@ +/* + * jmemnobs.c + * + * Copyright (C) 1992-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file provides a really simple implementation of the system- + * dependent portion of the JPEG memory manager. This implementation + * assumes that no backing-store files are needed: all required space + * can be obtained from malloc(). + * This is very portable in the sense that it'll compile on almost anything, + * but you'd better have lots of main memory (or virtual memory) if you want + * to process big images. + * Note that the max_memory_to_use option is ignored by this implementation. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jmemsys.h" /* import the system-dependent declarations */ + +#ifndef HAVE_STDLIB_H /* should declare malloc(),free() */ +extern void * malloc JPP((size_t size)); +extern void free JPP((void *ptr)); +#endif + + +/* + * Memory allocation and freeing are controlled by the regular library + * routines malloc() and free(). + */ + +GLOBAL(void *) +jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject) +{ + return (void *) malloc(sizeofobject); +} + +GLOBAL(void) +jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject) +{ + free(object); +} + + +/* + * "Large" objects are treated the same as "small" ones. + * NB: although we include FAR keywords in the routine declarations, + * this file won't actually work in 80x86 small/medium model; at least, + * you probably won't be able to process useful-size images in only 64KB. + */ + +GLOBAL(void FAR *) +jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject) +{ + return (void FAR *) malloc(sizeofobject); +} + +GLOBAL(void) +jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject) +{ + free(object); +} + + +/* + * This routine computes the total memory space available for allocation. + * Here we always say, "we got all you want bud!" + */ + +GLOBAL(long) +jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed, + long max_bytes_needed, long already_allocated) +{ + return max_bytes_needed; +} + + +/* + * Backing store (temporary file) management. + * Since jpeg_mem_available always promised the moon, + * this should never be called and we can just error out. + */ + +GLOBAL(void) +jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info, + long total_bytes_needed) +{ + ERREXIT(cinfo, JERR_NO_BACKING_STORE); +} + + +/* + * These routines take care of any system-dependent initialization and + * cleanup required. Here, there isn't any. + */ + +GLOBAL(long) +jpeg_mem_init (j_common_ptr cinfo) +{ + return 0; /* just set max_memory_to_use to 0 */ +} + +GLOBAL(void) +jpeg_mem_term (j_common_ptr cinfo) +{ + /* no work */ +} diff --git a/mk4/modimage/jpeg-6b/jmemsys.h b/mk4/modimage/jpeg-6b/jmemsys.h new file mode 100644 index 0000000..6c3c6d3 --- /dev/null +++ b/mk4/modimage/jpeg-6b/jmemsys.h @@ -0,0 +1,198 @@ +/* + * jmemsys.h + * + * Copyright (C) 1992-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This include file defines the interface between the system-independent + * and system-dependent portions of the JPEG memory manager. No other + * modules need include it. (The system-independent portion is jmemmgr.c; + * there are several different versions of the system-dependent portion.) + * + * This file works as-is for the system-dependent memory managers supplied + * in the IJG distribution. You may need to modify it if you write a + * custom memory manager. If system-dependent changes are needed in + * this file, the best method is to #ifdef them based on a configuration + * symbol supplied in jconfig.h, as we have done with USE_MSDOS_MEMMGR + * and USE_MAC_MEMMGR. + */ + + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_get_small jGetSmall +#define jpeg_free_small jFreeSmall +#define jpeg_get_large jGetLarge +#define jpeg_free_large jFreeLarge +#define jpeg_mem_available jMemAvail +#define jpeg_open_backing_store jOpenBackStore +#define jpeg_mem_init jMemInit +#define jpeg_mem_term jMemTerm +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* + * These two functions are used to allocate and release small chunks of + * memory. (Typically the total amount requested through jpeg_get_small is + * no more than 20K or so; this will be requested in chunks of a few K each.) + * Behavior should be the same as for the standard library functions malloc + * and free; in particular, jpeg_get_small must return NULL on failure. + * On most systems, these ARE malloc and free. jpeg_free_small is passed the + * size of the object being freed, just in case it's needed. + * On an 80x86 machine using small-data memory model, these manage near heap. + */ + +EXTERN(void *) jpeg_get_small JPP((j_common_ptr cinfo, size_t sizeofobject)); +EXTERN(void) jpeg_free_small JPP((j_common_ptr cinfo, void * object, + size_t sizeofobject)); + +/* + * These two functions are used to allocate and release large chunks of + * memory (up to the total free space designated by jpeg_mem_available). + * The interface is the same as above, except that on an 80x86 machine, + * far pointers are used. On most other machines these are identical to + * the jpeg_get/free_small routines; but we keep them separate anyway, + * in case a different allocation strategy is desirable for large chunks. + */ + +EXTERN(void FAR *) jpeg_get_large JPP((j_common_ptr cinfo, + size_t sizeofobject)); +EXTERN(void) jpeg_free_large JPP((j_common_ptr cinfo, void FAR * object, + size_t sizeofobject)); + +/* + * The macro MAX_ALLOC_CHUNK designates the maximum number of bytes that may + * be requested in a single call to jpeg_get_large (and jpeg_get_small for that + * matter, but that case should never come into play). This macro is needed + * to model the 64Kb-segment-size limit of far addressing on 80x86 machines. + * On those machines, we expect that jconfig.h will provide a proper value. + * On machines with 32-bit flat address spaces, any large constant may be used. + * + * NB: jmemmgr.c expects that MAX_ALLOC_CHUNK will be representable as type + * size_t and will be a multiple of sizeof(align_type). + */ + +#ifndef MAX_ALLOC_CHUNK /* may be overridden in jconfig.h */ +#define MAX_ALLOC_CHUNK 1000000000L +#endif + +/* + * This routine computes the total space still available for allocation by + * jpeg_get_large. If more space than this is needed, backing store will be + * used. NOTE: any memory already allocated must not be counted. + * + * There is a minimum space requirement, corresponding to the minimum + * feasible buffer sizes; jmemmgr.c will request that much space even if + * jpeg_mem_available returns zero. The maximum space needed, enough to hold + * all working storage in memory, is also passed in case it is useful. + * Finally, the total space already allocated is passed. If no better + * method is available, cinfo->mem->max_memory_to_use - already_allocated + * is often a suitable calculation. + * + * It is OK for jpeg_mem_available to underestimate the space available + * (that'll just lead to more backing-store access than is really necessary). + * However, an overestimate will lead to failure. Hence it's wise to subtract + * a slop factor from the true available space. 5% should be enough. + * + * On machines with lots of virtual memory, any large constant may be returned. + * Conversely, zero may be returned to always use the minimum amount of memory. + */ + +EXTERN(long) jpeg_mem_available JPP((j_common_ptr cinfo, + long min_bytes_needed, + long max_bytes_needed, + long already_allocated)); + + +/* + * This structure holds whatever state is needed to access a single + * backing-store object. The read/write/close method pointers are called + * by jmemmgr.c to manipulate the backing-store object; all other fields + * are private to the system-dependent backing store routines. + */ + +#define TEMP_NAME_LENGTH 64 /* max length of a temporary file's name */ + + +#ifdef USE_MSDOS_MEMMGR /* DOS-specific junk */ + +typedef unsigned short XMSH; /* type of extended-memory handles */ +typedef unsigned short EMSH; /* type of expanded-memory handles */ + +typedef union { + short file_handle; /* DOS file handle if it's a temp file */ + XMSH xms_handle; /* handle if it's a chunk of XMS */ + EMSH ems_handle; /* handle if it's a chunk of EMS */ +} handle_union; + +#endif /* USE_MSDOS_MEMMGR */ + +#ifdef USE_MAC_MEMMGR /* Mac-specific junk */ +#include +#endif /* USE_MAC_MEMMGR */ + + +typedef struct backing_store_struct * backing_store_ptr; + +typedef struct backing_store_struct { + /* Methods for reading/writing/closing this backing-store object */ + JMETHOD(void, read_backing_store, (j_common_ptr cinfo, + backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count)); + JMETHOD(void, write_backing_store, (j_common_ptr cinfo, + backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count)); + JMETHOD(void, close_backing_store, (j_common_ptr cinfo, + backing_store_ptr info)); + + /* Private fields for system-dependent backing-store management */ +#ifdef USE_MSDOS_MEMMGR + /* For the MS-DOS manager (jmemdos.c), we need: */ + handle_union handle; /* reference to backing-store storage object */ + char temp_name[TEMP_NAME_LENGTH]; /* name if it's a file */ +#else +#ifdef USE_MAC_MEMMGR + /* For the Mac manager (jmemmac.c), we need: */ + short temp_file; /* file reference number to temp file */ + FSSpec tempSpec; /* the FSSpec for the temp file */ + char temp_name[TEMP_NAME_LENGTH]; /* name if it's a file */ +#else + /* For a typical implementation with temp files, we need: */ + FILE * temp_file; /* stdio reference to temp file */ + char temp_name[TEMP_NAME_LENGTH]; /* name of temp file */ +#endif +#endif +} backing_store_info; + + +/* + * Initial opening of a backing-store object. This must fill in the + * read/write/close pointers in the object. The read/write routines + * may take an error exit if the specified maximum file size is exceeded. + * (If jpeg_mem_available always returns a large value, this routine can + * just take an error exit.) + */ + +EXTERN(void) jpeg_open_backing_store JPP((j_common_ptr cinfo, + backing_store_ptr info, + long total_bytes_needed)); + + +/* + * These routines take care of any system-dependent initialization and + * cleanup required. jpeg_mem_init will be called before anything is + * allocated (and, therefore, nothing in cinfo is of use except the error + * manager pointer). It should return a suitable default value for + * max_memory_to_use; this may subsequently be overridden by the surrounding + * application. (Note that max_memory_to_use is only important if + * jpeg_mem_available chooses to consult it ... no one else will.) + * jpeg_mem_term may assume that all requested memory has been freed and that + * all opened backing-store objects have been closed. + */ + +EXTERN(long) jpeg_mem_init JPP((j_common_ptr cinfo)); +EXTERN(void) jpeg_mem_term JPP((j_common_ptr cinfo)); diff --git a/mk4/modimage/jpeg-6b/jmorecfg.h b/mk4/modimage/jpeg-6b/jmorecfg.h new file mode 100644 index 0000000..54a7d1c --- /dev/null +++ b/mk4/modimage/jpeg-6b/jmorecfg.h @@ -0,0 +1,363 @@ +/* + * jmorecfg.h + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains additional configuration options that customize the + * JPEG software for special applications or support machine-dependent + * optimizations. Most users will not need to touch this file. + */ + + +/* + * Define BITS_IN_JSAMPLE as either + * 8 for 8-bit sample values (the usual setting) + * 12 for 12-bit sample values + * Only 8 and 12 are legal data precisions for lossy JPEG according to the + * JPEG standard, and the IJG code does not support anything else! + * We do not support run-time selection of data precision, sorry. + */ + +#define BITS_IN_JSAMPLE 8 /* use 8 or 12 */ + + +/* + * Maximum number of components (color channels) allowed in JPEG image. + * To meet the letter of the JPEG spec, set this to 255. However, darn + * few applications need more than 4 channels (maybe 5 for CMYK + alpha + * mask). We recommend 10 as a reasonable compromise; use 4 if you are + * really short on memory. (Each allowed component costs a hundred or so + * bytes of storage, whether actually used in an image or not.) + */ + +#define MAX_COMPONENTS 10 /* maximum number of image components */ + + +/* + * Basic data types. + * You may need to change these if you have a machine with unusual data + * type sizes; for example, "char" not 8 bits, "short" not 16 bits, + * or "long" not 32 bits. We don't care whether "int" is 16 or 32 bits, + * but it had better be at least 16. + */ + +/* Representation of a single sample (pixel element value). + * We frequently allocate large arrays of these, so it's important to keep + * them small. But if you have memory to burn and access to char or short + * arrays is very slow on your hardware, you might want to change these. + */ + +#if BITS_IN_JSAMPLE == 8 +/* JSAMPLE should be the smallest type that will hold the values 0..255. + * You can use a signed char by having GETJSAMPLE mask it with 0xFF. + */ + +#ifdef HAVE_UNSIGNED_CHAR + +typedef unsigned char JSAMPLE; +#define GETJSAMPLE(value) ((int) (value)) + +#else /* not HAVE_UNSIGNED_CHAR */ + +typedef char JSAMPLE; +#ifdef CHAR_IS_UNSIGNED +#define GETJSAMPLE(value) ((int) (value)) +#else +#define GETJSAMPLE(value) ((int) (value) & 0xFF) +#endif /* CHAR_IS_UNSIGNED */ + +#endif /* HAVE_UNSIGNED_CHAR */ + +#define MAXJSAMPLE 255 +#define CENTERJSAMPLE 128 + +#endif /* BITS_IN_JSAMPLE == 8 */ + + +#if BITS_IN_JSAMPLE == 12 +/* JSAMPLE should be the smallest type that will hold the values 0..4095. + * On nearly all machines "short" will do nicely. + */ + +typedef short JSAMPLE; +#define GETJSAMPLE(value) ((int) (value)) + +#define MAXJSAMPLE 4095 +#define CENTERJSAMPLE 2048 + +#endif /* BITS_IN_JSAMPLE == 12 */ + + +/* Representation of a DCT frequency coefficient. + * This should be a signed value of at least 16 bits; "short" is usually OK. + * Again, we allocate large arrays of these, but you can change to int + * if you have memory to burn and "short" is really slow. + */ + +typedef short JCOEF; + + +/* Compressed datastreams are represented as arrays of JOCTET. + * These must be EXACTLY 8 bits wide, at least once they are written to + * external storage. Note that when using the stdio data source/destination + * managers, this is also the data type passed to fread/fwrite. + */ + +#ifdef HAVE_UNSIGNED_CHAR + +typedef unsigned char JOCTET; +#define GETJOCTET(value) (value) + +#else /* not HAVE_UNSIGNED_CHAR */ + +typedef char JOCTET; +#ifdef CHAR_IS_UNSIGNED +#define GETJOCTET(value) (value) +#else +#define GETJOCTET(value) ((value) & 0xFF) +#endif /* CHAR_IS_UNSIGNED */ + +#endif /* HAVE_UNSIGNED_CHAR */ + + +/* These typedefs are used for various table entries and so forth. + * They must be at least as wide as specified; but making them too big + * won't cost a huge amount of memory, so we don't provide special + * extraction code like we did for JSAMPLE. (In other words, these + * typedefs live at a different point on the speed/space tradeoff curve.) + */ + +/* UINT8 must hold at least the values 0..255. */ + +#ifdef HAVE_UNSIGNED_CHAR +typedef unsigned char UINT8; +#else /* not HAVE_UNSIGNED_CHAR */ +#ifdef CHAR_IS_UNSIGNED +typedef char UINT8; +#else /* not CHAR_IS_UNSIGNED */ +typedef short UINT8; +#endif /* CHAR_IS_UNSIGNED */ +#endif /* HAVE_UNSIGNED_CHAR */ + +/* UINT16 must hold at least the values 0..65535. */ + +#ifdef HAVE_UNSIGNED_SHORT +typedef unsigned short UINT16; +#else /* not HAVE_UNSIGNED_SHORT */ +typedef unsigned int UINT16; +#endif /* HAVE_UNSIGNED_SHORT */ + +/* INT16 must hold at least the values -32768..32767. */ + +#ifndef XMD_H /* X11/xmd.h correctly defines INT16 */ +typedef short INT16; +#endif + +/* INT32 must hold at least signed 32-bit values. */ + +#ifndef XMD_H /* X11/xmd.h correctly defines INT32 */ +typedef long INT32; +#endif + +/* Datatype used for image dimensions. The JPEG standard only supports + * images up to 64K*64K due to 16-bit fields in SOF markers. Therefore + * "unsigned int" is sufficient on all machines. However, if you need to + * handle larger images and you don't mind deviating from the spec, you + * can change this datatype. + */ + +typedef unsigned int JDIMENSION; + +#define JPEG_MAX_DIMENSION 65500L /* a tad under 64K to prevent overflows */ + + +/* These macros are used in all function definitions and extern declarations. + * You could modify them if you need to change function linkage conventions; + * in particular, you'll need to do that to make the library a Windows DLL. + * Another application is to make all functions global for use with debuggers + * or code profilers that require it. + */ + +/* a function called through method pointers: */ +#define METHODDEF(type) static type +/* a function used only in its module: */ +#define LOCAL(type) static type +/* a function referenced thru EXTERNs: */ +#define GLOBAL(type) type +/* a reference to a GLOBAL function: */ +#define EXTERN(type) extern type + + +/* This macro is used to declare a "method", that is, a function pointer. + * We want to supply prototype parameters if the compiler can cope. + * Note that the arglist parameter must be parenthesized! + * Again, you can customize this if you need special linkage keywords. + */ + +#ifdef HAVE_PROTOTYPES +#define JMETHOD(type,methodname,arglist) type (*methodname) arglist +#else +#define JMETHOD(type,methodname,arglist) type (*methodname) () +#endif + + +/* Here is the pseudo-keyword for declaring pointers that must be "far" + * on 80x86 machines. Most of the specialized coding for 80x86 is handled + * by just saying "FAR *" where such a pointer is needed. In a few places + * explicit coding is needed; see uses of the NEED_FAR_POINTERS symbol. + */ + +#ifdef NEED_FAR_POINTERS +#define FAR far +#else +#define FAR +#endif + + +/* + * On a few systems, type boolean and/or its values FALSE, TRUE may appear + * in standard header files. Or you may have conflicts with application- + * specific header files that you want to include together with these files. + * Defining HAVE_BOOLEAN before including jpeglib.h should make it work. + */ + +#ifndef HAVE_BOOLEAN +typedef int boolean; +#endif +#ifndef FALSE /* in case these macros already exist */ +#define FALSE 0 /* values of boolean */ +#endif +#ifndef TRUE +#define TRUE 1 +#endif + + +/* + * The remaining options affect code selection within the JPEG library, + * but they don't need to be visible to most applications using the library. + * To minimize application namespace pollution, the symbols won't be + * defined unless JPEG_INTERNALS or JPEG_INTERNAL_OPTIONS has been defined. + */ + +#ifdef JPEG_INTERNALS +#define JPEG_INTERNAL_OPTIONS +#endif + +#ifdef JPEG_INTERNAL_OPTIONS + + +/* + * These defines indicate whether to include various optional functions. + * Undefining some of these symbols will produce a smaller but less capable + * library. Note that you can leave certain source files out of the + * compilation/linking process if you've #undef'd the corresponding symbols. + * (You may HAVE to do that if your compiler doesn't like null source files.) + */ + +/* Arithmetic coding is unsupported for legal reasons. Complaints to IBM. */ + +/* Capability options common to encoder and decoder: */ + +#define DCT_ISLOW_SUPPORTED /* slow but accurate integer algorithm */ +#define DCT_IFAST_SUPPORTED /* faster, less accurate integer method */ +#define DCT_FLOAT_SUPPORTED /* floating-point: accurate, fast on fast HW */ + +/* Encoder capability options: */ + +#undef C_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */ +#define C_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ +#define C_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/ +#define ENTROPY_OPT_SUPPORTED /* Optimization of entropy coding parms? */ +/* Note: if you selected 12-bit data precision, it is dangerous to turn off + * ENTROPY_OPT_SUPPORTED. The standard Huffman tables are only good for 8-bit + * precision, so jchuff.c normally uses entropy optimization to compute + * usable tables for higher precision. If you don't want to do optimization, + * you'll have to supply different default Huffman tables. + * The exact same statements apply for progressive JPEG: the default tables + * don't work for progressive mode. (This may get fixed, however.) + */ +#define INPUT_SMOOTHING_SUPPORTED /* Input image smoothing option? */ + +/* Decoder capability options: */ + +#undef D_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */ +#define D_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ +#define D_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/ +#define SAVE_MARKERS_SUPPORTED /* jpeg_save_markers() needed? */ +#define BLOCK_SMOOTHING_SUPPORTED /* Block smoothing? (Progressive only) */ +#define IDCT_SCALING_SUPPORTED /* Output rescaling via IDCT? */ +#undef UPSAMPLE_SCALING_SUPPORTED /* Output rescaling at upsample stage? */ +#define UPSAMPLE_MERGING_SUPPORTED /* Fast path for sloppy upsampling? */ +#define QUANT_1PASS_SUPPORTED /* 1-pass color quantization? */ +#define QUANT_2PASS_SUPPORTED /* 2-pass color quantization? */ + +/* more capability options later, no doubt */ + + +/* + * Ordering of RGB data in scanlines passed to or from the application. + * If your application wants to deal with data in the order B,G,R, just + * change these macros. You can also deal with formats such as R,G,B,X + * (one extra byte per pixel) by changing RGB_PIXELSIZE. Note that changing + * the offsets will also change the order in which colormap data is organized. + * RESTRICTIONS: + * 1. The sample applications cjpeg,djpeg do NOT support modified RGB formats. + * 2. These macros only affect RGB<=>YCbCr color conversion, so they are not + * useful if you are using JPEG color spaces other than YCbCr or grayscale. + * 3. The color quantizer modules will not behave desirably if RGB_PIXELSIZE + * is not 3 (they don't understand about dummy color components!). So you + * can't use color quantization if you change that value. + */ + +#define RGB_RED 0 /* Offset of Red in an RGB scanline element */ +#define RGB_GREEN 1 /* Offset of Green */ +#define RGB_BLUE 2 /* Offset of Blue */ +#define RGB_PIXELSIZE 3 /* JSAMPLEs per RGB scanline element */ + + +/* Definitions for speed-related optimizations. */ + + +/* If your compiler supports inline functions, define INLINE + * as the inline keyword; otherwise define it as empty. + */ + +#ifndef INLINE +#ifdef __GNUC__ /* for instance, GNU C knows about inline */ +#define INLINE __inline__ +#endif +#ifndef INLINE +#define INLINE /* default is to define it as empty */ +#endif +#endif + + +/* On some machines (notably 68000 series) "int" is 32 bits, but multiplying + * two 16-bit shorts is faster than multiplying two ints. Define MULTIPLIER + * as short on such a machine. MULTIPLIER must be at least 16 bits wide. + */ + +#ifndef MULTIPLIER +#define MULTIPLIER int /* type for fastest integer multiply */ +#endif + + +/* FAST_FLOAT should be either float or double, whichever is done faster + * by your compiler. (Note that this type is only used in the floating point + * DCT routines, so it only matters if you've defined DCT_FLOAT_SUPPORTED.) + * Typically, float is faster in ANSI C compilers, while double is faster in + * pre-ANSI compilers (because they insist on converting to double anyway). + * The code below therefore chooses float if we have ANSI-style prototypes. + */ + +#ifndef FAST_FLOAT +#ifdef HAVE_PROTOTYPES +#define FAST_FLOAT float +#else +#define FAST_FLOAT double +#endif +#endif + +#endif /* JPEG_INTERNAL_OPTIONS */ diff --git a/mk4/modimage/jpeg-6b/jpegint.h b/mk4/modimage/jpeg-6b/jpegint.h new file mode 100644 index 0000000..95b00d4 --- /dev/null +++ b/mk4/modimage/jpeg-6b/jpegint.h @@ -0,0 +1,392 @@ +/* + * jpegint.h + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file provides common declarations for the various JPEG modules. + * These declarations are considered internal to the JPEG library; most + * applications using the library shouldn't need to include this file. + */ + + +/* Declarations for both compression & decompression */ + +typedef enum { /* Operating modes for buffer controllers */ + JBUF_PASS_THRU, /* Plain stripwise operation */ + /* Remaining modes require a full-image buffer to have been created */ + JBUF_SAVE_SOURCE, /* Run source subobject only, save output */ + JBUF_CRANK_DEST, /* Run dest subobject only, using saved data */ + JBUF_SAVE_AND_PASS /* Run both subobjects, save output */ +} J_BUF_MODE; + +/* Values of global_state field (jdapi.c has some dependencies on ordering!) */ +#define CSTATE_START 100 /* after create_compress */ +#define CSTATE_SCANNING 101 /* start_compress done, write_scanlines OK */ +#define CSTATE_RAW_OK 102 /* start_compress done, write_raw_data OK */ +#define CSTATE_WRCOEFS 103 /* jpeg_write_coefficients done */ +#define DSTATE_START 200 /* after create_decompress */ +#define DSTATE_INHEADER 201 /* reading header markers, no SOS yet */ +#define DSTATE_READY 202 /* found SOS, ready for start_decompress */ +#define DSTATE_PRELOAD 203 /* reading multiscan file in start_decompress*/ +#define DSTATE_PRESCAN 204 /* performing dummy pass for 2-pass quant */ +#define DSTATE_SCANNING 205 /* start_decompress done, read_scanlines OK */ +#define DSTATE_RAW_OK 206 /* start_decompress done, read_raw_data OK */ +#define DSTATE_BUFIMAGE 207 /* expecting jpeg_start_output */ +#define DSTATE_BUFPOST 208 /* looking for SOS/EOI in jpeg_finish_output */ +#define DSTATE_RDCOEFS 209 /* reading file in jpeg_read_coefficients */ +#define DSTATE_STOPPING 210 /* looking for EOI in jpeg_finish_decompress */ + + +/* Declarations for compression modules */ + +/* Master control module */ +struct jpeg_comp_master { + JMETHOD(void, prepare_for_pass, (j_compress_ptr cinfo)); + JMETHOD(void, pass_startup, (j_compress_ptr cinfo)); + JMETHOD(void, finish_pass, (j_compress_ptr cinfo)); + + /* State variables made visible to other modules */ + boolean call_pass_startup; /* True if pass_startup must be called */ + boolean is_last_pass; /* True during last pass */ +}; + +/* Main buffer control (downsampled-data buffer) */ +struct jpeg_c_main_controller { + JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(void, process_data, (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail)); +}; + +/* Compression preprocessing (downsampling input buffer control) */ +struct jpeg_c_prep_controller { + JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(void, pre_process_data, (j_compress_ptr cinfo, + JSAMPARRAY input_buf, + JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail, + JSAMPIMAGE output_buf, + JDIMENSION *out_row_group_ctr, + JDIMENSION out_row_groups_avail)); +}; + +/* Coefficient buffer control */ +struct jpeg_c_coef_controller { + JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(boolean, compress_data, (j_compress_ptr cinfo, + JSAMPIMAGE input_buf)); +}; + +/* Colorspace conversion */ +struct jpeg_color_converter { + JMETHOD(void, start_pass, (j_compress_ptr cinfo)); + JMETHOD(void, color_convert, (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows)); +}; + +/* Downsampling */ +struct jpeg_downsampler { + JMETHOD(void, start_pass, (j_compress_ptr cinfo)); + JMETHOD(void, downsample, (j_compress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION in_row_index, + JSAMPIMAGE output_buf, + JDIMENSION out_row_group_index)); + + boolean need_context_rows; /* TRUE if need rows above & below */ +}; + +/* Forward DCT (also controls coefficient quantization) */ +struct jpeg_forward_dct { + JMETHOD(void, start_pass, (j_compress_ptr cinfo)); + /* perhaps this should be an array??? */ + JMETHOD(void, forward_DCT, (j_compress_ptr cinfo, + jpeg_component_info * compptr, + JSAMPARRAY sample_data, JBLOCKROW coef_blocks, + JDIMENSION start_row, JDIMENSION start_col, + JDIMENSION num_blocks)); +}; + +/* Entropy encoding */ +struct jpeg_entropy_encoder { + JMETHOD(void, start_pass, (j_compress_ptr cinfo, boolean gather_statistics)); + JMETHOD(boolean, encode_mcu, (j_compress_ptr cinfo, JBLOCKROW *MCU_data)); + JMETHOD(void, finish_pass, (j_compress_ptr cinfo)); +}; + +/* Marker writing */ +struct jpeg_marker_writer { + JMETHOD(void, write_file_header, (j_compress_ptr cinfo)); + JMETHOD(void, write_frame_header, (j_compress_ptr cinfo)); + JMETHOD(void, write_scan_header, (j_compress_ptr cinfo)); + JMETHOD(void, write_file_trailer, (j_compress_ptr cinfo)); + JMETHOD(void, write_tables_only, (j_compress_ptr cinfo)); + /* These routines are exported to allow insertion of extra markers */ + /* Probably only COM and APPn markers should be written this way */ + JMETHOD(void, write_marker_header, (j_compress_ptr cinfo, int marker, + unsigned int datalen)); + JMETHOD(void, write_marker_byte, (j_compress_ptr cinfo, int val)); +}; + + +/* Declarations for decompression modules */ + +/* Master control module */ +struct jpeg_decomp_master { + JMETHOD(void, prepare_for_output_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, finish_output_pass, (j_decompress_ptr cinfo)); + + /* State variables made visible to other modules */ + boolean is_dummy_pass; /* True during 1st pass for 2-pass quant */ +}; + +/* Input control module */ +struct jpeg_input_controller { + JMETHOD(int, consume_input, (j_decompress_ptr cinfo)); + JMETHOD(void, reset_input_controller, (j_decompress_ptr cinfo)); + JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, finish_input_pass, (j_decompress_ptr cinfo)); + + /* State variables made visible to other modules */ + boolean has_multiple_scans; /* True if file has multiple scans */ + boolean eoi_reached; /* True when EOI has been consumed */ +}; + +/* Main buffer control (downsampled-data buffer) */ +struct jpeg_d_main_controller { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(void, process_data, (j_decompress_ptr cinfo, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); +}; + +/* Coefficient buffer control */ +struct jpeg_d_coef_controller { + JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo)); + JMETHOD(int, consume_data, (j_decompress_ptr cinfo)); + JMETHOD(void, start_output_pass, (j_decompress_ptr cinfo)); + JMETHOD(int, decompress_data, (j_decompress_ptr cinfo, + JSAMPIMAGE output_buf)); + /* Pointer to array of coefficient virtual arrays, or NULL if none */ + jvirt_barray_ptr *coef_arrays; +}; + +/* Decompression postprocessing (color quantization buffer control) */ +struct jpeg_d_post_controller { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(void, post_process_data, (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, + JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, + JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); +}; + +/* Marker reading & parsing */ +struct jpeg_marker_reader { + JMETHOD(void, reset_marker_reader, (j_decompress_ptr cinfo)); + /* Read markers until SOS or EOI. + * Returns same codes as are defined for jpeg_consume_input: + * JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI. + */ + JMETHOD(int, read_markers, (j_decompress_ptr cinfo)); + /* Read a restart marker --- exported for use by entropy decoder only */ + jpeg_marker_parser_method read_restart_marker; + + /* State of marker reader --- nominally internal, but applications + * supplying COM or APPn handlers might like to know the state. + */ + boolean saw_SOI; /* found SOI? */ + boolean saw_SOF; /* found SOF? */ + int next_restart_num; /* next restart number expected (0-7) */ + unsigned int discarded_bytes; /* # of bytes skipped looking for a marker */ +}; + +/* Entropy decoding */ +struct jpeg_entropy_decoder { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + JMETHOD(boolean, decode_mcu, (j_decompress_ptr cinfo, + JBLOCKROW *MCU_data)); + + /* This is here to share code between baseline and progressive decoders; */ + /* other modules probably should not use it */ + boolean insufficient_data; /* set TRUE after emitting warning */ +}; + +/* Inverse DCT (also performs dequantization) */ +typedef JMETHOD(void, inverse_DCT_method_ptr, + (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col)); + +struct jpeg_inverse_dct { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + /* It is useful to allow each component to have a separate IDCT method. */ + inverse_DCT_method_ptr inverse_DCT[MAX_COMPONENTS]; +}; + +/* Upsampling (note that upsampler must also call color converter) */ +struct jpeg_upsampler { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, upsample, (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, + JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, + JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); + + boolean need_context_rows; /* TRUE if need rows above & below */ +}; + +/* Colorspace conversion */ +struct jpeg_color_deconverter { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, color_convert, (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows)); +}; + +/* Color quantization or color precision reduction */ +struct jpeg_color_quantizer { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo, boolean is_pre_scan)); + JMETHOD(void, color_quantize, (j_decompress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPARRAY output_buf, + int num_rows)); + JMETHOD(void, finish_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, new_color_map, (j_decompress_ptr cinfo)); +}; + + +/* Miscellaneous useful macros */ + +#undef MAX +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#undef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) + + +/* We assume that right shift corresponds to signed division by 2 with + * rounding towards minus infinity. This is correct for typical "arithmetic + * shift" instructions that shift in copies of the sign bit. But some + * C compilers implement >> with an unsigned shift. For these machines you + * must define RIGHT_SHIFT_IS_UNSIGNED. + * RIGHT_SHIFT provides a proper signed right shift of an INT32 quantity. + * It is only applied with constant shift counts. SHIFT_TEMPS must be + * included in the variables of any routine using RIGHT_SHIFT. + */ + +#ifdef RIGHT_SHIFT_IS_UNSIGNED +#define SHIFT_TEMPS INT32 shift_temp; +#define RIGHT_SHIFT(x,shft) \ + ((shift_temp = (x)) < 0 ? \ + (shift_temp >> (shft)) | ((~((INT32) 0)) << (32-(shft))) : \ + (shift_temp >> (shft))) +#else +#define SHIFT_TEMPS +#define RIGHT_SHIFT(x,shft) ((x) >> (shft)) +#endif + + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jinit_compress_master jICompress +#define jinit_c_master_control jICMaster +#define jinit_c_main_controller jICMainC +#define jinit_c_prep_controller jICPrepC +#define jinit_c_coef_controller jICCoefC +#define jinit_color_converter jICColor +#define jinit_downsampler jIDownsampler +#define jinit_forward_dct jIFDCT +#define jinit_huff_encoder jIHEncoder +#define jinit_phuff_encoder jIPHEncoder +#define jinit_marker_writer jIMWriter +#define jinit_master_decompress jIDMaster +#define jinit_d_main_controller jIDMainC +#define jinit_d_coef_controller jIDCoefC +#define jinit_d_post_controller jIDPostC +#define jinit_input_controller jIInCtlr +#define jinit_marker_reader jIMReader +#define jinit_huff_decoder jIHDecoder +#define jinit_phuff_decoder jIPHDecoder +#define jinit_inverse_dct jIIDCT +#define jinit_upsampler jIUpsampler +#define jinit_color_deconverter jIDColor +#define jinit_1pass_quantizer jI1Quant +#define jinit_2pass_quantizer jI2Quant +#define jinit_merged_upsampler jIMUpsampler +#define jinit_memory_mgr jIMemMgr +#define jdiv_round_up jDivRound +#define jround_up jRound +#define jcopy_sample_rows jCopySamples +#define jcopy_block_row jCopyBlocks +#define jzero_far jZeroFar +#define jpeg_zigzag_order jZIGTable +#define jpeg_natural_order jZAGTable +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* Compression module initialization routines */ +EXTERN(void) jinit_compress_master JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_c_master_control JPP((j_compress_ptr cinfo, + boolean transcode_only)); +EXTERN(void) jinit_c_main_controller JPP((j_compress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_c_prep_controller JPP((j_compress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_c_coef_controller JPP((j_compress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_color_converter JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_downsampler JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_forward_dct JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_huff_encoder JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_phuff_encoder JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_marker_writer JPP((j_compress_ptr cinfo)); +/* Decompression module initialization routines */ +EXTERN(void) jinit_master_decompress JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_d_main_controller JPP((j_decompress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_d_coef_controller JPP((j_decompress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_d_post_controller JPP((j_decompress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_input_controller JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_marker_reader JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_huff_decoder JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_phuff_decoder JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_inverse_dct JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_upsampler JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_color_deconverter JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_1pass_quantizer JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_2pass_quantizer JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_merged_upsampler JPP((j_decompress_ptr cinfo)); +/* Memory manager initialization */ +EXTERN(void) jinit_memory_mgr JPP((j_common_ptr cinfo)); + +/* Utility routines in jutils.c */ +EXTERN(long) jdiv_round_up JPP((long a, long b)); +EXTERN(long) jround_up JPP((long a, long b)); +EXTERN(void) jcopy_sample_rows JPP((JSAMPARRAY input_array, int source_row, + JSAMPARRAY output_array, int dest_row, + int num_rows, JDIMENSION num_cols)); +EXTERN(void) jcopy_block_row JPP((JBLOCKROW input_row, JBLOCKROW output_row, + JDIMENSION num_blocks)); +EXTERN(void) jzero_far JPP((void FAR * target, size_t bytestozero)); +/* Constant tables in jutils.c */ +#if 0 /* This table is not actually needed in v6a */ +extern const int jpeg_zigzag_order[]; /* natural coef order to zigzag order */ +#endif +extern const int jpeg_natural_order[]; /* zigzag coef order to natural order */ + +/* Suppress undefined-structure complaints if necessary. */ + +#ifdef INCOMPLETE_TYPES_BROKEN +#ifndef AM_MEMORY_MANAGER /* only jmemmgr.c defines these */ +struct jvirt_sarray_control { long dummy; }; +struct jvirt_barray_control { long dummy; }; +#endif +#endif /* INCOMPLETE_TYPES_BROKEN */ diff --git a/mk4/modimage/jpeg-6b/jpeglib.h b/mk4/modimage/jpeg-6b/jpeglib.h new file mode 100644 index 0000000..d1be8dd --- /dev/null +++ b/mk4/modimage/jpeg-6b/jpeglib.h @@ -0,0 +1,1096 @@ +/* + * jpeglib.h + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file defines the application interface for the JPEG library. + * Most applications using the library need only include this file, + * and perhaps jerror.h if they want to know the exact error codes. + */ + +#ifndef JPEGLIB_H +#define JPEGLIB_H + +/* + * First we include the configuration files that record how this + * installation of the JPEG library is set up. jconfig.h can be + * generated automatically for many systems. jmorecfg.h contains + * manual configuration options that most people need not worry about. + */ + +#ifndef JCONFIG_INCLUDED /* in case jinclude.h already did */ +#include "jconfig.h" /* widely used configuration options */ +#endif +#include "jmorecfg.h" /* seldom changed options */ + + +/* Version ID for the JPEG library. + * Might be useful for tests like "#if JPEG_LIB_VERSION >= 60". + */ + +#define JPEG_LIB_VERSION 62 /* Version 6b */ + + +/* Various constants determining the sizes of things. + * All of these are specified by the JPEG standard, so don't change them + * if you want to be compatible. + */ + +#define DCTSIZE 8 /* The basic DCT block is 8x8 samples */ +#define DCTSIZE2 64 /* DCTSIZE squared; # of elements in a block */ +#define NUM_QUANT_TBLS 4 /* Quantization tables are numbered 0..3 */ +#define NUM_HUFF_TBLS 4 /* Huffman tables are numbered 0..3 */ +#define NUM_ARITH_TBLS 16 /* Arith-coding tables are numbered 0..15 */ +#define MAX_COMPS_IN_SCAN 4 /* JPEG limit on # of components in one scan */ +#define MAX_SAMP_FACTOR 4 /* JPEG limit on sampling factors */ +/* Unfortunately, some bozo at Adobe saw no reason to be bound by the standard; + * the PostScript DCT filter can emit files with many more than 10 blocks/MCU. + * If you happen to run across such a file, you can up D_MAX_BLOCKS_IN_MCU + * to handle it. We even let you do this from the jconfig.h file. However, + * we strongly discourage changing C_MAX_BLOCKS_IN_MCU; just because Adobe + * sometimes emits noncompliant files doesn't mean you should too. + */ +#define C_MAX_BLOCKS_IN_MCU 10 /* compressor's limit on blocks per MCU */ +#ifndef D_MAX_BLOCKS_IN_MCU +#define D_MAX_BLOCKS_IN_MCU 10 /* decompressor's limit on blocks per MCU */ +#endif + + +/* Data structures for images (arrays of samples and of DCT coefficients). + * On 80x86 machines, the image arrays are too big for near pointers, + * but the pointer arrays can fit in near memory. + */ + +typedef JSAMPLE FAR *JSAMPROW; /* ptr to one image row of pixel samples. */ +typedef JSAMPROW *JSAMPARRAY; /* ptr to some rows (a 2-D sample array) */ +typedef JSAMPARRAY *JSAMPIMAGE; /* a 3-D sample array: top index is color */ + +typedef JCOEF JBLOCK[DCTSIZE2]; /* one block of coefficients */ +typedef JBLOCK FAR *JBLOCKROW; /* pointer to one row of coefficient blocks */ +typedef JBLOCKROW *JBLOCKARRAY; /* a 2-D array of coefficient blocks */ +typedef JBLOCKARRAY *JBLOCKIMAGE; /* a 3-D array of coefficient blocks */ + +typedef JCOEF FAR *JCOEFPTR; /* useful in a couple of places */ + + +/* Types for JPEG compression parameters and working tables. */ + + +/* DCT coefficient quantization tables. */ + +typedef struct { + /* This array gives the coefficient quantizers in natural array order + * (not the zigzag order in which they are stored in a JPEG DQT marker). + * CAUTION: IJG versions prior to v6a kept this array in zigzag order. + */ + UINT16 quantval[DCTSIZE2]; /* quantization step for each coefficient */ + /* This field is used only during compression. It's initialized FALSE when + * the table is created, and set TRUE when it's been output to the file. + * You could suppress output of a table by setting this to TRUE. + * (See jpeg_suppress_tables for an example.) + */ + boolean sent_table; /* TRUE when table has been output */ +} JQUANT_TBL; + + +/* Huffman coding tables. */ + +typedef struct { + /* These two fields directly represent the contents of a JPEG DHT marker */ + UINT8 bits[17]; /* bits[k] = # of symbols with codes of */ + /* length k bits; bits[0] is unused */ + UINT8 huffval[256]; /* The symbols, in order of incr code length */ + /* This field is used only during compression. It's initialized FALSE when + * the table is created, and set TRUE when it's been output to the file. + * You could suppress output of a table by setting this to TRUE. + * (See jpeg_suppress_tables for an example.) + */ + boolean sent_table; /* TRUE when table has been output */ +} JHUFF_TBL; + + +/* Basic info about one component (color channel). */ + +typedef struct { + /* These values are fixed over the whole image. */ + /* For compression, they must be supplied by parameter setup; */ + /* for decompression, they are read from the SOF marker. */ + int component_id; /* identifier for this component (0..255) */ + int component_index; /* its index in SOF or cinfo->comp_info[] */ + int h_samp_factor; /* horizontal sampling factor (1..4) */ + int v_samp_factor; /* vertical sampling factor (1..4) */ + int quant_tbl_no; /* quantization table selector (0..3) */ + /* These values may vary between scans. */ + /* For compression, they must be supplied by parameter setup; */ + /* for decompression, they are read from the SOS marker. */ + /* The decompressor output side may not use these variables. */ + int dc_tbl_no; /* DC entropy table selector (0..3) */ + int ac_tbl_no; /* AC entropy table selector (0..3) */ + + /* Remaining fields should be treated as private by applications. */ + + /* These values are computed during compression or decompression startup: */ + /* Component's size in DCT blocks. + * Any dummy blocks added to complete an MCU are not counted; therefore + * these values do not depend on whether a scan is interleaved or not. + */ + JDIMENSION width_in_blocks; + JDIMENSION height_in_blocks; + /* Size of a DCT block in samples. Always DCTSIZE for compression. + * For decompression this is the size of the output from one DCT block, + * reflecting any scaling we choose to apply during the IDCT step. + * Values of 1,2,4,8 are likely to be supported. Note that different + * components may receive different IDCT scalings. + */ + int DCT_scaled_size; + /* The downsampled dimensions are the component's actual, unpadded number + * of samples at the main buffer (preprocessing/compression interface), thus + * downsampled_width = ceil(image_width * Hi/Hmax) + * and similarly for height. For decompression, IDCT scaling is included, so + * downsampled_width = ceil(image_width * Hi/Hmax * DCT_scaled_size/DCTSIZE) + */ + JDIMENSION downsampled_width; /* actual width in samples */ + JDIMENSION downsampled_height; /* actual height in samples */ + /* This flag is used only for decompression. In cases where some of the + * components will be ignored (eg grayscale output from YCbCr image), + * we can skip most computations for the unused components. + */ + boolean component_needed; /* do we need the value of this component? */ + + /* These values are computed before starting a scan of the component. */ + /* The decompressor output side may not use these variables. */ + int MCU_width; /* number of blocks per MCU, horizontally */ + int MCU_height; /* number of blocks per MCU, vertically */ + int MCU_blocks; /* MCU_width * MCU_height */ + int MCU_sample_width; /* MCU width in samples, MCU_width*DCT_scaled_size */ + int last_col_width; /* # of non-dummy blocks across in last MCU */ + int last_row_height; /* # of non-dummy blocks down in last MCU */ + + /* Saved quantization table for component; NULL if none yet saved. + * See jdinput.c comments about the need for this information. + * This field is currently used only for decompression. + */ + JQUANT_TBL * quant_table; + + /* Private per-component storage for DCT or IDCT subsystem. */ + void * dct_table; +} jpeg_component_info; + + +/* The script for encoding a multiple-scan file is an array of these: */ + +typedef struct { + int comps_in_scan; /* number of components encoded in this scan */ + int component_index[MAX_COMPS_IN_SCAN]; /* their SOF/comp_info[] indexes */ + int Ss, Se; /* progressive JPEG spectral selection parms */ + int Ah, Al; /* progressive JPEG successive approx. parms */ +} jpeg_scan_info; + +/* The decompressor can save APPn and COM markers in a list of these: */ + +typedef struct jpeg_marker_struct FAR * jpeg_saved_marker_ptr; + +struct jpeg_marker_struct { + jpeg_saved_marker_ptr next; /* next in list, or NULL */ + UINT8 marker; /* marker code: JPEG_COM, or JPEG_APP0+n */ + unsigned int original_length; /* # bytes of data in the file */ + unsigned int data_length; /* # bytes of data saved at data[] */ + JOCTET FAR * data; /* the data contained in the marker */ + /* the marker length word is not counted in data_length or original_length */ +}; + +/* Known color spaces. */ + +typedef enum { + JCS_UNKNOWN, /* error/unspecified */ + JCS_GRAYSCALE, /* monochrome */ + JCS_RGB, /* red/green/blue */ + JCS_YCbCr, /* Y/Cb/Cr (also known as YUV) */ + JCS_CMYK, /* C/M/Y/K */ + JCS_YCCK /* Y/Cb/Cr/K */ +} J_COLOR_SPACE; + +/* DCT/IDCT algorithm options. */ + +typedef enum { + JDCT_ISLOW, /* slow but accurate integer algorithm */ + JDCT_IFAST, /* faster, less accurate integer method */ + JDCT_FLOAT /* floating-point: accurate, fast on fast HW */ +} J_DCT_METHOD; + +#ifndef JDCT_DEFAULT /* may be overridden in jconfig.h */ +#define JDCT_DEFAULT JDCT_ISLOW +#endif +#ifndef JDCT_FASTEST /* may be overridden in jconfig.h */ +#define JDCT_FASTEST JDCT_IFAST +#endif + +/* Dithering options for decompression. */ + +typedef enum { + JDITHER_NONE, /* no dithering */ + JDITHER_ORDERED, /* simple ordered dither */ + JDITHER_FS /* Floyd-Steinberg error diffusion dither */ +} J_DITHER_MODE; + + +/* Common fields between JPEG compression and decompression master structs. */ + +#define jpeg_common_fields \ + struct jpeg_error_mgr * err; /* Error handler module */\ + struct jpeg_memory_mgr * mem; /* Memory manager module */\ + struct jpeg_progress_mgr * progress; /* Progress monitor, or NULL if none */\ + void * client_data; /* Available for use by application */\ + boolean is_decompressor; /* So common code can tell which is which */\ + int global_state /* For checking call sequence validity */ + +/* Routines that are to be used by both halves of the library are declared + * to receive a pointer to this structure. There are no actual instances of + * jpeg_common_struct, only of jpeg_compress_struct and jpeg_decompress_struct. + */ +struct jpeg_common_struct { + jpeg_common_fields; /* Fields common to both master struct types */ + /* Additional fields follow in an actual jpeg_compress_struct or + * jpeg_decompress_struct. All three structs must agree on these + * initial fields! (This would be a lot cleaner in C++.) + */ +}; + +typedef struct jpeg_common_struct * j_common_ptr; +typedef struct jpeg_compress_struct * j_compress_ptr; +typedef struct jpeg_decompress_struct * j_decompress_ptr; + + +/* Master record for a compression instance */ + +struct jpeg_compress_struct { + jpeg_common_fields; /* Fields shared with jpeg_decompress_struct */ + + /* Destination for compressed data */ + struct jpeg_destination_mgr * dest; + + /* Description of source image --- these fields must be filled in by + * outer application before starting compression. in_color_space must + * be correct before you can even call jpeg_set_defaults(). + */ + + JDIMENSION image_width; /* input image width */ + JDIMENSION image_height; /* input image height */ + int input_components; /* # of color components in input image */ + J_COLOR_SPACE in_color_space; /* colorspace of input image */ + + double input_gamma; /* image gamma of input image */ + + /* Compression parameters --- these fields must be set before calling + * jpeg_start_compress(). We recommend calling jpeg_set_defaults() to + * initialize everything to reasonable defaults, then changing anything + * the application specifically wants to change. That way you won't get + * burnt when new parameters are added. Also note that there are several + * helper routines to simplify changing parameters. + */ + + int data_precision; /* bits of precision in image data */ + + int num_components; /* # of color components in JPEG image */ + J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */ + + jpeg_component_info * comp_info; + /* comp_info[i] describes component that appears i'th in SOF */ + + JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS]; + /* ptrs to coefficient quantization tables, or NULL if not defined */ + + JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; + JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; + /* ptrs to Huffman coding tables, or NULL if not defined */ + + UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ + UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ + UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ + + int num_scans; /* # of entries in scan_info array */ + const jpeg_scan_info * scan_info; /* script for multi-scan file, or NULL */ + /* The default value of scan_info is NULL, which causes a single-scan + * sequential JPEG file to be emitted. To create a multi-scan file, + * set num_scans and scan_info to point to an array of scan definitions. + */ + + boolean raw_data_in; /* TRUE=caller supplies downsampled data */ + boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ + boolean optimize_coding; /* TRUE=optimize entropy encoding parms */ + boolean CCIR601_sampling; /* TRUE=first samples are cosited */ + int smoothing_factor; /* 1..100, or 0 for no input smoothing */ + J_DCT_METHOD dct_method; /* DCT algorithm selector */ + + /* The restart interval can be specified in absolute MCUs by setting + * restart_interval, or in MCU rows by setting restart_in_rows + * (in which case the correct restart_interval will be figured + * for each scan). + */ + unsigned int restart_interval; /* MCUs per restart, or 0 for no restart */ + int restart_in_rows; /* if > 0, MCU rows per restart interval */ + + /* Parameters controlling emission of special markers. */ + + boolean write_JFIF_header; /* should a JFIF marker be written? */ + UINT8 JFIF_major_version; /* What to write for the JFIF version number */ + UINT8 JFIF_minor_version; + /* These three values are not used by the JPEG code, merely copied */ + /* into the JFIF APP0 marker. density_unit can be 0 for unknown, */ + /* 1 for dots/inch, or 2 for dots/cm. Note that the pixel aspect */ + /* ratio is defined by X_density/Y_density even when density_unit=0. */ + UINT8 density_unit; /* JFIF code for pixel size units */ + UINT16 X_density; /* Horizontal pixel density */ + UINT16 Y_density; /* Vertical pixel density */ + boolean write_Adobe_marker; /* should an Adobe marker be written? */ + + /* State variable: index of next scanline to be written to + * jpeg_write_scanlines(). Application may use this to control its + * processing loop, e.g., "while (next_scanline < image_height)". + */ + + JDIMENSION next_scanline; /* 0 .. image_height-1 */ + + /* Remaining fields are known throughout compressor, but generally + * should not be touched by a surrounding application. + */ + + /* + * These fields are computed during compression startup + */ + boolean progressive_mode; /* TRUE if scan script uses progressive mode */ + int max_h_samp_factor; /* largest h_samp_factor */ + int max_v_samp_factor; /* largest v_samp_factor */ + + JDIMENSION total_iMCU_rows; /* # of iMCU rows to be input to coef ctlr */ + /* The coefficient controller receives data in units of MCU rows as defined + * for fully interleaved scans (whether the JPEG file is interleaved or not). + * There are v_samp_factor * DCTSIZE sample rows of each component in an + * "iMCU" (interleaved MCU) row. + */ + + /* + * These fields are valid during any one scan. + * They describe the components and MCUs actually appearing in the scan. + */ + int comps_in_scan; /* # of JPEG components in this scan */ + jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; + /* *cur_comp_info[i] describes component that appears i'th in SOS */ + + JDIMENSION MCUs_per_row; /* # of MCUs across the image */ + JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ + + int blocks_in_MCU; /* # of DCT blocks per MCU */ + int MCU_membership[C_MAX_BLOCKS_IN_MCU]; + /* MCU_membership[i] is index in cur_comp_info of component owning */ + /* i'th block in an MCU */ + + int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */ + + /* + * Links to compression subobjects (methods and private variables of modules) + */ + struct jpeg_comp_master * master; + struct jpeg_c_main_controller * main; + struct jpeg_c_prep_controller * prep; + struct jpeg_c_coef_controller * coef; + struct jpeg_marker_writer * marker; + struct jpeg_color_converter * cconvert; + struct jpeg_downsampler * downsample; + struct jpeg_forward_dct * fdct; + struct jpeg_entropy_encoder * entropy; + jpeg_scan_info * script_space; /* workspace for jpeg_simple_progression */ + int script_space_size; +}; + + +/* Master record for a decompression instance */ + +struct jpeg_decompress_struct { + jpeg_common_fields; /* Fields shared with jpeg_compress_struct */ + + /* Source of compressed data */ + struct jpeg_source_mgr * src; + + /* Basic description of image --- filled in by jpeg_read_header(). */ + /* Application may inspect these values to decide how to process image. */ + + JDIMENSION image_width; /* nominal image width (from SOF marker) */ + JDIMENSION image_height; /* nominal image height */ + int num_components; /* # of color components in JPEG image */ + J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */ + + /* Decompression processing parameters --- these fields must be set before + * calling jpeg_start_decompress(). Note that jpeg_read_header() initializes + * them to default values. + */ + + J_COLOR_SPACE out_color_space; /* colorspace for output */ + + unsigned int scale_num, scale_denom; /* fraction by which to scale image */ + + double output_gamma; /* image gamma wanted in output */ + + boolean buffered_image; /* TRUE=multiple output passes */ + boolean raw_data_out; /* TRUE=downsampled data wanted */ + + J_DCT_METHOD dct_method; /* IDCT algorithm selector */ + boolean do_fancy_upsampling; /* TRUE=apply fancy upsampling */ + boolean do_block_smoothing; /* TRUE=apply interblock smoothing */ + + boolean quantize_colors; /* TRUE=colormapped output wanted */ + /* the following are ignored if not quantize_colors: */ + J_DITHER_MODE dither_mode; /* type of color dithering to use */ + boolean two_pass_quantize; /* TRUE=use two-pass color quantization */ + int desired_number_of_colors; /* max # colors to use in created colormap */ + /* these are significant only in buffered-image mode: */ + boolean enable_1pass_quant; /* enable future use of 1-pass quantizer */ + boolean enable_external_quant;/* enable future use of external colormap */ + boolean enable_2pass_quant; /* enable future use of 2-pass quantizer */ + + /* Description of actual output image that will be returned to application. + * These fields are computed by jpeg_start_decompress(). + * You can also use jpeg_calc_output_dimensions() to determine these values + * in advance of calling jpeg_start_decompress(). + */ + + JDIMENSION output_width; /* scaled image width */ + JDIMENSION output_height; /* scaled image height */ + int out_color_components; /* # of color components in out_color_space */ + int output_components; /* # of color components returned */ + /* output_components is 1 (a colormap index) when quantizing colors; + * otherwise it equals out_color_components. + */ + int rec_outbuf_height; /* min recommended height of scanline buffer */ + /* If the buffer passed to jpeg_read_scanlines() is less than this many rows + * high, space and time will be wasted due to unnecessary data copying. + * Usually rec_outbuf_height will be 1 or 2, at most 4. + */ + + /* When quantizing colors, the output colormap is described by these fields. + * The application can supply a colormap by setting colormap non-NULL before + * calling jpeg_start_decompress; otherwise a colormap is created during + * jpeg_start_decompress or jpeg_start_output. + * The map has out_color_components rows and actual_number_of_colors columns. + */ + int actual_number_of_colors; /* number of entries in use */ + JSAMPARRAY colormap; /* The color map as a 2-D pixel array */ + + /* State variables: these variables indicate the progress of decompression. + * The application may examine these but must not modify them. + */ + + /* Row index of next scanline to be read from jpeg_read_scanlines(). + * Application may use this to control its processing loop, e.g., + * "while (output_scanline < output_height)". + */ + JDIMENSION output_scanline; /* 0 .. output_height-1 */ + + /* Current input scan number and number of iMCU rows completed in scan. + * These indicate the progress of the decompressor input side. + */ + int input_scan_number; /* Number of SOS markers seen so far */ + JDIMENSION input_iMCU_row; /* Number of iMCU rows completed */ + + /* The "output scan number" is the notional scan being displayed by the + * output side. The decompressor will not allow output scan/row number + * to get ahead of input scan/row, but it can fall arbitrarily far behind. + */ + int output_scan_number; /* Nominal scan number being displayed */ + JDIMENSION output_iMCU_row; /* Number of iMCU rows read */ + + /* Current progression status. coef_bits[c][i] indicates the precision + * with which component c's DCT coefficient i (in zigzag order) is known. + * It is -1 when no data has yet been received, otherwise it is the point + * transform (shift) value for the most recent scan of the coefficient + * (thus, 0 at completion of the progression). + * This pointer is NULL when reading a non-progressive file. + */ + int (*coef_bits)[DCTSIZE2]; /* -1 or current Al value for each coef */ + + /* Internal JPEG parameters --- the application usually need not look at + * these fields. Note that the decompressor output side may not use + * any parameters that can change between scans. + */ + + /* Quantization and Huffman tables are carried forward across input + * datastreams when processing abbreviated JPEG datastreams. + */ + + JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS]; + /* ptrs to coefficient quantization tables, or NULL if not defined */ + + JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; + JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; + /* ptrs to Huffman coding tables, or NULL if not defined */ + + /* These parameters are never carried across datastreams, since they + * are given in SOF/SOS markers or defined to be reset by SOI. + */ + + int data_precision; /* bits of precision in image data */ + + jpeg_component_info * comp_info; + /* comp_info[i] describes component that appears i'th in SOF */ + + boolean progressive_mode; /* TRUE if SOFn specifies progressive mode */ + boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ + + UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ + UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ + UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ + + unsigned int restart_interval; /* MCUs per restart interval, or 0 for no restart */ + + /* These fields record data obtained from optional markers recognized by + * the JPEG library. + */ + boolean saw_JFIF_marker; /* TRUE iff a JFIF APP0 marker was found */ + /* Data copied from JFIF marker; only valid if saw_JFIF_marker is TRUE: */ + UINT8 JFIF_major_version; /* JFIF version number */ + UINT8 JFIF_minor_version; + UINT8 density_unit; /* JFIF code for pixel size units */ + UINT16 X_density; /* Horizontal pixel density */ + UINT16 Y_density; /* Vertical pixel density */ + boolean saw_Adobe_marker; /* TRUE iff an Adobe APP14 marker was found */ + UINT8 Adobe_transform; /* Color transform code from Adobe marker */ + + boolean CCIR601_sampling; /* TRUE=first samples are cosited */ + + /* Aside from the specific data retained from APPn markers known to the + * library, the uninterpreted contents of any or all APPn and COM markers + * can be saved in a list for examination by the application. + */ + jpeg_saved_marker_ptr marker_list; /* Head of list of saved markers */ + + /* Remaining fields are known throughout decompressor, but generally + * should not be touched by a surrounding application. + */ + + /* + * These fields are computed during decompression startup + */ + int max_h_samp_factor; /* largest h_samp_factor */ + int max_v_samp_factor; /* largest v_samp_factor */ + + int min_DCT_scaled_size; /* smallest DCT_scaled_size of any component */ + + JDIMENSION total_iMCU_rows; /* # of iMCU rows in image */ + /* The coefficient controller's input and output progress is measured in + * units of "iMCU" (interleaved MCU) rows. These are the same as MCU rows + * in fully interleaved JPEG scans, but are used whether the scan is + * interleaved or not. We define an iMCU row as v_samp_factor DCT block + * rows of each component. Therefore, the IDCT output contains + * v_samp_factor*DCT_scaled_size sample rows of a component per iMCU row. + */ + + JSAMPLE * sample_range_limit; /* table for fast range-limiting */ + + /* + * These fields are valid during any one scan. + * They describe the components and MCUs actually appearing in the scan. + * Note that the decompressor output side must not use these fields. + */ + int comps_in_scan; /* # of JPEG components in this scan */ + jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; + /* *cur_comp_info[i] describes component that appears i'th in SOS */ + + JDIMENSION MCUs_per_row; /* # of MCUs across the image */ + JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ + + int blocks_in_MCU; /* # of DCT blocks per MCU */ + int MCU_membership[D_MAX_BLOCKS_IN_MCU]; + /* MCU_membership[i] is index in cur_comp_info of component owning */ + /* i'th block in an MCU */ + + int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */ + + /* This field is shared between entropy decoder and marker parser. + * It is either zero or the code of a JPEG marker that has been + * read from the data source, but has not yet been processed. + */ + int unread_marker; + + /* + * Links to decompression subobjects (methods, private variables of modules) + */ + struct jpeg_decomp_master * master; + struct jpeg_d_main_controller * main; + struct jpeg_d_coef_controller * coef; + struct jpeg_d_post_controller * post; + struct jpeg_input_controller * inputctl; + struct jpeg_marker_reader * marker; + struct jpeg_entropy_decoder * entropy; + struct jpeg_inverse_dct * idct; + struct jpeg_upsampler * upsample; + struct jpeg_color_deconverter * cconvert; + struct jpeg_color_quantizer * cquantize; +}; + + +/* "Object" declarations for JPEG modules that may be supplied or called + * directly by the surrounding application. + * As with all objects in the JPEG library, these structs only define the + * publicly visible methods and state variables of a module. Additional + * private fields may exist after the public ones. + */ + + +/* Error handler object */ + +struct jpeg_error_mgr { + /* Error exit handler: does not return to caller */ + JMETHOD(void, error_exit, (j_common_ptr cinfo)); + /* Conditionally emit a trace or warning message */ + JMETHOD(void, emit_message, (j_common_ptr cinfo, int msg_level)); + /* Routine that actually outputs a trace or error message */ + JMETHOD(void, output_message, (j_common_ptr cinfo)); + /* Format a message string for the most recent JPEG error or message */ + JMETHOD(void, format_message, (j_common_ptr cinfo, char * buffer)); +#define JMSG_LENGTH_MAX 200 /* recommended size of format_message buffer */ + /* Reset error state variables at start of a new image */ + JMETHOD(void, reset_error_mgr, (j_common_ptr cinfo)); + + /* The message ID code and any parameters are saved here. + * A message can have one string parameter or up to 8 int parameters. + */ + int msg_code; +#define JMSG_STR_PARM_MAX 80 + union { + int i[8]; + char s[JMSG_STR_PARM_MAX]; + } msg_parm; + + /* Standard state variables for error facility */ + + int trace_level; /* max msg_level that will be displayed */ + + /* For recoverable corrupt-data errors, we emit a warning message, + * but keep going unless emit_message chooses to abort. emit_message + * should count warnings in num_warnings. The surrounding application + * can check for bad data by seeing if num_warnings is nonzero at the + * end of processing. + */ + long num_warnings; /* number of corrupt-data warnings */ + + /* These fields point to the table(s) of error message strings. + * An application can change the table pointer to switch to a different + * message list (typically, to change the language in which errors are + * reported). Some applications may wish to add additional error codes + * that will be handled by the JPEG library error mechanism; the second + * table pointer is used for this purpose. + * + * First table includes all errors generated by JPEG library itself. + * Error code 0 is reserved for a "no such error string" message. + */ + const char * const * jpeg_message_table; /* Library errors */ + int last_jpeg_message; /* Table contains strings 0..last_jpeg_message */ + /* Second table can be added by application (see cjpeg/djpeg for example). + * It contains strings numbered first_addon_message..last_addon_message. + */ + const char * const * addon_message_table; /* Non-library errors */ + int first_addon_message; /* code for first string in addon table */ + int last_addon_message; /* code for last string in addon table */ +}; + + +/* Progress monitor object */ + +struct jpeg_progress_mgr { + JMETHOD(void, progress_monitor, (j_common_ptr cinfo)); + + long pass_counter; /* work units completed in this pass */ + long pass_limit; /* total number of work units in this pass */ + int completed_passes; /* passes completed so far */ + int total_passes; /* total number of passes expected */ +}; + + +/* Data destination object for compression */ + +struct jpeg_destination_mgr { + JOCTET * next_output_byte; /* => next byte to write in buffer */ + size_t free_in_buffer; /* # of byte spaces remaining in buffer */ + + JMETHOD(void, init_destination, (j_compress_ptr cinfo)); + JMETHOD(boolean, empty_output_buffer, (j_compress_ptr cinfo)); + JMETHOD(void, term_destination, (j_compress_ptr cinfo)); +}; + + +/* Data source object for decompression */ + +struct jpeg_source_mgr { + const JOCTET * next_input_byte; /* => next byte to read from buffer */ + size_t bytes_in_buffer; /* # of bytes remaining in buffer */ + + JMETHOD(void, init_source, (j_decompress_ptr cinfo)); + JMETHOD(boolean, fill_input_buffer, (j_decompress_ptr cinfo)); + JMETHOD(void, skip_input_data, (j_decompress_ptr cinfo, long num_bytes)); + JMETHOD(boolean, resync_to_restart, (j_decompress_ptr cinfo, int desired)); + JMETHOD(void, term_source, (j_decompress_ptr cinfo)); +}; + + +/* Memory manager object. + * Allocates "small" objects (a few K total), "large" objects (tens of K), + * and "really big" objects (virtual arrays with backing store if needed). + * The memory manager does not allow individual objects to be freed; rather, + * each created object is assigned to a pool, and whole pools can be freed + * at once. This is faster and more convenient than remembering exactly what + * to free, especially where malloc()/free() are not too speedy. + * NB: alloc routines never return NULL. They exit to error_exit if not + * successful. + */ + +#define JPOOL_PERMANENT 0 /* lasts until master record is destroyed */ +#define JPOOL_IMAGE 1 /* lasts until done with image/datastream */ +#define JPOOL_NUMPOOLS 2 + +typedef struct jvirt_sarray_control * jvirt_sarray_ptr; +typedef struct jvirt_barray_control * jvirt_barray_ptr; + + +struct jpeg_memory_mgr { + /* Method pointers */ + JMETHOD(void *, alloc_small, (j_common_ptr cinfo, int pool_id, + size_t sizeofobject)); + JMETHOD(void FAR *, alloc_large, (j_common_ptr cinfo, int pool_id, + size_t sizeofobject)); + JMETHOD(JSAMPARRAY, alloc_sarray, (j_common_ptr cinfo, int pool_id, + JDIMENSION samplesperrow, + JDIMENSION numrows)); + JMETHOD(JBLOCKARRAY, alloc_barray, (j_common_ptr cinfo, int pool_id, + JDIMENSION blocksperrow, + JDIMENSION numrows)); + JMETHOD(jvirt_sarray_ptr, request_virt_sarray, (j_common_ptr cinfo, + int pool_id, + boolean pre_zero, + JDIMENSION samplesperrow, + JDIMENSION numrows, + JDIMENSION maxaccess)); + JMETHOD(jvirt_barray_ptr, request_virt_barray, (j_common_ptr cinfo, + int pool_id, + boolean pre_zero, + JDIMENSION blocksperrow, + JDIMENSION numrows, + JDIMENSION maxaccess)); + JMETHOD(void, realize_virt_arrays, (j_common_ptr cinfo)); + JMETHOD(JSAMPARRAY, access_virt_sarray, (j_common_ptr cinfo, + jvirt_sarray_ptr ptr, + JDIMENSION start_row, + JDIMENSION num_rows, + boolean writable)); + JMETHOD(JBLOCKARRAY, access_virt_barray, (j_common_ptr cinfo, + jvirt_barray_ptr ptr, + JDIMENSION start_row, + JDIMENSION num_rows, + boolean writable)); + JMETHOD(void, free_pool, (j_common_ptr cinfo, int pool_id)); + JMETHOD(void, self_destruct, (j_common_ptr cinfo)); + + /* Limit on memory allocation for this JPEG object. (Note that this is + * merely advisory, not a guaranteed maximum; it only affects the space + * used for virtual-array buffers.) May be changed by outer application + * after creating the JPEG object. + */ + long max_memory_to_use; + + /* Maximum allocation request accepted by alloc_large. */ + long max_alloc_chunk; +}; + + +/* Routine signature for application-supplied marker processing methods. + * Need not pass marker code since it is stored in cinfo->unread_marker. + */ +typedef JMETHOD(boolean, jpeg_marker_parser_method, (j_decompress_ptr cinfo)); + + +/* Declarations for routines called by application. + * The JPP macro hides prototype parameters from compilers that can't cope. + * Note JPP requires double parentheses. + */ + +#ifdef HAVE_PROTOTYPES +#define JPP(arglist) arglist +#else +#define JPP(arglist) () +#endif + + +/* Short forms of external names for systems with brain-damaged linkers. + * We shorten external names to be unique in the first six letters, which + * is good enough for all known systems. + * (If your compiler itself needs names to be unique in less than 15 + * characters, you are out of luck. Get a better compiler.) + */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_std_error jStdError +#define jpeg_CreateCompress jCreaCompress +#define jpeg_CreateDecompress jCreaDecompress +#define jpeg_destroy_compress jDestCompress +#define jpeg_destroy_decompress jDestDecompress +#define jpeg_stdio_dest jStdDest +#define jpeg_stdio_src jStdSrc +#define jpeg_set_defaults jSetDefaults +#define jpeg_set_colorspace jSetColorspace +#define jpeg_default_colorspace jDefColorspace +#define jpeg_set_quality jSetQuality +#define jpeg_set_linear_quality jSetLQuality +#define jpeg_add_quant_table jAddQuantTable +#define jpeg_quality_scaling jQualityScaling +#define jpeg_simple_progression jSimProgress +#define jpeg_suppress_tables jSuppressTables +#define jpeg_alloc_quant_table jAlcQTable +#define jpeg_alloc_huff_table jAlcHTable +#define jpeg_start_compress jStrtCompress +#define jpeg_write_scanlines jWrtScanlines +#define jpeg_finish_compress jFinCompress +#define jpeg_write_raw_data jWrtRawData +#define jpeg_write_marker jWrtMarker +#define jpeg_write_m_header jWrtMHeader +#define jpeg_write_m_byte jWrtMByte +#define jpeg_write_tables jWrtTables +#define jpeg_read_header jReadHeader +#define jpeg_start_decompress jStrtDecompress +#define jpeg_read_scanlines jReadScanlines +#define jpeg_finish_decompress jFinDecompress +#define jpeg_read_raw_data jReadRawData +#define jpeg_has_multiple_scans jHasMultScn +#define jpeg_start_output jStrtOutput +#define jpeg_finish_output jFinOutput +#define jpeg_input_complete jInComplete +#define jpeg_new_colormap jNewCMap +#define jpeg_consume_input jConsumeInput +#define jpeg_calc_output_dimensions jCalcDimensions +#define jpeg_save_markers jSaveMarkers +#define jpeg_set_marker_processor jSetMarker +#define jpeg_read_coefficients jReadCoefs +#define jpeg_write_coefficients jWrtCoefs +#define jpeg_copy_critical_parameters jCopyCrit +#define jpeg_abort_compress jAbrtCompress +#define jpeg_abort_decompress jAbrtDecompress +#define jpeg_abort jAbort +#define jpeg_destroy jDestroy +#define jpeg_resync_to_restart jResyncRestart +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* Default error-management setup */ +EXTERN(struct jpeg_error_mgr *) jpeg_std_error + JPP((struct jpeg_error_mgr * err)); + +/* Initialization of JPEG compression objects. + * jpeg_create_compress() and jpeg_create_decompress() are the exported + * names that applications should call. These expand to calls on + * jpeg_CreateCompress and jpeg_CreateDecompress with additional information + * passed for version mismatch checking. + * NB: you must set up the error-manager BEFORE calling jpeg_create_xxx. + */ +#define jpeg_create_compress(cinfo) \ + jpeg_CreateCompress((cinfo), JPEG_LIB_VERSION, \ + (size_t) sizeof(struct jpeg_compress_struct)) +#define jpeg_create_decompress(cinfo) \ + jpeg_CreateDecompress((cinfo), JPEG_LIB_VERSION, \ + (size_t) sizeof(struct jpeg_decompress_struct)) +EXTERN(void) jpeg_CreateCompress JPP((j_compress_ptr cinfo, + int version, size_t structsize)); +EXTERN(void) jpeg_CreateDecompress JPP((j_decompress_ptr cinfo, + int version, size_t structsize)); +/* Destruction of JPEG compression objects */ +EXTERN(void) jpeg_destroy_compress JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_destroy_decompress JPP((j_decompress_ptr cinfo)); + +/* Standard data source and destination managers: stdio streams. */ +/* Caller is responsible for opening the file before and closing after. */ +EXTERN(void) jpeg_stdio_dest JPP((j_compress_ptr cinfo, FILE * outfile)); +EXTERN(void) jpeg_stdio_src JPP((j_decompress_ptr cinfo, FILE * infile)); + +/* Default parameter setup for compression */ +EXTERN(void) jpeg_set_defaults JPP((j_compress_ptr cinfo)); +/* Compression parameter setup aids */ +EXTERN(void) jpeg_set_colorspace JPP((j_compress_ptr cinfo, + J_COLOR_SPACE colorspace)); +EXTERN(void) jpeg_default_colorspace JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_set_quality JPP((j_compress_ptr cinfo, int quality, + boolean force_baseline)); +EXTERN(void) jpeg_set_linear_quality JPP((j_compress_ptr cinfo, + int scale_factor, + boolean force_baseline)); +EXTERN(void) jpeg_add_quant_table JPP((j_compress_ptr cinfo, int which_tbl, + const unsigned int *basic_table, + int scale_factor, + boolean force_baseline)); +EXTERN(int) jpeg_quality_scaling JPP((int quality)); +EXTERN(void) jpeg_simple_progression JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_suppress_tables JPP((j_compress_ptr cinfo, + boolean suppress)); +EXTERN(JQUANT_TBL *) jpeg_alloc_quant_table JPP((j_common_ptr cinfo)); +EXTERN(JHUFF_TBL *) jpeg_alloc_huff_table JPP((j_common_ptr cinfo)); + +/* Main entry points for compression */ +EXTERN(void) jpeg_start_compress JPP((j_compress_ptr cinfo, + boolean write_all_tables)); +EXTERN(JDIMENSION) jpeg_write_scanlines JPP((j_compress_ptr cinfo, + JSAMPARRAY scanlines, + JDIMENSION num_lines)); +EXTERN(void) jpeg_finish_compress JPP((j_compress_ptr cinfo)); + +/* Replaces jpeg_write_scanlines when writing raw downsampled data. */ +EXTERN(JDIMENSION) jpeg_write_raw_data JPP((j_compress_ptr cinfo, + JSAMPIMAGE data, + JDIMENSION num_lines)); + +/* Write a special marker. See libjpeg.doc concerning safe usage. */ +EXTERN(void) jpeg_write_marker + JPP((j_compress_ptr cinfo, int marker, + const JOCTET * dataptr, unsigned int datalen)); +/* Same, but piecemeal. */ +EXTERN(void) jpeg_write_m_header + JPP((j_compress_ptr cinfo, int marker, unsigned int datalen)); +EXTERN(void) jpeg_write_m_byte + JPP((j_compress_ptr cinfo, int val)); + +/* Alternate compression function: just write an abbreviated table file */ +EXTERN(void) jpeg_write_tables JPP((j_compress_ptr cinfo)); + +/* Decompression startup: read start of JPEG datastream to see what's there */ +EXTERN(int) jpeg_read_header JPP((j_decompress_ptr cinfo, + boolean require_image)); +/* Return value is one of: */ +#define JPEG_SUSPENDED 0 /* Suspended due to lack of input data */ +#define JPEG_HEADER_OK 1 /* Found valid image datastream */ +#define JPEG_HEADER_TABLES_ONLY 2 /* Found valid table-specs-only datastream */ +/* If you pass require_image = TRUE (normal case), you need not check for + * a TABLES_ONLY return code; an abbreviated file will cause an error exit. + * JPEG_SUSPENDED is only possible if you use a data source module that can + * give a suspension return (the stdio source module doesn't). + */ + +/* Main entry points for decompression */ +EXTERN(boolean) jpeg_start_decompress JPP((j_decompress_ptr cinfo)); +EXTERN(JDIMENSION) jpeg_read_scanlines JPP((j_decompress_ptr cinfo, + JSAMPARRAY scanlines, + JDIMENSION max_lines)); +EXTERN(boolean) jpeg_finish_decompress JPP((j_decompress_ptr cinfo)); + +/* Replaces jpeg_read_scanlines when reading raw downsampled data. */ +EXTERN(JDIMENSION) jpeg_read_raw_data JPP((j_decompress_ptr cinfo, + JSAMPIMAGE data, + JDIMENSION max_lines)); + +/* Additional entry points for buffered-image mode. */ +EXTERN(boolean) jpeg_has_multiple_scans JPP((j_decompress_ptr cinfo)); +EXTERN(boolean) jpeg_start_output JPP((j_decompress_ptr cinfo, + int scan_number)); +EXTERN(boolean) jpeg_finish_output JPP((j_decompress_ptr cinfo)); +EXTERN(boolean) jpeg_input_complete JPP((j_decompress_ptr cinfo)); +EXTERN(void) jpeg_new_colormap JPP((j_decompress_ptr cinfo)); +EXTERN(int) jpeg_consume_input JPP((j_decompress_ptr cinfo)); +/* Return value is one of: */ +/* #define JPEG_SUSPENDED 0 Suspended due to lack of input data */ +#define JPEG_REACHED_SOS 1 /* Reached start of new scan */ +#define JPEG_REACHED_EOI 2 /* Reached end of image */ +#define JPEG_ROW_COMPLETED 3 /* Completed one iMCU row */ +#define JPEG_SCAN_COMPLETED 4 /* Completed last iMCU row of a scan */ + +/* Precalculate output dimensions for current decompression parameters. */ +EXTERN(void) jpeg_calc_output_dimensions JPP((j_decompress_ptr cinfo)); + +/* Control saving of COM and APPn markers into marker_list. */ +EXTERN(void) jpeg_save_markers + JPP((j_decompress_ptr cinfo, int marker_code, + unsigned int length_limit)); + +/* Install a special processing method for COM or APPn markers. */ +EXTERN(void) jpeg_set_marker_processor + JPP((j_decompress_ptr cinfo, int marker_code, + jpeg_marker_parser_method routine)); + +/* Read or write raw DCT coefficients --- useful for lossless transcoding. */ +EXTERN(jvirt_barray_ptr *) jpeg_read_coefficients JPP((j_decompress_ptr cinfo)); +EXTERN(void) jpeg_write_coefficients JPP((j_compress_ptr cinfo, + jvirt_barray_ptr * coef_arrays)); +EXTERN(void) jpeg_copy_critical_parameters JPP((j_decompress_ptr srcinfo, + j_compress_ptr dstinfo)); + +/* If you choose to abort compression or decompression before completing + * jpeg_finish_(de)compress, then you need to clean up to release memory, + * temporary files, etc. You can just call jpeg_destroy_(de)compress + * if you're done with the JPEG object, but if you want to clean it up and + * reuse it, call this: + */ +EXTERN(void) jpeg_abort_compress JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_abort_decompress JPP((j_decompress_ptr cinfo)); + +/* Generic versions of jpeg_abort and jpeg_destroy that work on either + * flavor of JPEG object. These may be more convenient in some places. + */ +EXTERN(void) jpeg_abort JPP((j_common_ptr cinfo)); +EXTERN(void) jpeg_destroy JPP((j_common_ptr cinfo)); + +/* Default restart-marker-resync procedure for use by data source modules */ +EXTERN(boolean) jpeg_resync_to_restart JPP((j_decompress_ptr cinfo, + int desired)); + + +/* These marker codes are exported since applications and data source modules + * are likely to want to use them. + */ + +#define JPEG_RST0 0xD0 /* RST0 marker code */ +#define JPEG_EOI 0xD9 /* EOI marker code */ +#define JPEG_APP0 0xE0 /* APP0 marker code */ +#define JPEG_COM 0xFE /* COM marker code */ + + +/* If we have a brain-damaged compiler that emits warnings (or worse, errors) + * for structure definitions that are never filled in, keep it quiet by + * supplying dummy definitions for the various substructures. + */ + +#ifdef INCOMPLETE_TYPES_BROKEN +#ifndef JPEG_INTERNALS /* will be defined in jpegint.h */ +struct jvirt_sarray_control { long dummy; }; +struct jvirt_barray_control { long dummy; }; +struct jpeg_comp_master { long dummy; }; +struct jpeg_c_main_controller { long dummy; }; +struct jpeg_c_prep_controller { long dummy; }; +struct jpeg_c_coef_controller { long dummy; }; +struct jpeg_marker_writer { long dummy; }; +struct jpeg_color_converter { long dummy; }; +struct jpeg_downsampler { long dummy; }; +struct jpeg_forward_dct { long dummy; }; +struct jpeg_entropy_encoder { long dummy; }; +struct jpeg_decomp_master { long dummy; }; +struct jpeg_d_main_controller { long dummy; }; +struct jpeg_d_coef_controller { long dummy; }; +struct jpeg_d_post_controller { long dummy; }; +struct jpeg_input_controller { long dummy; }; +struct jpeg_marker_reader { long dummy; }; +struct jpeg_entropy_decoder { long dummy; }; +struct jpeg_inverse_dct { long dummy; }; +struct jpeg_upsampler { long dummy; }; +struct jpeg_color_deconverter { long dummy; }; +struct jpeg_color_quantizer { long dummy; }; +#endif /* JPEG_INTERNALS */ +#endif /* INCOMPLETE_TYPES_BROKEN */ + + +/* + * The JPEG library modules define JPEG_INTERNALS before including this file. + * The internal structure declarations are read only when that is true. + * Applications using the library should not include jpegint.h, but may wish + * to include jerror.h. + */ + +#ifdef JPEG_INTERNALS +#include "jpegint.h" /* fetch private declarations */ +#include "jerror.h" /* fetch error codes too */ +#endif + +#endif /* JPEGLIB_H */ diff --git a/mk4/modimage/jpeg-6b/jpegtran.1 b/mk4/modimage/jpeg-6b/jpegtran.1 new file mode 100644 index 0000000..6de18e2 --- /dev/null +++ b/mk4/modimage/jpeg-6b/jpegtran.1 @@ -0,0 +1,238 @@ +.TH JPEGTRAN 1 "3 August 1997" +.SH NAME +jpegtran \- lossless transformation of JPEG files +.SH SYNOPSIS +.B jpegtran +[ +.I options +] +[ +.I filename +] +.LP +.SH DESCRIPTION +.LP +.B jpegtran +performs various useful transformations of JPEG files. +It can translate the coded representation from one variant of JPEG to another, +for example from baseline JPEG to progressive JPEG or vice versa. It can also +perform some rearrangements of the image data, for example turning an image +from landscape to portrait format by rotation. +.PP +.B jpegtran +works by rearranging the compressed data (DCT coefficients), without +ever fully decoding the image. Therefore, its transformations are lossless: +there is no image degradation at all, which would not be true if you used +.B djpeg +followed by +.B cjpeg +to accomplish the same conversion. But by the same token, +.B jpegtran +cannot perform lossy operations such as changing the image quality. +.PP +.B jpegtran +reads the named JPEG/JFIF file, or the standard input if no file is +named, and produces a JPEG/JFIF file on the standard output. +.SH OPTIONS +All switch names may be abbreviated; for example, +.B \-optimize +may be written +.B \-opt +or +.BR \-o . +Upper and lower case are equivalent. +British spellings are also accepted (e.g., +.BR \-optimise ), +though for brevity these are not mentioned below. +.PP +To specify the coded JPEG representation used in the output file, +.B jpegtran +accepts a subset of the switches recognized by +.BR cjpeg : +.TP +.B \-optimize +Perform optimization of entropy encoding parameters. +.TP +.B \-progressive +Create progressive JPEG file. +.TP +.BI \-restart " N" +Emit a JPEG restart marker every N MCU rows, or every N MCU blocks if "B" is +attached to the number. +.TP +.BI \-scans " file" +Use the scan script given in the specified text file. +.PP +See +.BR cjpeg (1) +for more details about these switches. +If you specify none of these switches, you get a plain baseline-JPEG output +file. The quality setting and so forth are determined by the input file. +.PP +The image can be losslessly transformed by giving one of these switches: +.TP +.B \-flip horizontal +Mirror image horizontally (left-right). +.TP +.B \-flip vertical +Mirror image vertically (top-bottom). +.TP +.B \-rotate 90 +Rotate image 90 degrees clockwise. +.TP +.B \-rotate 180 +Rotate image 180 degrees. +.TP +.B \-rotate 270 +Rotate image 270 degrees clockwise (or 90 ccw). +.TP +.B \-transpose +Transpose image (across UL-to-LR axis). +.TP +.B \-transverse +Transverse transpose (across UR-to-LL axis). +.PP +The transpose transformation has no restrictions regarding image dimensions. +The other transformations operate rather oddly if the image dimensions are not +a multiple of the iMCU size (usually 8 or 16 pixels), because they can only +transform complete blocks of DCT coefficient data in the desired way. +.PP +.BR jpegtran 's +default behavior when transforming an odd-size image is designed +to preserve exact reversibility and mathematical consistency of the +transformation set. As stated, transpose is able to flip the entire image +area. Horizontal mirroring leaves any partial iMCU column at the right edge +untouched, but is able to flip all rows of the image. Similarly, vertical +mirroring leaves any partial iMCU row at the bottom edge untouched, but is +able to flip all columns. The other transforms can be built up as sequences +of transpose and flip operations; for consistency, their actions on edge +pixels are defined to be the same as the end result of the corresponding +transpose-and-flip sequence. +.PP +For practical use, you may prefer to discard any untransformable edge pixels +rather than having a strange-looking strip along the right and/or bottom edges +of a transformed image. To do this, add the +.B \-trim +switch: +.TP +.B \-trim +Drop non-transformable edge blocks. +.PP +Obviously, a transformation with +.B \-trim +is not reversible, so strictly speaking +.B jpegtran +with this switch is not lossless. Also, the expected mathematical +equivalences between the transformations no longer hold. For example, +.B \-rot 270 -trim +trims only the bottom edge, but +.B \-rot 90 -trim +followed by +.B \-rot 180 -trim +trims both edges. +.PP +Another not-strictly-lossless transformation switch is: +.TP +.B \-grayscale +Force grayscale output. +.PP +This option discards the chrominance channels if the input image is YCbCr +(ie, a standard color JPEG), resulting in a grayscale JPEG file. The +luminance channel is preserved exactly, so this is a better method of reducing +to grayscale than decompression, conversion, and recompression. This switch +is particularly handy for fixing a monochrome picture that was mistakenly +encoded as a color JPEG. (In such a case, the space savings from getting rid +of the near-empty chroma channels won't be large; but the decoding time for +a grayscale JPEG is substantially less than that for a color JPEG.) +.PP +.B jpegtran +also recognizes these switches that control what to do with "extra" markers, +such as comment blocks: +.TP +.B \-copy none +Copy no extra markers from source file. This setting suppresses all +comments and other excess baggage present in the source file. +.TP +.B \-copy comments +Copy only comment markers. This setting copies comments from the source file, +but discards any other inessential data. +.TP +.B \-copy all +Copy all extra markers. This setting preserves miscellaneous markers +found in the source file, such as JFIF thumbnails and Photoshop settings. +In some files these extra markers can be sizable. +.PP +The default behavior is +.BR "\-copy comments" . +(Note: in IJG releases v6 and v6a, +.B jpegtran +always did the equivalent of +.BR "\-copy none" .) +.PP +Additional switches recognized by jpegtran are: +.TP +.BI \-maxmemory " N" +Set limit for amount of memory to use in processing large images. Value is +in thousands of bytes, or millions of bytes if "M" is attached to the +number. For example, +.B \-max 4m +selects 4000000 bytes. If more space is needed, temporary files will be used. +.TP +.BI \-outfile " name" +Send output image to the named file, not to standard output. +.TP +.B \-verbose +Enable debug printout. More +.BR \-v 's +give more output. Also, version information is printed at startup. +.TP +.B \-debug +Same as +.BR \-verbose . +.SH EXAMPLES +.LP +This example converts a baseline JPEG file to progressive form: +.IP +.B jpegtran \-progressive +.I foo.jpg +.B > +.I fooprog.jpg +.PP +This example rotates an image 90 degrees clockwise, discarding any +unrotatable edge pixels: +.IP +.B jpegtran \-rot 90 -trim +.I foo.jpg +.B > +.I foo90.jpg +.SH ENVIRONMENT +.TP +.B JPEGMEM +If this environment variable is set, its value is the default memory limit. +The value is specified as described for the +.B \-maxmemory +switch. +.B JPEGMEM +overrides the default value specified when the program was compiled, and +itself is overridden by an explicit +.BR \-maxmemory . +.SH SEE ALSO +.BR cjpeg (1), +.BR djpeg (1), +.BR rdjpgcom (1), +.BR wrjpgcom (1) +.br +Wallace, Gregory K. "The JPEG Still Picture Compression Standard", +Communications of the ACM, April 1991 (vol. 34, no. 4), pp. 30-44. +.SH AUTHOR +Independent JPEG Group +.SH BUGS +Arithmetic coding is not supported for legal reasons. +.PP +The transform options can't transform odd-size images perfectly. Use +.B \-trim +if you don't like the results without it. +.PP +The entire image is read into memory and then written out again, even in +cases where this isn't really necessary. Expect swapping on large images, +especially when using the more complex transform options. diff --git a/mk4/modimage/jpeg-6b/jpegtran.c b/mk4/modimage/jpeg-6b/jpegtran.c new file mode 100644 index 0000000..20ef111 --- /dev/null +++ b/mk4/modimage/jpeg-6b/jpegtran.c @@ -0,0 +1,504 @@ +/* + * jpegtran.c + * + * Copyright (C) 1995-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a command-line user interface for JPEG transcoding. + * It is very similar to cjpeg.c, but provides lossless transcoding between + * different JPEG file formats. It also provides some lossless and sort-of- + * lossless transformations of JPEG data. + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ +#include "transupp.h" /* Support routines for jpegtran */ +#include "jversion.h" /* for version message */ + +#ifdef USE_CCOMMAND /* command-line reader for Macintosh */ +#ifdef __MWERKS__ +#include /* Metrowerks needs this */ +#include /* ... and this */ +#endif +#ifdef THINK_C +#include /* Think declares it here */ +#endif +#endif + + +/* + * Argument-parsing code. + * The switch parser is designed to be useful with DOS-style command line + * syntax, ie, intermixed switches and file names, where only the switches + * to the left of a given file name affect processing of that file. + * The main program in this file doesn't actually use this capability... + */ + + +static const char * progname; /* program name for error messages */ +static char * outfilename; /* for -outfile switch */ +static JCOPY_OPTION copyoption; /* -copy switch */ +static jpeg_transform_info transformoption; /* image transformation options */ + + +LOCAL(void) +usage (void) +/* complain about bad command line */ +{ + fprintf(stderr, "usage: %s [switches] ", progname); +#ifdef TWO_FILE_COMMANDLINE + fprintf(stderr, "inputfile outputfile\n"); +#else + fprintf(stderr, "[inputfile]\n"); +#endif + + fprintf(stderr, "Switches (names may be abbreviated):\n"); + fprintf(stderr, " -copy none Copy no extra markers from source file\n"); + fprintf(stderr, " -copy comments Copy only comment markers (default)\n"); + fprintf(stderr, " -copy all Copy all extra markers\n"); +#ifdef ENTROPY_OPT_SUPPORTED + fprintf(stderr, " -optimize Optimize Huffman table (smaller file, but slow compression)\n"); +#endif +#ifdef C_PROGRESSIVE_SUPPORTED + fprintf(stderr, " -progressive Create progressive JPEG file\n"); +#endif +#if TRANSFORMS_SUPPORTED + fprintf(stderr, "Switches for modifying the image:\n"); + fprintf(stderr, " -grayscale Reduce to grayscale (omit color data)\n"); + fprintf(stderr, " -flip [horizontal|vertical] Mirror image (left-right or top-bottom)\n"); + fprintf(stderr, " -rotate [90|180|270] Rotate image (degrees clockwise)\n"); + fprintf(stderr, " -transpose Transpose image\n"); + fprintf(stderr, " -transverse Transverse transpose image\n"); + fprintf(stderr, " -trim Drop non-transformable edge blocks\n"); +#endif /* TRANSFORMS_SUPPORTED */ + fprintf(stderr, "Switches for advanced users:\n"); + fprintf(stderr, " -restart N Set restart interval in rows, or in blocks with B\n"); + fprintf(stderr, " -maxmemory N Maximum memory to use (in kbytes)\n"); + fprintf(stderr, " -outfile name Specify name for output file\n"); + fprintf(stderr, " -verbose or -debug Emit debug output\n"); + fprintf(stderr, "Switches for wizards:\n"); +#ifdef C_ARITH_CODING_SUPPORTED + fprintf(stderr, " -arithmetic Use arithmetic coding\n"); +#endif +#ifdef C_MULTISCAN_FILES_SUPPORTED + fprintf(stderr, " -scans file Create multi-scan JPEG per script file\n"); +#endif + exit(EXIT_FAILURE); +} + + +LOCAL(void) +select_transform (JXFORM_CODE transform) +/* Silly little routine to detect multiple transform options, + * which we can't handle. + */ +{ +#if TRANSFORMS_SUPPORTED + if (transformoption.transform == JXFORM_NONE || + transformoption.transform == transform) { + transformoption.transform = transform; + } else { + fprintf(stderr, "%s: can only do one image transformation at a time\n", + progname); + usage(); + } +#else + fprintf(stderr, "%s: sorry, image transformation was not compiled\n", + progname); + exit(EXIT_FAILURE); +#endif +} + + +LOCAL(int) +parse_switches (j_compress_ptr cinfo, int argc, char **argv, + int last_file_arg_seen, boolean for_real) +/* Parse optional switches. + * Returns argv[] index of first file-name argument (== argc if none). + * Any file names with indexes <= last_file_arg_seen are ignored; + * they have presumably been processed in a previous iteration. + * (Pass 0 for last_file_arg_seen on the first or only iteration.) + * for_real is FALSE on the first (dummy) pass; we may skip any expensive + * processing. + */ +{ + int argn; + char * arg; + boolean simple_progressive; + char * scansarg = NULL; /* saves -scans parm if any */ + + /* Set up default JPEG parameters. */ + simple_progressive = FALSE; + outfilename = NULL; + copyoption = JCOPYOPT_DEFAULT; + transformoption.transform = JXFORM_NONE; + transformoption.trim = FALSE; + transformoption.force_grayscale = FALSE; + cinfo->err->trace_level = 0; + + /* Scan command line options, adjust parameters */ + + for (argn = 1; argn < argc; argn++) { + arg = argv[argn]; + if (*arg != '-') { + /* Not a switch, must be a file name argument */ + if (argn <= last_file_arg_seen) { + outfilename = NULL; /* -outfile applies to just one input file */ + continue; /* ignore this name if previously processed */ + } + break; /* else done parsing switches */ + } + arg++; /* advance past switch marker character */ + + if (keymatch(arg, "arithmetic", 1)) { + /* Use arithmetic coding. */ +#ifdef C_ARITH_CODING_SUPPORTED + cinfo->arith_code = TRUE; +#else + fprintf(stderr, "%s: sorry, arithmetic coding not supported\n", + progname); + exit(EXIT_FAILURE); +#endif + + } else if (keymatch(arg, "copy", 1)) { + /* Select which extra markers to copy. */ + if (++argn >= argc) /* advance to next argument */ + usage(); + if (keymatch(argv[argn], "none", 1)) { + copyoption = JCOPYOPT_NONE; + } else if (keymatch(argv[argn], "comments", 1)) { + copyoption = JCOPYOPT_COMMENTS; + } else if (keymatch(argv[argn], "all", 1)) { + copyoption = JCOPYOPT_ALL; + } else + usage(); + + } else if (keymatch(arg, "debug", 1) || keymatch(arg, "verbose", 1)) { + /* Enable debug printouts. */ + /* On first -d, print version identification */ + static boolean printed_version = FALSE; + + if (! printed_version) { + fprintf(stderr, "Independent JPEG Group's JPEGTRAN, version %s\n%s\n", + JVERSION, JCOPYRIGHT); + printed_version = TRUE; + } + cinfo->err->trace_level++; + + } else if (keymatch(arg, "flip", 1)) { + /* Mirror left-right or top-bottom. */ + if (++argn >= argc) /* advance to next argument */ + usage(); + if (keymatch(argv[argn], "horizontal", 1)) + select_transform(JXFORM_FLIP_H); + else if (keymatch(argv[argn], "vertical", 1)) + select_transform(JXFORM_FLIP_V); + else + usage(); + + } else if (keymatch(arg, "grayscale", 1) || keymatch(arg, "greyscale",1)) { + /* Force to grayscale. */ +#if TRANSFORMS_SUPPORTED + transformoption.force_grayscale = TRUE; +#else + select_transform(JXFORM_NONE); /* force an error */ +#endif + + } else if (keymatch(arg, "maxmemory", 3)) { + /* Maximum memory in Kb (or Mb with 'm'). */ + long lval; + char ch = 'x'; + + if (++argn >= argc) /* advance to next argument */ + usage(); + if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1) + usage(); + if (ch == 'm' || ch == 'M') + lval *= 1000L; + cinfo->mem->max_memory_to_use = lval * 1000L; + + } else if (keymatch(arg, "optimize", 1) || keymatch(arg, "optimise", 1)) { + /* Enable entropy parm optimization. */ +#ifdef ENTROPY_OPT_SUPPORTED + cinfo->optimize_coding = TRUE; +#else + fprintf(stderr, "%s: sorry, entropy optimization was not compiled\n", + progname); + exit(EXIT_FAILURE); +#endif + + } else if (keymatch(arg, "outfile", 4)) { + /* Set output file name. */ + if (++argn >= argc) /* advance to next argument */ + usage(); + outfilename = argv[argn]; /* save it away for later use */ + + } else if (keymatch(arg, "progressive", 1)) { + /* Select simple progressive mode. */ +#ifdef C_PROGRESSIVE_SUPPORTED + simple_progressive = TRUE; + /* We must postpone execution until num_components is known. */ +#else + fprintf(stderr, "%s: sorry, progressive output was not compiled\n", + progname); + exit(EXIT_FAILURE); +#endif + + } else if (keymatch(arg, "restart", 1)) { + /* Restart interval in MCU rows (or in MCUs with 'b'). */ + long lval; + char ch = 'x'; + + if (++argn >= argc) /* advance to next argument */ + usage(); + if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1) + usage(); + if (lval < 0 || lval > 65535L) + usage(); + if (ch == 'b' || ch == 'B') { + cinfo->restart_interval = (unsigned int) lval; + cinfo->restart_in_rows = 0; /* else prior '-restart n' overrides me */ + } else { + cinfo->restart_in_rows = (int) lval; + /* restart_interval will be computed during startup */ + } + + } else if (keymatch(arg, "rotate", 2)) { + /* Rotate 90, 180, or 270 degrees (measured clockwise). */ + if (++argn >= argc) /* advance to next argument */ + usage(); + if (keymatch(argv[argn], "90", 2)) + select_transform(JXFORM_ROT_90); + else if (keymatch(argv[argn], "180", 3)) + select_transform(JXFORM_ROT_180); + else if (keymatch(argv[argn], "270", 3)) + select_transform(JXFORM_ROT_270); + else + usage(); + + } else if (keymatch(arg, "scans", 1)) { + /* Set scan script. */ +#ifdef C_MULTISCAN_FILES_SUPPORTED + if (++argn >= argc) /* advance to next argument */ + usage(); + scansarg = argv[argn]; + /* We must postpone reading the file in case -progressive appears. */ +#else + fprintf(stderr, "%s: sorry, multi-scan output was not compiled\n", + progname); + exit(EXIT_FAILURE); +#endif + + } else if (keymatch(arg, "transpose", 1)) { + /* Transpose (across UL-to-LR axis). */ + select_transform(JXFORM_TRANSPOSE); + + } else if (keymatch(arg, "transverse", 6)) { + /* Transverse transpose (across UR-to-LL axis). */ + select_transform(JXFORM_TRANSVERSE); + + } else if (keymatch(arg, "trim", 3)) { + /* Trim off any partial edge MCUs that the transform can't handle. */ + transformoption.trim = TRUE; + + } else { + usage(); /* bogus switch */ + } + } + + /* Post-switch-scanning cleanup */ + + if (for_real) { + +#ifdef C_PROGRESSIVE_SUPPORTED + if (simple_progressive) /* process -progressive; -scans can override */ + jpeg_simple_progression(cinfo); +#endif + +#ifdef C_MULTISCAN_FILES_SUPPORTED + if (scansarg != NULL) /* process -scans if it was present */ + if (! read_scan_script(cinfo, scansarg)) + usage(); +#endif + } + + return argn; /* return index of next arg (file name) */ +} + + +/* + * The main program. + */ + +int +main (int argc, char **argv) +{ + struct jpeg_decompress_struct srcinfo; + struct jpeg_compress_struct dstinfo; + struct jpeg_error_mgr jsrcerr, jdsterr; +#ifdef PROGRESS_REPORT + struct cdjpeg_progress_mgr progress; +#endif + jvirt_barray_ptr * src_coef_arrays; + jvirt_barray_ptr * dst_coef_arrays; + int file_index; + FILE * input_file; + FILE * output_file; + + /* On Mac, fetch a command line. */ +#ifdef USE_CCOMMAND + argc = ccommand(&argv); +#endif + + progname = argv[0]; + if (progname == NULL || progname[0] == 0) + progname = "jpegtran"; /* in case C library doesn't provide it */ + + /* Initialize the JPEG decompression object with default error handling. */ + srcinfo.err = jpeg_std_error(&jsrcerr); + jpeg_create_decompress(&srcinfo); + /* Initialize the JPEG compression object with default error handling. */ + dstinfo.err = jpeg_std_error(&jdsterr); + jpeg_create_compress(&dstinfo); + + /* Now safe to enable signal catcher. + * Note: we assume only the decompression object will have virtual arrays. + */ +#ifdef NEED_SIGNAL_CATCHER + enable_signal_catcher((j_common_ptr) &srcinfo); +#endif + + /* Scan command line to find file names. + * It is convenient to use just one switch-parsing routine, but the switch + * values read here are mostly ignored; we will rescan the switches after + * opening the input file. Also note that most of the switches affect the + * destination JPEG object, so we parse into that and then copy over what + * needs to affects the source too. + */ + + file_index = parse_switches(&dstinfo, argc, argv, 0, FALSE); + jsrcerr.trace_level = jdsterr.trace_level; + srcinfo.mem->max_memory_to_use = dstinfo.mem->max_memory_to_use; + +#ifdef TWO_FILE_COMMANDLINE + /* Must have either -outfile switch or explicit output file name */ + if (outfilename == NULL) { + if (file_index != argc-2) { + fprintf(stderr, "%s: must name one input and one output file\n", + progname); + usage(); + } + outfilename = argv[file_index+1]; + } else { + if (file_index != argc-1) { + fprintf(stderr, "%s: must name one input and one output file\n", + progname); + usage(); + } + } +#else + /* Unix style: expect zero or one file name */ + if (file_index < argc-1) { + fprintf(stderr, "%s: only one input file\n", progname); + usage(); + } +#endif /* TWO_FILE_COMMANDLINE */ + + /* Open the input file. */ + if (file_index < argc) { + if ((input_file = fopen(argv[file_index], READ_BINARY)) == NULL) { + fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index]); + exit(EXIT_FAILURE); + } + } else { + /* default input file is stdin */ + input_file = read_stdin(); + } + + /* Open the output file. */ + if (outfilename != NULL) { + if ((output_file = fopen(outfilename, WRITE_BINARY)) == NULL) { + fprintf(stderr, "%s: can't open %s\n", progname, outfilename); + exit(EXIT_FAILURE); + } + } else { + /* default output file is stdout */ + output_file = write_stdout(); + } + +#ifdef PROGRESS_REPORT + start_progress_monitor((j_common_ptr) &dstinfo, &progress); +#endif + + /* Specify data source for decompression */ + jpeg_stdio_src(&srcinfo, input_file); + + /* Enable saving of extra markers that we want to copy */ + jcopy_markers_setup(&srcinfo, copyoption); + + /* Read file header */ + (void) jpeg_read_header(&srcinfo, TRUE); + + /* Any space needed by a transform option must be requested before + * jpeg_read_coefficients so that memory allocation will be done right. + */ +#if TRANSFORMS_SUPPORTED + jtransform_request_workspace(&srcinfo, &transformoption); +#endif + + /* Read source file as DCT coefficients */ + src_coef_arrays = jpeg_read_coefficients(&srcinfo); + + /* Initialize destination compression parameters from source values */ + jpeg_copy_critical_parameters(&srcinfo, &dstinfo); + + /* Adjust destination parameters if required by transform options; + * also find out which set of coefficient arrays will hold the output. + */ +#if TRANSFORMS_SUPPORTED + dst_coef_arrays = jtransform_adjust_parameters(&srcinfo, &dstinfo, + src_coef_arrays, + &transformoption); +#else + dst_coef_arrays = src_coef_arrays; +#endif + + /* Adjust default compression parameters by re-parsing the options */ + file_index = parse_switches(&dstinfo, argc, argv, 0, TRUE); + + /* Specify data destination for compression */ + jpeg_stdio_dest(&dstinfo, output_file); + + /* Start compressor (note no image data is actually written here) */ + jpeg_write_coefficients(&dstinfo, dst_coef_arrays); + + /* Copy to the output file any extra markers that we want to preserve */ + jcopy_markers_execute(&srcinfo, &dstinfo, copyoption); + + /* Execute image transformation, if any */ +#if TRANSFORMS_SUPPORTED + jtransform_execute_transformation(&srcinfo, &dstinfo, + src_coef_arrays, + &transformoption); +#endif + + /* Finish compression and release memory */ + jpeg_finish_compress(&dstinfo); + jpeg_destroy_compress(&dstinfo); + (void) jpeg_finish_decompress(&srcinfo); + jpeg_destroy_decompress(&srcinfo); + + /* Close files, if we opened them */ + if (input_file != stdin) + fclose(input_file); + if (output_file != stdout) + fclose(output_file); + +#ifdef PROGRESS_REPORT + end_progress_monitor((j_common_ptr) &dstinfo); +#endif + + /* All done. */ + exit(jsrcerr.num_warnings + jdsterr.num_warnings ?EXIT_WARNING:EXIT_SUCCESS); + return 0; /* suppress no-return-value warnings */ +} diff --git a/mk4/modimage/jpeg-6b/jquant1.c b/mk4/modimage/jpeg-6b/jquant1.c new file mode 100644 index 0000000..b2f96aa --- /dev/null +++ b/mk4/modimage/jpeg-6b/jquant1.c @@ -0,0 +1,856 @@ +/* + * jquant1.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains 1-pass color quantization (color mapping) routines. + * These routines provide mapping to a fixed color map using equally spaced + * color values. Optional Floyd-Steinberg or ordered dithering is available. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + +#ifdef QUANT_1PASS_SUPPORTED + + +/* + * The main purpose of 1-pass quantization is to provide a fast, if not very + * high quality, colormapped output capability. A 2-pass quantizer usually + * gives better visual quality; however, for quantized grayscale output this + * quantizer is perfectly adequate. Dithering is highly recommended with this + * quantizer, though you can turn it off if you really want to. + * + * In 1-pass quantization the colormap must be chosen in advance of seeing the + * image. We use a map consisting of all combinations of Ncolors[i] color + * values for the i'th component. The Ncolors[] values are chosen so that + * their product, the total number of colors, is no more than that requested. + * (In most cases, the product will be somewhat less.) + * + * Since the colormap is orthogonal, the representative value for each color + * component can be determined without considering the other components; + * then these indexes can be combined into a colormap index by a standard + * N-dimensional-array-subscript calculation. Most of the arithmetic involved + * can be precalculated and stored in the lookup table colorindex[]. + * colorindex[i][j] maps pixel value j in component i to the nearest + * representative value (grid plane) for that component; this index is + * multiplied by the array stride for component i, so that the + * index of the colormap entry closest to a given pixel value is just + * sum( colorindex[component-number][pixel-component-value] ) + * Aside from being fast, this scheme allows for variable spacing between + * representative values with no additional lookup cost. + * + * If gamma correction has been applied in color conversion, it might be wise + * to adjust the color grid spacing so that the representative colors are + * equidistant in linear space. At this writing, gamma correction is not + * implemented by jdcolor, so nothing is done here. + */ + + +/* Declarations for ordered dithering. + * + * We use a standard 16x16 ordered dither array. The basic concept of ordered + * dithering is described in many references, for instance Dale Schumacher's + * chapter II.2 of Graphics Gems II (James Arvo, ed. Academic Press, 1991). + * In place of Schumacher's comparisons against a "threshold" value, we add a + * "dither" value to the input pixel and then round the result to the nearest + * output value. The dither value is equivalent to (0.5 - threshold) times + * the distance between output values. For ordered dithering, we assume that + * the output colors are equally spaced; if not, results will probably be + * worse, since the dither may be too much or too little at a given point. + * + * The normal calculation would be to form pixel value + dither, range-limit + * this to 0..MAXJSAMPLE, and then index into the colorindex table as usual. + * We can skip the separate range-limiting step by extending the colorindex + * table in both directions. + */ + +#define ODITHER_SIZE 16 /* dimension of dither matrix */ +/* NB: if ODITHER_SIZE is not a power of 2, ODITHER_MASK uses will break */ +#define ODITHER_CELLS (ODITHER_SIZE*ODITHER_SIZE) /* # cells in matrix */ +#define ODITHER_MASK (ODITHER_SIZE-1) /* mask for wrapping around counters */ + +typedef int ODITHER_MATRIX[ODITHER_SIZE][ODITHER_SIZE]; +typedef int (*ODITHER_MATRIX_PTR)[ODITHER_SIZE]; + +static const UINT8 base_dither_matrix[ODITHER_SIZE][ODITHER_SIZE] = { + /* Bayer's order-4 dither array. Generated by the code given in + * Stephen Hawley's article "Ordered Dithering" in Graphics Gems I. + * The values in this array must range from 0 to ODITHER_CELLS-1. + */ + { 0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255 }, + { 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 }, + { 32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223 }, + { 160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95 }, + { 8,200, 56,248, 4,196, 52,244, 11,203, 59,251, 7,199, 55,247 }, + { 136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119 }, + { 40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215 }, + { 168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87 }, + { 2,194, 50,242, 14,206, 62,254, 1,193, 49,241, 13,205, 61,253 }, + { 130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125 }, + { 34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221 }, + { 162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93 }, + { 10,202, 58,250, 6,198, 54,246, 9,201, 57,249, 5,197, 53,245 }, + { 138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117 }, + { 42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213 }, + { 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85 } +}; + + +/* Declarations for Floyd-Steinberg dithering. + * + * Errors are accumulated into the array fserrors[], at a resolution of + * 1/16th of a pixel count. The error at a given pixel is propagated + * to its not-yet-processed neighbors using the standard F-S fractions, + * ... (here) 7/16 + * 3/16 5/16 1/16 + * We work left-to-right on even rows, right-to-left on odd rows. + * + * We can get away with a single array (holding one row's worth of errors) + * by using it to store the current row's errors at pixel columns not yet + * processed, but the next row's errors at columns already processed. We + * need only a few extra variables to hold the errors immediately around the + * current column. (If we are lucky, those variables are in registers, but + * even if not, they're probably cheaper to access than array elements are.) + * + * The fserrors[] array is indexed [component#][position]. + * We provide (#columns + 2) entries per component; the extra entry at each + * end saves us from special-casing the first and last pixels. + * + * Note: on a wide image, we might not have enough room in a PC's near data + * segment to hold the error array; so it is allocated with alloc_large. + */ + +#if BITS_IN_JSAMPLE == 8 +typedef INT16 FSERROR; /* 16 bits should be enough */ +typedef int LOCFSERROR; /* use 'int' for calculation temps */ +#else +typedef INT32 FSERROR; /* may need more than 16 bits */ +typedef INT32 LOCFSERROR; /* be sure calculation temps are big enough */ +#endif + +typedef FSERROR FAR *FSERRPTR; /* pointer to error array (in FAR storage!) */ + + +/* Private subobject */ + +#define MAX_Q_COMPS 4 /* max components I can handle */ + +typedef struct { + struct jpeg_color_quantizer pub; /* public fields */ + + /* Initially allocated colormap is saved here */ + JSAMPARRAY sv_colormap; /* The color map as a 2-D pixel array */ + int sv_actual; /* number of entries in use */ + + JSAMPARRAY colorindex; /* Precomputed mapping for speed */ + /* colorindex[i][j] = index of color closest to pixel value j in component i, + * premultiplied as described above. Since colormap indexes must fit into + * JSAMPLEs, the entries of this array will too. + */ + boolean is_padded; /* is the colorindex padded for odither? */ + + int Ncolors[MAX_Q_COMPS]; /* # of values alloced to each component */ + + /* Variables for ordered dithering */ + int row_index; /* cur row's vertical index in dither matrix */ + ODITHER_MATRIX_PTR odither[MAX_Q_COMPS]; /* one dither array per component */ + + /* Variables for Floyd-Steinberg dithering */ + FSERRPTR fserrors[MAX_Q_COMPS]; /* accumulated errors */ + boolean on_odd_row; /* flag to remember which row we are on */ +} my_cquantizer; + +typedef my_cquantizer * my_cquantize_ptr; + + +/* + * Policy-making subroutines for create_colormap and create_colorindex. + * These routines determine the colormap to be used. The rest of the module + * only assumes that the colormap is orthogonal. + * + * * select_ncolors decides how to divvy up the available colors + * among the components. + * * output_value defines the set of representative values for a component. + * * largest_input_value defines the mapping from input values to + * representative values for a component. + * Note that the latter two routines may impose different policies for + * different components, though this is not currently done. + */ + + +LOCAL(int) +select_ncolors (j_decompress_ptr cinfo, int Ncolors[]) +/* Determine allocation of desired colors to components, */ +/* and fill in Ncolors[] array to indicate choice. */ +/* Return value is total number of colors (product of Ncolors[] values). */ +{ + int nc = cinfo->out_color_components; /* number of color components */ + int max_colors = cinfo->desired_number_of_colors; + int total_colors, iroot, i, j; + boolean changed; + long temp; + static const int RGB_order[3] = { RGB_GREEN, RGB_RED, RGB_BLUE }; + + /* We can allocate at least the nc'th root of max_colors per component. */ + /* Compute floor(nc'th root of max_colors). */ + iroot = 1; + do { + iroot++; + temp = iroot; /* set temp = iroot ** nc */ + for (i = 1; i < nc; i++) + temp *= iroot; + } while (temp <= (long) max_colors); /* repeat till iroot exceeds root */ + iroot--; /* now iroot = floor(root) */ + + /* Must have at least 2 color values per component */ + if (iroot < 2) + ERREXIT1(cinfo, JERR_QUANT_FEW_COLORS, (int) temp); + + /* Initialize to iroot color values for each component */ + total_colors = 1; + for (i = 0; i < nc; i++) { + Ncolors[i] = iroot; + total_colors *= iroot; + } + /* We may be able to increment the count for one or more components without + * exceeding max_colors, though we know not all can be incremented. + * Sometimes, the first component can be incremented more than once! + * (Example: for 16 colors, we start at 2*2*2, go to 3*2*2, then 4*2*2.) + * In RGB colorspace, try to increment G first, then R, then B. + */ + do { + changed = FALSE; + for (i = 0; i < nc; i++) { + j = (cinfo->out_color_space == JCS_RGB ? RGB_order[i] : i); + /* calculate new total_colors if Ncolors[j] is incremented */ + temp = total_colors / Ncolors[j]; + temp *= Ncolors[j]+1; /* done in long arith to avoid oflo */ + if (temp > (long) max_colors) + break; /* won't fit, done with this pass */ + Ncolors[j]++; /* OK, apply the increment */ + total_colors = (int) temp; + changed = TRUE; + } + } while (changed); + + return total_colors; +} + + +LOCAL(int) +output_value (j_decompress_ptr cinfo, int ci, int j, int maxj) +/* Return j'th output value, where j will range from 0 to maxj */ +/* The output values must fall in 0..MAXJSAMPLE in increasing order */ +{ + /* We always provide values 0 and MAXJSAMPLE for each component; + * any additional values are equally spaced between these limits. + * (Forcing the upper and lower values to the limits ensures that + * dithering can't produce a color outside the selected gamut.) + */ + return (int) (((INT32) j * MAXJSAMPLE + maxj/2) / maxj); +} + + +LOCAL(int) +largest_input_value (j_decompress_ptr cinfo, int ci, int j, int maxj) +/* Return largest input value that should map to j'th output value */ +/* Must have largest(j=0) >= 0, and largest(j=maxj) >= MAXJSAMPLE */ +{ + /* Breakpoints are halfway between values returned by output_value */ + return (int) (((INT32) (2*j + 1) * MAXJSAMPLE + maxj) / (2*maxj)); +} + + +/* + * Create the colormap. + */ + +LOCAL(void) +create_colormap (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + JSAMPARRAY colormap; /* Created colormap */ + int total_colors; /* Number of distinct output colors */ + int i,j,k, nci, blksize, blkdist, ptr, val; + + /* Select number of colors for each component */ + total_colors = select_ncolors(cinfo, cquantize->Ncolors); + + /* Report selected color counts */ + if (cinfo->out_color_components == 3) + TRACEMS4(cinfo, 1, JTRC_QUANT_3_NCOLORS, + total_colors, cquantize->Ncolors[0], + cquantize->Ncolors[1], cquantize->Ncolors[2]); + else + TRACEMS1(cinfo, 1, JTRC_QUANT_NCOLORS, total_colors); + + /* Allocate and fill in the colormap. */ + /* The colors are ordered in the map in standard row-major order, */ + /* i.e. rightmost (highest-indexed) color changes most rapidly. */ + + colormap = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) total_colors, (JDIMENSION) cinfo->out_color_components); + + /* blksize is number of adjacent repeated entries for a component */ + /* blkdist is distance between groups of identical entries for a component */ + blkdist = total_colors; + + for (i = 0; i < cinfo->out_color_components; i++) { + /* fill in colormap entries for i'th color component */ + nci = cquantize->Ncolors[i]; /* # of distinct values for this color */ + blksize = blkdist / nci; + for (j = 0; j < nci; j++) { + /* Compute j'th output value (out of nci) for component */ + val = output_value(cinfo, i, j, nci-1); + /* Fill in all colormap entries that have this value of this component */ + for (ptr = j * blksize; ptr < total_colors; ptr += blkdist) { + /* fill in blksize entries beginning at ptr */ + for (k = 0; k < blksize; k++) + colormap[i][ptr+k] = (JSAMPLE) val; + } + } + blkdist = blksize; /* blksize of this color is blkdist of next */ + } + + /* Save the colormap in private storage, + * where it will survive color quantization mode changes. + */ + cquantize->sv_colormap = colormap; + cquantize->sv_actual = total_colors; +} + + +/* + * Create the color index table. + */ + +LOCAL(void) +create_colorindex (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + JSAMPROW indexptr; + int i,j,k, nci, blksize, val, pad; + + /* For ordered dither, we pad the color index tables by MAXJSAMPLE in + * each direction (input index values can be -MAXJSAMPLE .. 2*MAXJSAMPLE). + * This is not necessary in the other dithering modes. However, we + * flag whether it was done in case user changes dithering mode. + */ + if (cinfo->dither_mode == JDITHER_ORDERED) { + pad = MAXJSAMPLE*2; + cquantize->is_padded = TRUE; + } else { + pad = 0; + cquantize->is_padded = FALSE; + } + + cquantize->colorindex = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) (MAXJSAMPLE+1 + pad), + (JDIMENSION) cinfo->out_color_components); + + /* blksize is number of adjacent repeated entries for a component */ + blksize = cquantize->sv_actual; + + for (i = 0; i < cinfo->out_color_components; i++) { + /* fill in colorindex entries for i'th color component */ + nci = cquantize->Ncolors[i]; /* # of distinct values for this color */ + blksize = blksize / nci; + + /* adjust colorindex pointers to provide padding at negative indexes. */ + if (pad) + cquantize->colorindex[i] += MAXJSAMPLE; + + /* in loop, val = index of current output value, */ + /* and k = largest j that maps to current val */ + indexptr = cquantize->colorindex[i]; + val = 0; + k = largest_input_value(cinfo, i, 0, nci-1); + for (j = 0; j <= MAXJSAMPLE; j++) { + while (j > k) /* advance val if past boundary */ + k = largest_input_value(cinfo, i, ++val, nci-1); + /* premultiply so that no multiplication needed in main processing */ + indexptr[j] = (JSAMPLE) (val * blksize); + } + /* Pad at both ends if necessary */ + if (pad) + for (j = 1; j <= MAXJSAMPLE; j++) { + indexptr[-j] = indexptr[0]; + indexptr[MAXJSAMPLE+j] = indexptr[MAXJSAMPLE]; + } + } +} + + +/* + * Create an ordered-dither array for a component having ncolors + * distinct output values. + */ + +LOCAL(ODITHER_MATRIX_PTR) +make_odither_array (j_decompress_ptr cinfo, int ncolors) +{ + ODITHER_MATRIX_PTR odither; + int j,k; + INT32 num,den; + + odither = (ODITHER_MATRIX_PTR) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(ODITHER_MATRIX)); + /* The inter-value distance for this color is MAXJSAMPLE/(ncolors-1). + * Hence the dither value for the matrix cell with fill order f + * (f=0..N-1) should be (N-1-2*f)/(2*N) * MAXJSAMPLE/(ncolors-1). + * On 16-bit-int machine, be careful to avoid overflow. + */ + den = 2 * ODITHER_CELLS * ((INT32) (ncolors - 1)); + for (j = 0; j < ODITHER_SIZE; j++) { + for (k = 0; k < ODITHER_SIZE; k++) { + num = ((INT32) (ODITHER_CELLS-1 - 2*((int)base_dither_matrix[j][k]))) + * MAXJSAMPLE; + /* Ensure round towards zero despite C's lack of consistency + * about rounding negative values in integer division... + */ + odither[j][k] = (int) (num<0 ? -((-num)/den) : num/den); + } + } + return odither; +} + + +/* + * Create the ordered-dither tables. + * Components having the same number of representative colors may + * share a dither table. + */ + +LOCAL(void) +create_odither_tables (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + ODITHER_MATRIX_PTR odither; + int i, j, nci; + + for (i = 0; i < cinfo->out_color_components; i++) { + nci = cquantize->Ncolors[i]; /* # of distinct values for this color */ + odither = NULL; /* search for matching prior component */ + for (j = 0; j < i; j++) { + if (nci == cquantize->Ncolors[j]) { + odither = cquantize->odither[j]; + break; + } + } + if (odither == NULL) /* need a new table? */ + odither = make_odither_array(cinfo, nci); + cquantize->odither[i] = odither; + } +} + + +/* + * Map some rows of pixels to the output colormapped representation. + */ + +METHODDEF(void) +color_quantize (j_decompress_ptr cinfo, JSAMPARRAY input_buf, + JSAMPARRAY output_buf, int num_rows) +/* General case, no dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + JSAMPARRAY colorindex = cquantize->colorindex; + register int pixcode, ci; + register JSAMPROW ptrin, ptrout; + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + register int nc = cinfo->out_color_components; + + for (row = 0; row < num_rows; row++) { + ptrin = input_buf[row]; + ptrout = output_buf[row]; + for (col = width; col > 0; col--) { + pixcode = 0; + for (ci = 0; ci < nc; ci++) { + pixcode += GETJSAMPLE(colorindex[ci][GETJSAMPLE(*ptrin++)]); + } + *ptrout++ = (JSAMPLE) pixcode; + } + } +} + + +METHODDEF(void) +color_quantize3 (j_decompress_ptr cinfo, JSAMPARRAY input_buf, + JSAMPARRAY output_buf, int num_rows) +/* Fast path for out_color_components==3, no dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + register int pixcode; + register JSAMPROW ptrin, ptrout; + JSAMPROW colorindex0 = cquantize->colorindex[0]; + JSAMPROW colorindex1 = cquantize->colorindex[1]; + JSAMPROW colorindex2 = cquantize->colorindex[2]; + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + + for (row = 0; row < num_rows; row++) { + ptrin = input_buf[row]; + ptrout = output_buf[row]; + for (col = width; col > 0; col--) { + pixcode = GETJSAMPLE(colorindex0[GETJSAMPLE(*ptrin++)]); + pixcode += GETJSAMPLE(colorindex1[GETJSAMPLE(*ptrin++)]); + pixcode += GETJSAMPLE(colorindex2[GETJSAMPLE(*ptrin++)]); + *ptrout++ = (JSAMPLE) pixcode; + } + } +} + + +METHODDEF(void) +quantize_ord_dither (j_decompress_ptr cinfo, JSAMPARRAY input_buf, + JSAMPARRAY output_buf, int num_rows) +/* General case, with ordered dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + register JSAMPROW input_ptr; + register JSAMPROW output_ptr; + JSAMPROW colorindex_ci; + int * dither; /* points to active row of dither matrix */ + int row_index, col_index; /* current indexes into dither matrix */ + int nc = cinfo->out_color_components; + int ci; + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + + for (row = 0; row < num_rows; row++) { + /* Initialize output values to 0 so can process components separately */ + jzero_far((void FAR *) output_buf[row], + (size_t) (width * SIZEOF(JSAMPLE))); + row_index = cquantize->row_index; + for (ci = 0; ci < nc; ci++) { + input_ptr = input_buf[row] + ci; + output_ptr = output_buf[row]; + colorindex_ci = cquantize->colorindex[ci]; + dither = cquantize->odither[ci][row_index]; + col_index = 0; + + for (col = width; col > 0; col--) { + /* Form pixel value + dither, range-limit to 0..MAXJSAMPLE, + * select output value, accumulate into output code for this pixel. + * Range-limiting need not be done explicitly, as we have extended + * the colorindex table to produce the right answers for out-of-range + * inputs. The maximum dither is +- MAXJSAMPLE; this sets the + * required amount of padding. + */ + *output_ptr += colorindex_ci[GETJSAMPLE(*input_ptr)+dither[col_index]]; + input_ptr += nc; + output_ptr++; + col_index = (col_index + 1) & ODITHER_MASK; + } + } + /* Advance row index for next row */ + row_index = (row_index + 1) & ODITHER_MASK; + cquantize->row_index = row_index; + } +} + + +METHODDEF(void) +quantize3_ord_dither (j_decompress_ptr cinfo, JSAMPARRAY input_buf, + JSAMPARRAY output_buf, int num_rows) +/* Fast path for out_color_components==3, with ordered dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + register int pixcode; + register JSAMPROW input_ptr; + register JSAMPROW output_ptr; + JSAMPROW colorindex0 = cquantize->colorindex[0]; + JSAMPROW colorindex1 = cquantize->colorindex[1]; + JSAMPROW colorindex2 = cquantize->colorindex[2]; + int * dither0; /* points to active row of dither matrix */ + int * dither1; + int * dither2; + int row_index, col_index; /* current indexes into dither matrix */ + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + + for (row = 0; row < num_rows; row++) { + row_index = cquantize->row_index; + input_ptr = input_buf[row]; + output_ptr = output_buf[row]; + dither0 = cquantize->odither[0][row_index]; + dither1 = cquantize->odither[1][row_index]; + dither2 = cquantize->odither[2][row_index]; + col_index = 0; + + for (col = width; col > 0; col--) { + pixcode = GETJSAMPLE(colorindex0[GETJSAMPLE(*input_ptr++) + + dither0[col_index]]); + pixcode += GETJSAMPLE(colorindex1[GETJSAMPLE(*input_ptr++) + + dither1[col_index]]); + pixcode += GETJSAMPLE(colorindex2[GETJSAMPLE(*input_ptr++) + + dither2[col_index]]); + *output_ptr++ = (JSAMPLE) pixcode; + col_index = (col_index + 1) & ODITHER_MASK; + } + row_index = (row_index + 1) & ODITHER_MASK; + cquantize->row_index = row_index; + } +} + + +METHODDEF(void) +quantize_fs_dither (j_decompress_ptr cinfo, JSAMPARRAY input_buf, + JSAMPARRAY output_buf, int num_rows) +/* General case, with Floyd-Steinberg dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + register LOCFSERROR cur; /* current error or pixel value */ + LOCFSERROR belowerr; /* error for pixel below cur */ + LOCFSERROR bpreverr; /* error for below/prev col */ + LOCFSERROR bnexterr; /* error for below/next col */ + LOCFSERROR delta; + register FSERRPTR errorptr; /* => fserrors[] at column before current */ + register JSAMPROW input_ptr; + register JSAMPROW output_ptr; + JSAMPROW colorindex_ci; + JSAMPROW colormap_ci; + int pixcode; + int nc = cinfo->out_color_components; + int dir; /* 1 for left-to-right, -1 for right-to-left */ + int dirnc; /* dir * nc */ + int ci; + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + JSAMPLE *range_limit = cinfo->sample_range_limit; + SHIFT_TEMPS + + for (row = 0; row < num_rows; row++) { + /* Initialize output values to 0 so can process components separately */ + jzero_far((void FAR *) output_buf[row], + (size_t) (width * SIZEOF(JSAMPLE))); + for (ci = 0; ci < nc; ci++) { + input_ptr = input_buf[row] + ci; + output_ptr = output_buf[row]; + if (cquantize->on_odd_row) { + /* work right to left in this row */ + input_ptr += (width-1) * nc; /* so point to rightmost pixel */ + output_ptr += width-1; + dir = -1; + dirnc = -nc; + errorptr = cquantize->fserrors[ci] + (width+1); /* => entry after last column */ + } else { + /* work left to right in this row */ + dir = 1; + dirnc = nc; + errorptr = cquantize->fserrors[ci]; /* => entry before first column */ + } + colorindex_ci = cquantize->colorindex[ci]; + colormap_ci = cquantize->sv_colormap[ci]; + /* Preset error values: no error propagated to first pixel from left */ + cur = 0; + /* and no error propagated to row below yet */ + belowerr = bpreverr = 0; + + for (col = width; col > 0; col--) { + /* cur holds the error propagated from the previous pixel on the + * current line. Add the error propagated from the previous line + * to form the complete error correction term for this pixel, and + * round the error term (which is expressed * 16) to an integer. + * RIGHT_SHIFT rounds towards minus infinity, so adding 8 is correct + * for either sign of the error value. + * Note: errorptr points to *previous* column's array entry. + */ + cur = RIGHT_SHIFT(cur + errorptr[dir] + 8, 4); + /* Form pixel value + error, and range-limit to 0..MAXJSAMPLE. + * The maximum error is +- MAXJSAMPLE; this sets the required size + * of the range_limit array. + */ + cur += GETJSAMPLE(*input_ptr); + cur = GETJSAMPLE(range_limit[cur]); + /* Select output value, accumulate into output code for this pixel */ + pixcode = GETJSAMPLE(colorindex_ci[cur]); + *output_ptr += (JSAMPLE) pixcode; + /* Compute actual representation error at this pixel */ + /* Note: we can do this even though we don't have the final */ + /* pixel code, because the colormap is orthogonal. */ + cur -= GETJSAMPLE(colormap_ci[pixcode]); + /* Compute error fractions to be propagated to adjacent pixels. + * Add these into the running sums, and simultaneously shift the + * next-line error sums left by 1 column. + */ + bnexterr = cur; + delta = cur * 2; + cur += delta; /* form error * 3 */ + errorptr[0] = (FSERROR) (bpreverr + cur); + cur += delta; /* form error * 5 */ + bpreverr = belowerr + cur; + belowerr = bnexterr; + cur += delta; /* form error * 7 */ + /* At this point cur contains the 7/16 error value to be propagated + * to the next pixel on the current line, and all the errors for the + * next line have been shifted over. We are therefore ready to move on. + */ + input_ptr += dirnc; /* advance input ptr to next column */ + output_ptr += dir; /* advance output ptr to next column */ + errorptr += dir; /* advance errorptr to current column */ + } + /* Post-loop cleanup: we must unload the final error value into the + * final fserrors[] entry. Note we need not unload belowerr because + * it is for the dummy column before or after the actual array. + */ + errorptr[0] = (FSERROR) bpreverr; /* unload prev err into array */ + } + cquantize->on_odd_row = (cquantize->on_odd_row ? FALSE : TRUE); + } +} + + +/* + * Allocate workspace for Floyd-Steinberg errors. + */ + +LOCAL(void) +alloc_fs_workspace (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + size_t arraysize; + int i; + + arraysize = (size_t) ((cinfo->output_width + 2) * SIZEOF(FSERROR)); + for (i = 0; i < cinfo->out_color_components; i++) { + cquantize->fserrors[i] = (FSERRPTR) + (*cinfo->mem->alloc_large)((j_common_ptr) cinfo, JPOOL_IMAGE, arraysize); + } +} + + +/* + * Initialize for one-pass color quantization. + */ + +METHODDEF(void) +start_pass_1_quant (j_decompress_ptr cinfo, boolean is_pre_scan) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + size_t arraysize; + int i; + + /* Install my colormap. */ + cinfo->colormap = cquantize->sv_colormap; + cinfo->actual_number_of_colors = cquantize->sv_actual; + + /* Initialize for desired dithering mode. */ + switch (cinfo->dither_mode) { + case JDITHER_NONE: + if (cinfo->out_color_components == 3) + cquantize->pub.color_quantize = color_quantize3; + else + cquantize->pub.color_quantize = color_quantize; + break; + case JDITHER_ORDERED: + if (cinfo->out_color_components == 3) + cquantize->pub.color_quantize = quantize3_ord_dither; + else + cquantize->pub.color_quantize = quantize_ord_dither; + cquantize->row_index = 0; /* initialize state for ordered dither */ + /* If user changed to ordered dither from another mode, + * we must recreate the color index table with padding. + * This will cost extra space, but probably isn't very likely. + */ + if (! cquantize->is_padded) + create_colorindex(cinfo); + /* Create ordered-dither tables if we didn't already. */ + if (cquantize->odither[0] == NULL) + create_odither_tables(cinfo); + break; + case JDITHER_FS: + cquantize->pub.color_quantize = quantize_fs_dither; + cquantize->on_odd_row = FALSE; /* initialize state for F-S dither */ + /* Allocate Floyd-Steinberg workspace if didn't already. */ + if (cquantize->fserrors[0] == NULL) + alloc_fs_workspace(cinfo); + /* Initialize the propagated errors to zero. */ + arraysize = (size_t) ((cinfo->output_width + 2) * SIZEOF(FSERROR)); + for (i = 0; i < cinfo->out_color_components; i++) + jzero_far((void FAR *) cquantize->fserrors[i], arraysize); + break; + default: + ERREXIT(cinfo, JERR_NOT_COMPILED); + break; + } +} + + +/* + * Finish up at the end of the pass. + */ + +METHODDEF(void) +finish_pass_1_quant (j_decompress_ptr cinfo) +{ + /* no work in 1-pass case */ +} + + +/* + * Switch to a new external colormap between output passes. + * Shouldn't get to this module! + */ + +METHODDEF(void) +new_color_map_1_quant (j_decompress_ptr cinfo) +{ + ERREXIT(cinfo, JERR_MODE_CHANGE); +} + + +/* + * Module initialization routine for 1-pass color quantization. + */ + +GLOBAL(void) +jinit_1pass_quantizer (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize; + + cquantize = (my_cquantize_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_cquantizer)); + cinfo->cquantize = (struct jpeg_color_quantizer *) cquantize; + cquantize->pub.start_pass = start_pass_1_quant; + cquantize->pub.finish_pass = finish_pass_1_quant; + cquantize->pub.new_color_map = new_color_map_1_quant; + cquantize->fserrors[0] = NULL; /* Flag FS workspace not allocated */ + cquantize->odither[0] = NULL; /* Also flag odither arrays not allocated */ + + /* Make sure my internal arrays won't overflow */ + if (cinfo->out_color_components > MAX_Q_COMPS) + ERREXIT1(cinfo, JERR_QUANT_COMPONENTS, MAX_Q_COMPS); + /* Make sure colormap indexes can be represented by JSAMPLEs */ + if (cinfo->desired_number_of_colors > (MAXJSAMPLE+1)) + ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, MAXJSAMPLE+1); + + /* Create the colormap and color index table. */ + create_colormap(cinfo); + create_colorindex(cinfo); + + /* Allocate Floyd-Steinberg workspace now if requested. + * We do this now since it is FAR storage and may affect the memory + * manager's space calculations. If the user changes to FS dither + * mode in a later pass, we will allocate the space then, and will + * possibly overrun the max_memory_to_use setting. + */ + if (cinfo->dither_mode == JDITHER_FS) + alloc_fs_workspace(cinfo); +} + +#endif /* QUANT_1PASS_SUPPORTED */ diff --git a/mk4/modimage/jpeg-6b/jquant2.c b/mk4/modimage/jpeg-6b/jquant2.c new file mode 100644 index 0000000..af601e3 --- /dev/null +++ b/mk4/modimage/jpeg-6b/jquant2.c @@ -0,0 +1,1310 @@ +/* + * jquant2.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains 2-pass color quantization (color mapping) routines. + * These routines provide selection of a custom color map for an image, + * followed by mapping of the image to that color map, with optional + * Floyd-Steinberg dithering. + * It is also possible to use just the second pass to map to an arbitrary + * externally-given color map. + * + * Note: ordered dithering is not supported, since there isn't any fast + * way to compute intercolor distances; it's unclear that ordered dither's + * fundamental assumptions even hold with an irregularly spaced color map. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + +#ifdef QUANT_2PASS_SUPPORTED + + +/* + * This module implements the well-known Heckbert paradigm for color + * quantization. Most of the ideas used here can be traced back to + * Heckbert's seminal paper + * Heckbert, Paul. "Color Image Quantization for Frame Buffer Display", + * Proc. SIGGRAPH '82, Computer Graphics v.16 #3 (July 1982), pp 297-304. + * + * In the first pass over the image, we accumulate a histogram showing the + * usage count of each possible color. To keep the histogram to a reasonable + * size, we reduce the precision of the input; typical practice is to retain + * 5 or 6 bits per color, so that 8 or 4 different input values are counted + * in the same histogram cell. + * + * Next, the color-selection step begins with a box representing the whole + * color space, and repeatedly splits the "largest" remaining box until we + * have as many boxes as desired colors. Then the mean color in each + * remaining box becomes one of the possible output colors. + * + * The second pass over the image maps each input pixel to the closest output + * color (optionally after applying a Floyd-Steinberg dithering correction). + * This mapping is logically trivial, but making it go fast enough requires + * considerable care. + * + * Heckbert-style quantizers vary a good deal in their policies for choosing + * the "largest" box and deciding where to cut it. The particular policies + * used here have proved out well in experimental comparisons, but better ones + * may yet be found. + * + * In earlier versions of the IJG code, this module quantized in YCbCr color + * space, processing the raw upsampled data without a color conversion step. + * This allowed the color conversion math to be done only once per colormap + * entry, not once per pixel. However, that optimization precluded other + * useful optimizations (such as merging color conversion with upsampling) + * and it also interfered with desired capabilities such as quantizing to an + * externally-supplied colormap. We have therefore abandoned that approach. + * The present code works in the post-conversion color space, typically RGB. + * + * To improve the visual quality of the results, we actually work in scaled + * RGB space, giving G distances more weight than R, and R in turn more than + * B. To do everything in integer math, we must use integer scale factors. + * The 2/3/1 scale factors used here correspond loosely to the relative + * weights of the colors in the NTSC grayscale equation. + * If you want to use this code to quantize a non-RGB color space, you'll + * probably need to change these scale factors. + */ + +#define R_SCALE 2 /* scale R distances by this much */ +#define G_SCALE 3 /* scale G distances by this much */ +#define B_SCALE 1 /* and B by this much */ + +/* Relabel R/G/B as components 0/1/2, respecting the RGB ordering defined + * in jmorecfg.h. As the code stands, it will do the right thing for R,G,B + * and B,G,R orders. If you define some other weird order in jmorecfg.h, + * you'll get compile errors until you extend this logic. In that case + * you'll probably want to tweak the histogram sizes too. + */ + +#if RGB_RED == 0 +#define C0_SCALE R_SCALE +#endif +#if RGB_BLUE == 0 +#define C0_SCALE B_SCALE +#endif +#if RGB_GREEN == 1 +#define C1_SCALE G_SCALE +#endif +#if RGB_RED == 2 +#define C2_SCALE R_SCALE +#endif +#if RGB_BLUE == 2 +#define C2_SCALE B_SCALE +#endif + + +/* + * First we have the histogram data structure and routines for creating it. + * + * The number of bits of precision can be adjusted by changing these symbols. + * We recommend keeping 6 bits for G and 5 each for R and B. + * If you have plenty of memory and cycles, 6 bits all around gives marginally + * better results; if you are short of memory, 5 bits all around will save + * some space but degrade the results. + * To maintain a fully accurate histogram, we'd need to allocate a "long" + * (preferably unsigned long) for each cell. In practice this is overkill; + * we can get by with 16 bits per cell. Few of the cell counts will overflow, + * and clamping those that do overflow to the maximum value will give close- + * enough results. This reduces the recommended histogram size from 256Kb + * to 128Kb, which is a useful savings on PC-class machines. + * (In the second pass the histogram space is re-used for pixel mapping data; + * in that capacity, each cell must be able to store zero to the number of + * desired colors. 16 bits/cell is plenty for that too.) + * Since the JPEG code is intended to run in small memory model on 80x86 + * machines, we can't just allocate the histogram in one chunk. Instead + * of a true 3-D array, we use a row of pointers to 2-D arrays. Each + * pointer corresponds to a C0 value (typically 2^5 = 32 pointers) and + * each 2-D array has 2^6*2^5 = 2048 or 2^6*2^6 = 4096 entries. Note that + * on 80x86 machines, the pointer row is in near memory but the actual + * arrays are in far memory (same arrangement as we use for image arrays). + */ + +#define MAXNUMCOLORS (MAXJSAMPLE+1) /* maximum size of colormap */ + +/* These will do the right thing for either R,G,B or B,G,R color order, + * but you may not like the results for other color orders. + */ +#define HIST_C0_BITS 5 /* bits of precision in R/B histogram */ +#define HIST_C1_BITS 6 /* bits of precision in G histogram */ +#define HIST_C2_BITS 5 /* bits of precision in B/R histogram */ + +/* Number of elements along histogram axes. */ +#define HIST_C0_ELEMS (1<cquantize; + register JSAMPROW ptr; + register histptr histp; + register hist3d histogram = cquantize->histogram; + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + + for (row = 0; row < num_rows; row++) { + ptr = input_buf[row]; + for (col = width; col > 0; col--) { + /* get pixel value and index into the histogram */ + histp = & histogram[GETJSAMPLE(ptr[0]) >> C0_SHIFT] + [GETJSAMPLE(ptr[1]) >> C1_SHIFT] + [GETJSAMPLE(ptr[2]) >> C2_SHIFT]; + /* increment, check for overflow and undo increment if so. */ + if (++(*histp) <= 0) + (*histp)--; + ptr += 3; + } + } +} + + +/* + * Next we have the really interesting routines: selection of a colormap + * given the completed histogram. + * These routines work with a list of "boxes", each representing a rectangular + * subset of the input color space (to histogram precision). + */ + +typedef struct { + /* The bounds of the box (inclusive); expressed as histogram indexes */ + int c0min, c0max; + int c1min, c1max; + int c2min, c2max; + /* The volume (actually 2-norm) of the box */ + INT32 volume; + /* The number of nonzero histogram cells within this box */ + long colorcount; +} box; + +typedef box * boxptr; + + +LOCAL(boxptr) +find_biggest_color_pop (boxptr boxlist, int numboxes) +/* Find the splittable box with the largest color population */ +/* Returns NULL if no splittable boxes remain */ +{ + register boxptr boxp; + register int i; + register long maxc = 0; + boxptr which = NULL; + + for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++) { + if (boxp->colorcount > maxc && boxp->volume > 0) { + which = boxp; + maxc = boxp->colorcount; + } + } + return which; +} + + +LOCAL(boxptr) +find_biggest_volume (boxptr boxlist, int numboxes) +/* Find the splittable box with the largest (scaled) volume */ +/* Returns NULL if no splittable boxes remain */ +{ + register boxptr boxp; + register int i; + register INT32 maxv = 0; + boxptr which = NULL; + + for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++) { + if (boxp->volume > maxv) { + which = boxp; + maxv = boxp->volume; + } + } + return which; +} + + +LOCAL(void) +update_box (j_decompress_ptr cinfo, boxptr boxp) +/* Shrink the min/max bounds of a box to enclose only nonzero elements, */ +/* and recompute its volume and population */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + histptr histp; + int c0,c1,c2; + int c0min,c0max,c1min,c1max,c2min,c2max; + INT32 dist0,dist1,dist2; + long ccount; + + c0min = boxp->c0min; c0max = boxp->c0max; + c1min = boxp->c1min; c1max = boxp->c1max; + c2min = boxp->c2min; c2max = boxp->c2max; + + if (c0max > c0min) + for (c0 = c0min; c0 <= c0max; c0++) + for (c1 = c1min; c1 <= c1max; c1++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++) + if (*histp++ != 0) { + boxp->c0min = c0min = c0; + goto have_c0min; + } + } + have_c0min: + if (c0max > c0min) + for (c0 = c0max; c0 >= c0min; c0--) + for (c1 = c1min; c1 <= c1max; c1++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++) + if (*histp++ != 0) { + boxp->c0max = c0max = c0; + goto have_c0max; + } + } + have_c0max: + if (c1max > c1min) + for (c1 = c1min; c1 <= c1max; c1++) + for (c0 = c0min; c0 <= c0max; c0++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++) + if (*histp++ != 0) { + boxp->c1min = c1min = c1; + goto have_c1min; + } + } + have_c1min: + if (c1max > c1min) + for (c1 = c1max; c1 >= c1min; c1--) + for (c0 = c0min; c0 <= c0max; c0++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++) + if (*histp++ != 0) { + boxp->c1max = c1max = c1; + goto have_c1max; + } + } + have_c1max: + if (c2max > c2min) + for (c2 = c2min; c2 <= c2max; c2++) + for (c0 = c0min; c0 <= c0max; c0++) { + histp = & histogram[c0][c1min][c2]; + for (c1 = c1min; c1 <= c1max; c1++, histp += HIST_C2_ELEMS) + if (*histp != 0) { + boxp->c2min = c2min = c2; + goto have_c2min; + } + } + have_c2min: + if (c2max > c2min) + for (c2 = c2max; c2 >= c2min; c2--) + for (c0 = c0min; c0 <= c0max; c0++) { + histp = & histogram[c0][c1min][c2]; + for (c1 = c1min; c1 <= c1max; c1++, histp += HIST_C2_ELEMS) + if (*histp != 0) { + boxp->c2max = c2max = c2; + goto have_c2max; + } + } + have_c2max: + + /* Update box volume. + * We use 2-norm rather than real volume here; this biases the method + * against making long narrow boxes, and it has the side benefit that + * a box is splittable iff norm > 0. + * Since the differences are expressed in histogram-cell units, + * we have to shift back to JSAMPLE units to get consistent distances; + * after which, we scale according to the selected distance scale factors. + */ + dist0 = ((c0max - c0min) << C0_SHIFT) * C0_SCALE; + dist1 = ((c1max - c1min) << C1_SHIFT) * C1_SCALE; + dist2 = ((c2max - c2min) << C2_SHIFT) * C2_SCALE; + boxp->volume = dist0*dist0 + dist1*dist1 + dist2*dist2; + + /* Now scan remaining volume of box and compute population */ + ccount = 0; + for (c0 = c0min; c0 <= c0max; c0++) + for (c1 = c1min; c1 <= c1max; c1++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++, histp++) + if (*histp != 0) { + ccount++; + } + } + boxp->colorcount = ccount; +} + + +LOCAL(int) +median_cut (j_decompress_ptr cinfo, boxptr boxlist, int numboxes, + int desired_colors) +/* Repeatedly select and split the largest box until we have enough boxes */ +{ + int n,lb; + int c0,c1,c2,cmax; + register boxptr b1,b2; + + while (numboxes < desired_colors) { + /* Select box to split. + * Current algorithm: by population for first half, then by volume. + */ + if (numboxes*2 <= desired_colors) { + b1 = find_biggest_color_pop(boxlist, numboxes); + } else { + b1 = find_biggest_volume(boxlist, numboxes); + } + if (b1 == NULL) /* no splittable boxes left! */ + break; + b2 = &boxlist[numboxes]; /* where new box will go */ + /* Copy the color bounds to the new box. */ + b2->c0max = b1->c0max; b2->c1max = b1->c1max; b2->c2max = b1->c2max; + b2->c0min = b1->c0min; b2->c1min = b1->c1min; b2->c2min = b1->c2min; + /* Choose which axis to split the box on. + * Current algorithm: longest scaled axis. + * See notes in update_box about scaling distances. + */ + c0 = ((b1->c0max - b1->c0min) << C0_SHIFT) * C0_SCALE; + c1 = ((b1->c1max - b1->c1min) << C1_SHIFT) * C1_SCALE; + c2 = ((b1->c2max - b1->c2min) << C2_SHIFT) * C2_SCALE; + /* We want to break any ties in favor of green, then red, blue last. + * This code does the right thing for R,G,B or B,G,R color orders only. + */ +#if RGB_RED == 0 + cmax = c1; n = 1; + if (c0 > cmax) { cmax = c0; n = 0; } + if (c2 > cmax) { n = 2; } +#else + cmax = c1; n = 1; + if (c2 > cmax) { cmax = c2; n = 2; } + if (c0 > cmax) { n = 0; } +#endif + /* Choose split point along selected axis, and update box bounds. + * Current algorithm: split at halfway point. + * (Since the box has been shrunk to minimum volume, + * any split will produce two nonempty subboxes.) + * Note that lb value is max for lower box, so must be < old max. + */ + switch (n) { + case 0: + lb = (b1->c0max + b1->c0min) / 2; + b1->c0max = lb; + b2->c0min = lb+1; + break; + case 1: + lb = (b1->c1max + b1->c1min) / 2; + b1->c1max = lb; + b2->c1min = lb+1; + break; + case 2: + lb = (b1->c2max + b1->c2min) / 2; + b1->c2max = lb; + b2->c2min = lb+1; + break; + } + /* Update stats for boxes */ + update_box(cinfo, b1); + update_box(cinfo, b2); + numboxes++; + } + return numboxes; +} + + +LOCAL(void) +compute_color (j_decompress_ptr cinfo, boxptr boxp, int icolor) +/* Compute representative color for a box, put it in colormap[icolor] */ +{ + /* Current algorithm: mean weighted by pixels (not colors) */ + /* Note it is important to get the rounding correct! */ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + histptr histp; + int c0,c1,c2; + int c0min,c0max,c1min,c1max,c2min,c2max; + long count; + long total = 0; + long c0total = 0; + long c1total = 0; + long c2total = 0; + + c0min = boxp->c0min; c0max = boxp->c0max; + c1min = boxp->c1min; c1max = boxp->c1max; + c2min = boxp->c2min; c2max = boxp->c2max; + + for (c0 = c0min; c0 <= c0max; c0++) + for (c1 = c1min; c1 <= c1max; c1++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++) { + if ((count = *histp++) != 0) { + total += count; + c0total += ((c0 << C0_SHIFT) + ((1<>1)) * count; + c1total += ((c1 << C1_SHIFT) + ((1<>1)) * count; + c2total += ((c2 << C2_SHIFT) + ((1<>1)) * count; + } + } + } + + cinfo->colormap[0][icolor] = (JSAMPLE) ((c0total + (total>>1)) / total); + cinfo->colormap[1][icolor] = (JSAMPLE) ((c1total + (total>>1)) / total); + cinfo->colormap[2][icolor] = (JSAMPLE) ((c2total + (total>>1)) / total); +} + + +LOCAL(void) +select_colors (j_decompress_ptr cinfo, int desired_colors) +/* Master routine for color selection */ +{ + boxptr boxlist; + int numboxes; + int i; + + /* Allocate workspace for box list */ + boxlist = (boxptr) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, desired_colors * SIZEOF(box)); + /* Initialize one box containing whole space */ + numboxes = 1; + boxlist[0].c0min = 0; + boxlist[0].c0max = MAXJSAMPLE >> C0_SHIFT; + boxlist[0].c1min = 0; + boxlist[0].c1max = MAXJSAMPLE >> C1_SHIFT; + boxlist[0].c2min = 0; + boxlist[0].c2max = MAXJSAMPLE >> C2_SHIFT; + /* Shrink it to actually-used volume and set its statistics */ + update_box(cinfo, & boxlist[0]); + /* Perform median-cut to produce final box list */ + numboxes = median_cut(cinfo, boxlist, numboxes, desired_colors); + /* Compute the representative color for each box, fill colormap */ + for (i = 0; i < numboxes; i++) + compute_color(cinfo, & boxlist[i], i); + cinfo->actual_number_of_colors = numboxes; + TRACEMS1(cinfo, 1, JTRC_QUANT_SELECTED, numboxes); +} + + +/* + * These routines are concerned with the time-critical task of mapping input + * colors to the nearest color in the selected colormap. + * + * We re-use the histogram space as an "inverse color map", essentially a + * cache for the results of nearest-color searches. All colors within a + * histogram cell will be mapped to the same colormap entry, namely the one + * closest to the cell's center. This may not be quite the closest entry to + * the actual input color, but it's almost as good. A zero in the cache + * indicates we haven't found the nearest color for that cell yet; the array + * is cleared to zeroes before starting the mapping pass. When we find the + * nearest color for a cell, its colormap index plus one is recorded in the + * cache for future use. The pass2 scanning routines call fill_inverse_cmap + * when they need to use an unfilled entry in the cache. + * + * Our method of efficiently finding nearest colors is based on the "locally + * sorted search" idea described by Heckbert and on the incremental distance + * calculation described by Spencer W. Thomas in chapter III.1 of Graphics + * Gems II (James Arvo, ed. Academic Press, 1991). Thomas points out that + * the distances from a given colormap entry to each cell of the histogram can + * be computed quickly using an incremental method: the differences between + * distances to adjacent cells themselves differ by a constant. This allows a + * fairly fast implementation of the "brute force" approach of computing the + * distance from every colormap entry to every histogram cell. Unfortunately, + * it needs a work array to hold the best-distance-so-far for each histogram + * cell (because the inner loop has to be over cells, not colormap entries). + * The work array elements have to be INT32s, so the work array would need + * 256Kb at our recommended precision. This is not feasible in DOS machines. + * + * To get around these problems, we apply Thomas' method to compute the + * nearest colors for only the cells within a small subbox of the histogram. + * The work array need be only as big as the subbox, so the memory usage + * problem is solved. Furthermore, we need not fill subboxes that are never + * referenced in pass2; many images use only part of the color gamut, so a + * fair amount of work is saved. An additional advantage of this + * approach is that we can apply Heckbert's locality criterion to quickly + * eliminate colormap entries that are far away from the subbox; typically + * three-fourths of the colormap entries are rejected by Heckbert's criterion, + * and we need not compute their distances to individual cells in the subbox. + * The speed of this approach is heavily influenced by the subbox size: too + * small means too much overhead, too big loses because Heckbert's criterion + * can't eliminate as many colormap entries. Empirically the best subbox + * size seems to be about 1/512th of the histogram (1/8th in each direction). + * + * Thomas' article also describes a refined method which is asymptotically + * faster than the brute-force method, but it is also far more complex and + * cannot efficiently be applied to small subboxes. It is therefore not + * useful for programs intended to be portable to DOS machines. On machines + * with plenty of memory, filling the whole histogram in one shot with Thomas' + * refined method might be faster than the present code --- but then again, + * it might not be any faster, and it's certainly more complicated. + */ + + +/* log2(histogram cells in update box) for each axis; this can be adjusted */ +#define BOX_C0_LOG (HIST_C0_BITS-3) +#define BOX_C1_LOG (HIST_C1_BITS-3) +#define BOX_C2_LOG (HIST_C2_BITS-3) + +#define BOX_C0_ELEMS (1<actual_number_of_colors; + int maxc0, maxc1, maxc2; + int centerc0, centerc1, centerc2; + int i, x, ncolors; + INT32 minmaxdist, min_dist, max_dist, tdist; + INT32 mindist[MAXNUMCOLORS]; /* min distance to colormap entry i */ + + /* Compute true coordinates of update box's upper corner and center. + * Actually we compute the coordinates of the center of the upper-corner + * histogram cell, which are the upper bounds of the volume we care about. + * Note that since ">>" rounds down, the "center" values may be closer to + * min than to max; hence comparisons to them must be "<=", not "<". + */ + maxc0 = minc0 + ((1 << BOX_C0_SHIFT) - (1 << C0_SHIFT)); + centerc0 = (minc0 + maxc0) >> 1; + maxc1 = minc1 + ((1 << BOX_C1_SHIFT) - (1 << C1_SHIFT)); + centerc1 = (minc1 + maxc1) >> 1; + maxc2 = minc2 + ((1 << BOX_C2_SHIFT) - (1 << C2_SHIFT)); + centerc2 = (minc2 + maxc2) >> 1; + + /* For each color in colormap, find: + * 1. its minimum squared-distance to any point in the update box + * (zero if color is within update box); + * 2. its maximum squared-distance to any point in the update box. + * Both of these can be found by considering only the corners of the box. + * We save the minimum distance for each color in mindist[]; + * only the smallest maximum distance is of interest. + */ + minmaxdist = 0x7FFFFFFFL; + + for (i = 0; i < numcolors; i++) { + /* We compute the squared-c0-distance term, then add in the other two. */ + x = GETJSAMPLE(cinfo->colormap[0][i]); + if (x < minc0) { + tdist = (x - minc0) * C0_SCALE; + min_dist = tdist*tdist; + tdist = (x - maxc0) * C0_SCALE; + max_dist = tdist*tdist; + } else if (x > maxc0) { + tdist = (x - maxc0) * C0_SCALE; + min_dist = tdist*tdist; + tdist = (x - minc0) * C0_SCALE; + max_dist = tdist*tdist; + } else { + /* within cell range so no contribution to min_dist */ + min_dist = 0; + if (x <= centerc0) { + tdist = (x - maxc0) * C0_SCALE; + max_dist = tdist*tdist; + } else { + tdist = (x - minc0) * C0_SCALE; + max_dist = tdist*tdist; + } + } + + x = GETJSAMPLE(cinfo->colormap[1][i]); + if (x < minc1) { + tdist = (x - minc1) * C1_SCALE; + min_dist += tdist*tdist; + tdist = (x - maxc1) * C1_SCALE; + max_dist += tdist*tdist; + } else if (x > maxc1) { + tdist = (x - maxc1) * C1_SCALE; + min_dist += tdist*tdist; + tdist = (x - minc1) * C1_SCALE; + max_dist += tdist*tdist; + } else { + /* within cell range so no contribution to min_dist */ + if (x <= centerc1) { + tdist = (x - maxc1) * C1_SCALE; + max_dist += tdist*tdist; + } else { + tdist = (x - minc1) * C1_SCALE; + max_dist += tdist*tdist; + } + } + + x = GETJSAMPLE(cinfo->colormap[2][i]); + if (x < minc2) { + tdist = (x - minc2) * C2_SCALE; + min_dist += tdist*tdist; + tdist = (x - maxc2) * C2_SCALE; + max_dist += tdist*tdist; + } else if (x > maxc2) { + tdist = (x - maxc2) * C2_SCALE; + min_dist += tdist*tdist; + tdist = (x - minc2) * C2_SCALE; + max_dist += tdist*tdist; + } else { + /* within cell range so no contribution to min_dist */ + if (x <= centerc2) { + tdist = (x - maxc2) * C2_SCALE; + max_dist += tdist*tdist; + } else { + tdist = (x - minc2) * C2_SCALE; + max_dist += tdist*tdist; + } + } + + mindist[i] = min_dist; /* save away the results */ + if (max_dist < minmaxdist) + minmaxdist = max_dist; + } + + /* Now we know that no cell in the update box is more than minmaxdist + * away from some colormap entry. Therefore, only colors that are + * within minmaxdist of some part of the box need be considered. + */ + ncolors = 0; + for (i = 0; i < numcolors; i++) { + if (mindist[i] <= minmaxdist) + colorlist[ncolors++] = (JSAMPLE) i; + } + return ncolors; +} + + +LOCAL(void) +find_best_colors (j_decompress_ptr cinfo, int minc0, int minc1, int minc2, + int numcolors, JSAMPLE colorlist[], JSAMPLE bestcolor[]) +/* Find the closest colormap entry for each cell in the update box, + * given the list of candidate colors prepared by find_nearby_colors. + * Return the indexes of the closest entries in the bestcolor[] array. + * This routine uses Thomas' incremental distance calculation method to + * find the distance from a colormap entry to successive cells in the box. + */ +{ + int ic0, ic1, ic2; + int i, icolor; + register INT32 * bptr; /* pointer into bestdist[] array */ + JSAMPLE * cptr; /* pointer into bestcolor[] array */ + INT32 dist0, dist1; /* initial distance values */ + register INT32 dist2; /* current distance in inner loop */ + INT32 xx0, xx1; /* distance increments */ + register INT32 xx2; + INT32 inc0, inc1, inc2; /* initial values for increments */ + /* This array holds the distance to the nearest-so-far color for each cell */ + INT32 bestdist[BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS]; + + /* Initialize best-distance for each cell of the update box */ + bptr = bestdist; + for (i = BOX_C0_ELEMS*BOX_C1_ELEMS*BOX_C2_ELEMS-1; i >= 0; i--) + *bptr++ = 0x7FFFFFFFL; + + /* For each color selected by find_nearby_colors, + * compute its distance to the center of each cell in the box. + * If that's less than best-so-far, update best distance and color number. + */ + + /* Nominal steps between cell centers ("x" in Thomas article) */ +#define STEP_C0 ((1 << C0_SHIFT) * C0_SCALE) +#define STEP_C1 ((1 << C1_SHIFT) * C1_SCALE) +#define STEP_C2 ((1 << C2_SHIFT) * C2_SCALE) + + for (i = 0; i < numcolors; i++) { + icolor = GETJSAMPLE(colorlist[i]); + /* Compute (square of) distance from minc0/c1/c2 to this color */ + inc0 = (minc0 - GETJSAMPLE(cinfo->colormap[0][icolor])) * C0_SCALE; + dist0 = inc0*inc0; + inc1 = (minc1 - GETJSAMPLE(cinfo->colormap[1][icolor])) * C1_SCALE; + dist0 += inc1*inc1; + inc2 = (minc2 - GETJSAMPLE(cinfo->colormap[2][icolor])) * C2_SCALE; + dist0 += inc2*inc2; + /* Form the initial difference increments */ + inc0 = inc0 * (2 * STEP_C0) + STEP_C0 * STEP_C0; + inc1 = inc1 * (2 * STEP_C1) + STEP_C1 * STEP_C1; + inc2 = inc2 * (2 * STEP_C2) + STEP_C2 * STEP_C2; + /* Now loop over all cells in box, updating distance per Thomas method */ + bptr = bestdist; + cptr = bestcolor; + xx0 = inc0; + for (ic0 = BOX_C0_ELEMS-1; ic0 >= 0; ic0--) { + dist1 = dist0; + xx1 = inc1; + for (ic1 = BOX_C1_ELEMS-1; ic1 >= 0; ic1--) { + dist2 = dist1; + xx2 = inc2; + for (ic2 = BOX_C2_ELEMS-1; ic2 >= 0; ic2--) { + if (dist2 < *bptr) { + *bptr = dist2; + *cptr = (JSAMPLE) icolor; + } + dist2 += xx2; + xx2 += 2 * STEP_C2 * STEP_C2; + bptr++; + cptr++; + } + dist1 += xx1; + xx1 += 2 * STEP_C1 * STEP_C1; + } + dist0 += xx0; + xx0 += 2 * STEP_C0 * STEP_C0; + } + } +} + + +LOCAL(void) +fill_inverse_cmap (j_decompress_ptr cinfo, int c0, int c1, int c2) +/* Fill the inverse-colormap entries in the update box that contains */ +/* histogram cell c0/c1/c2. (Only that one cell MUST be filled, but */ +/* we can fill as many others as we wish.) */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + int minc0, minc1, minc2; /* lower left corner of update box */ + int ic0, ic1, ic2; + register JSAMPLE * cptr; /* pointer into bestcolor[] array */ + register histptr cachep; /* pointer into main cache array */ + /* This array lists the candidate colormap indexes. */ + JSAMPLE colorlist[MAXNUMCOLORS]; + int numcolors; /* number of candidate colors */ + /* This array holds the actually closest colormap index for each cell. */ + JSAMPLE bestcolor[BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS]; + + /* Convert cell coordinates to update box ID */ + c0 >>= BOX_C0_LOG; + c1 >>= BOX_C1_LOG; + c2 >>= BOX_C2_LOG; + + /* Compute true coordinates of update box's origin corner. + * Actually we compute the coordinates of the center of the corner + * histogram cell, which are the lower bounds of the volume we care about. + */ + minc0 = (c0 << BOX_C0_SHIFT) + ((1 << C0_SHIFT) >> 1); + minc1 = (c1 << BOX_C1_SHIFT) + ((1 << C1_SHIFT) >> 1); + minc2 = (c2 << BOX_C2_SHIFT) + ((1 << C2_SHIFT) >> 1); + + /* Determine which colormap entries are close enough to be candidates + * for the nearest entry to some cell in the update box. + */ + numcolors = find_nearby_colors(cinfo, minc0, minc1, minc2, colorlist); + + /* Determine the actually nearest colors. */ + find_best_colors(cinfo, minc0, minc1, minc2, numcolors, colorlist, + bestcolor); + + /* Save the best color numbers (plus 1) in the main cache array */ + c0 <<= BOX_C0_LOG; /* convert ID back to base cell indexes */ + c1 <<= BOX_C1_LOG; + c2 <<= BOX_C2_LOG; + cptr = bestcolor; + for (ic0 = 0; ic0 < BOX_C0_ELEMS; ic0++) { + for (ic1 = 0; ic1 < BOX_C1_ELEMS; ic1++) { + cachep = & histogram[c0+ic0][c1+ic1][c2]; + for (ic2 = 0; ic2 < BOX_C2_ELEMS; ic2++) { + *cachep++ = (histcell) (GETJSAMPLE(*cptr++) + 1); + } + } + } +} + + +/* + * Map some rows of pixels to the output colormapped representation. + */ + +METHODDEF(void) +pass2_no_dither (j_decompress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPARRAY output_buf, int num_rows) +/* This version performs no dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + register JSAMPROW inptr, outptr; + register histptr cachep; + register int c0, c1, c2; + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + + for (row = 0; row < num_rows; row++) { + inptr = input_buf[row]; + outptr = output_buf[row]; + for (col = width; col > 0; col--) { + /* get pixel value and index into the cache */ + c0 = GETJSAMPLE(*inptr++) >> C0_SHIFT; + c1 = GETJSAMPLE(*inptr++) >> C1_SHIFT; + c2 = GETJSAMPLE(*inptr++) >> C2_SHIFT; + cachep = & histogram[c0][c1][c2]; + /* If we have not seen this color before, find nearest colormap entry */ + /* and update the cache */ + if (*cachep == 0) + fill_inverse_cmap(cinfo, c0,c1,c2); + /* Now emit the colormap index for this cell */ + *outptr++ = (JSAMPLE) (*cachep - 1); + } + } +} + + +METHODDEF(void) +pass2_fs_dither (j_decompress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPARRAY output_buf, int num_rows) +/* This version performs Floyd-Steinberg dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + register LOCFSERROR cur0, cur1, cur2; /* current error or pixel value */ + LOCFSERROR belowerr0, belowerr1, belowerr2; /* error for pixel below cur */ + LOCFSERROR bpreverr0, bpreverr1, bpreverr2; /* error for below/prev col */ + register FSERRPTR errorptr; /* => fserrors[] at column before current */ + JSAMPROW inptr; /* => current input pixel */ + JSAMPROW outptr; /* => current output pixel */ + histptr cachep; + int dir; /* +1 or -1 depending on direction */ + int dir3; /* 3*dir, for advancing inptr & errorptr */ + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + JSAMPLE *range_limit = cinfo->sample_range_limit; + int *error_limit = cquantize->error_limiter; + JSAMPROW colormap0 = cinfo->colormap[0]; + JSAMPROW colormap1 = cinfo->colormap[1]; + JSAMPROW colormap2 = cinfo->colormap[2]; + SHIFT_TEMPS + + for (row = 0; row < num_rows; row++) { + inptr = input_buf[row]; + outptr = output_buf[row]; + if (cquantize->on_odd_row) { + /* work right to left in this row */ + inptr += (width-1) * 3; /* so point to rightmost pixel */ + outptr += width-1; + dir = -1; + dir3 = -3; + errorptr = cquantize->fserrors + (width+1)*3; /* => entry after last column */ + cquantize->on_odd_row = FALSE; /* flip for next time */ + } else { + /* work left to right in this row */ + dir = 1; + dir3 = 3; + errorptr = cquantize->fserrors; /* => entry before first real column */ + cquantize->on_odd_row = TRUE; /* flip for next time */ + } + /* Preset error values: no error propagated to first pixel from left */ + cur0 = cur1 = cur2 = 0; + /* and no error propagated to row below yet */ + belowerr0 = belowerr1 = belowerr2 = 0; + bpreverr0 = bpreverr1 = bpreverr2 = 0; + + for (col = width; col > 0; col--) { + /* curN holds the error propagated from the previous pixel on the + * current line. Add the error propagated from the previous line + * to form the complete error correction term for this pixel, and + * round the error term (which is expressed * 16) to an integer. + * RIGHT_SHIFT rounds towards minus infinity, so adding 8 is correct + * for either sign of the error value. + * Note: errorptr points to *previous* column's array entry. + */ + cur0 = RIGHT_SHIFT(cur0 + errorptr[dir3+0] + 8, 4); + cur1 = RIGHT_SHIFT(cur1 + errorptr[dir3+1] + 8, 4); + cur2 = RIGHT_SHIFT(cur2 + errorptr[dir3+2] + 8, 4); + /* Limit the error using transfer function set by init_error_limit. + * See comments with init_error_limit for rationale. + */ + cur0 = error_limit[cur0]; + cur1 = error_limit[cur1]; + cur2 = error_limit[cur2]; + /* Form pixel value + error, and range-limit to 0..MAXJSAMPLE. + * The maximum error is +- MAXJSAMPLE (or less with error limiting); + * this sets the required size of the range_limit array. + */ + cur0 += GETJSAMPLE(inptr[0]); + cur1 += GETJSAMPLE(inptr[1]); + cur2 += GETJSAMPLE(inptr[2]); + cur0 = GETJSAMPLE(range_limit[cur0]); + cur1 = GETJSAMPLE(range_limit[cur1]); + cur2 = GETJSAMPLE(range_limit[cur2]); + /* Index into the cache with adjusted pixel value */ + cachep = & histogram[cur0>>C0_SHIFT][cur1>>C1_SHIFT][cur2>>C2_SHIFT]; + /* If we have not seen this color before, find nearest colormap */ + /* entry and update the cache */ + if (*cachep == 0) + fill_inverse_cmap(cinfo, cur0>>C0_SHIFT,cur1>>C1_SHIFT,cur2>>C2_SHIFT); + /* Now emit the colormap index for this cell */ + { register int pixcode = *cachep - 1; + *outptr = (JSAMPLE) pixcode; + /* Compute representation error for this pixel */ + cur0 -= GETJSAMPLE(colormap0[pixcode]); + cur1 -= GETJSAMPLE(colormap1[pixcode]); + cur2 -= GETJSAMPLE(colormap2[pixcode]); + } + /* Compute error fractions to be propagated to adjacent pixels. + * Add these into the running sums, and simultaneously shift the + * next-line error sums left by 1 column. + */ + { register LOCFSERROR bnexterr, delta; + + bnexterr = cur0; /* Process component 0 */ + delta = cur0 * 2; + cur0 += delta; /* form error * 3 */ + errorptr[0] = (FSERROR) (bpreverr0 + cur0); + cur0 += delta; /* form error * 5 */ + bpreverr0 = belowerr0 + cur0; + belowerr0 = bnexterr; + cur0 += delta; /* form error * 7 */ + bnexterr = cur1; /* Process component 1 */ + delta = cur1 * 2; + cur1 += delta; /* form error * 3 */ + errorptr[1] = (FSERROR) (bpreverr1 + cur1); + cur1 += delta; /* form error * 5 */ + bpreverr1 = belowerr1 + cur1; + belowerr1 = bnexterr; + cur1 += delta; /* form error * 7 */ + bnexterr = cur2; /* Process component 2 */ + delta = cur2 * 2; + cur2 += delta; /* form error * 3 */ + errorptr[2] = (FSERROR) (bpreverr2 + cur2); + cur2 += delta; /* form error * 5 */ + bpreverr2 = belowerr2 + cur2; + belowerr2 = bnexterr; + cur2 += delta; /* form error * 7 */ + } + /* At this point curN contains the 7/16 error value to be propagated + * to the next pixel on the current line, and all the errors for the + * next line have been shifted over. We are therefore ready to move on. + */ + inptr += dir3; /* Advance pixel pointers to next column */ + outptr += dir; + errorptr += dir3; /* advance errorptr to current column */ + } + /* Post-loop cleanup: we must unload the final error values into the + * final fserrors[] entry. Note we need not unload belowerrN because + * it is for the dummy column before or after the actual array. + */ + errorptr[0] = (FSERROR) bpreverr0; /* unload prev errs into array */ + errorptr[1] = (FSERROR) bpreverr1; + errorptr[2] = (FSERROR) bpreverr2; + } +} + + +/* + * Initialize the error-limiting transfer function (lookup table). + * The raw F-S error computation can potentially compute error values of up to + * +- MAXJSAMPLE. But we want the maximum correction applied to a pixel to be + * much less, otherwise obviously wrong pixels will be created. (Typical + * effects include weird fringes at color-area boundaries, isolated bright + * pixels in a dark area, etc.) The standard advice for avoiding this problem + * is to ensure that the "corners" of the color cube are allocated as output + * colors; then repeated errors in the same direction cannot cause cascading + * error buildup. However, that only prevents the error from getting + * completely out of hand; Aaron Giles reports that error limiting improves + * the results even with corner colors allocated. + * A simple clamping of the error values to about +- MAXJSAMPLE/8 works pretty + * well, but the smoother transfer function used below is even better. Thanks + * to Aaron Giles for this idea. + */ + +LOCAL(void) +init_error_limit (j_decompress_ptr cinfo) +/* Allocate and fill in the error_limiter table */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + int * table; + int in, out; + + table = (int *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE*2+1) * SIZEOF(int)); + table += MAXJSAMPLE; /* so can index -MAXJSAMPLE .. +MAXJSAMPLE */ + cquantize->error_limiter = table; + +#define STEPSIZE ((MAXJSAMPLE+1)/16) + /* Map errors 1:1 up to +- MAXJSAMPLE/16 */ + out = 0; + for (in = 0; in < STEPSIZE; in++, out++) { + table[in] = out; table[-in] = -out; + } + /* Map errors 1:2 up to +- 3*MAXJSAMPLE/16 */ + for (; in < STEPSIZE*3; in++, out += (in&1) ? 0 : 1) { + table[in] = out; table[-in] = -out; + } + /* Clamp the rest to final out value (which is (MAXJSAMPLE+1)/8) */ + for (; in <= MAXJSAMPLE; in++) { + table[in] = out; table[-in] = -out; + } +#undef STEPSIZE +} + + +/* + * Finish up at the end of each pass. + */ + +METHODDEF(void) +finish_pass1 (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + + /* Select the representative colors and fill in cinfo->colormap */ + cinfo->colormap = cquantize->sv_colormap; + select_colors(cinfo, cquantize->desired); + /* Force next pass to zero the color index table */ + cquantize->needs_zeroed = TRUE; +} + + +METHODDEF(void) +finish_pass2 (j_decompress_ptr cinfo) +{ + /* no work */ +} + + +/* + * Initialize for each processing pass. + */ + +METHODDEF(void) +start_pass_2_quant (j_decompress_ptr cinfo, boolean is_pre_scan) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + int i; + + /* Only F-S dithering or no dithering is supported. */ + /* If user asks for ordered dither, give him F-S. */ + if (cinfo->dither_mode != JDITHER_NONE) + cinfo->dither_mode = JDITHER_FS; + + if (is_pre_scan) { + /* Set up method pointers */ + cquantize->pub.color_quantize = prescan_quantize; + cquantize->pub.finish_pass = finish_pass1; + cquantize->needs_zeroed = TRUE; /* Always zero histogram */ + } else { + /* Set up method pointers */ + if (cinfo->dither_mode == JDITHER_FS) + cquantize->pub.color_quantize = pass2_fs_dither; + else + cquantize->pub.color_quantize = pass2_no_dither; + cquantize->pub.finish_pass = finish_pass2; + + /* Make sure color count is acceptable */ + i = cinfo->actual_number_of_colors; + if (i < 1) + ERREXIT1(cinfo, JERR_QUANT_FEW_COLORS, 1); + if (i > MAXNUMCOLORS) + ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, MAXNUMCOLORS); + + if (cinfo->dither_mode == JDITHER_FS) { + size_t arraysize = (size_t) ((cinfo->output_width + 2) * + (3 * SIZEOF(FSERROR))); + /* Allocate Floyd-Steinberg workspace if we didn't already. */ + if (cquantize->fserrors == NULL) + cquantize->fserrors = (FSERRPTR) (*cinfo->mem->alloc_large) + ((j_common_ptr) cinfo, JPOOL_IMAGE, arraysize); + /* Initialize the propagated errors to zero. */ + jzero_far((void FAR *) cquantize->fserrors, arraysize); + /* Make the error-limit table if we didn't already. */ + if (cquantize->error_limiter == NULL) + init_error_limit(cinfo); + cquantize->on_odd_row = FALSE; + } + + } + /* Zero the histogram or inverse color map, if necessary */ + if (cquantize->needs_zeroed) { + for (i = 0; i < HIST_C0_ELEMS; i++) { + jzero_far((void FAR *) histogram[i], + HIST_C1_ELEMS*HIST_C2_ELEMS * SIZEOF(histcell)); + } + cquantize->needs_zeroed = FALSE; + } +} + + +/* + * Switch to a new external colormap between output passes. + */ + +METHODDEF(void) +new_color_map_2_quant (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + + /* Reset the inverse color map */ + cquantize->needs_zeroed = TRUE; +} + + +/* + * Module initialization routine for 2-pass color quantization. + */ + +GLOBAL(void) +jinit_2pass_quantizer (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize; + int i; + + cquantize = (my_cquantize_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_cquantizer)); + cinfo->cquantize = (struct jpeg_color_quantizer *) cquantize; + cquantize->pub.start_pass = start_pass_2_quant; + cquantize->pub.new_color_map = new_color_map_2_quant; + cquantize->fserrors = NULL; /* flag optional arrays not allocated */ + cquantize->error_limiter = NULL; + + /* Make sure jdmaster didn't give me a case I can't handle */ + if (cinfo->out_color_components != 3) + ERREXIT(cinfo, JERR_NOTIMPL); + + /* Allocate the histogram/inverse colormap storage */ + cquantize->histogram = (hist3d) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, HIST_C0_ELEMS * SIZEOF(hist2d)); + for (i = 0; i < HIST_C0_ELEMS; i++) { + cquantize->histogram[i] = (hist2d) (*cinfo->mem->alloc_large) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + HIST_C1_ELEMS*HIST_C2_ELEMS * SIZEOF(histcell)); + } + cquantize->needs_zeroed = TRUE; /* histogram is garbage now */ + + /* Allocate storage for the completed colormap, if required. + * We do this now since it is FAR storage and may affect + * the memory manager's space calculations. + */ + if (cinfo->enable_2pass_quant) { + /* Make sure color count is acceptable */ + int desired = cinfo->desired_number_of_colors; + /* Lower bound on # of colors ... somewhat arbitrary as long as > 0 */ + if (desired < 8) + ERREXIT1(cinfo, JERR_QUANT_FEW_COLORS, 8); + /* Make sure colormap indexes can be represented by JSAMPLEs */ + if (desired > MAXNUMCOLORS) + ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, MAXNUMCOLORS); + cquantize->sv_colormap = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo,JPOOL_IMAGE, (JDIMENSION) desired, (JDIMENSION) 3); + cquantize->desired = desired; + } else + cquantize->sv_colormap = NULL; + + /* Only F-S dithering or no dithering is supported. */ + /* If user asks for ordered dither, give him F-S. */ + if (cinfo->dither_mode != JDITHER_NONE) + cinfo->dither_mode = JDITHER_FS; + + /* Allocate Floyd-Steinberg workspace if necessary. + * This isn't really needed until pass 2, but again it is FAR storage. + * Although we will cope with a later change in dither_mode, + * we do not promise to honor max_memory_to_use if dither_mode changes. + */ + if (cinfo->dither_mode == JDITHER_FS) { + cquantize->fserrors = (FSERRPTR) (*cinfo->mem->alloc_large) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (size_t) ((cinfo->output_width + 2) * (3 * SIZEOF(FSERROR)))); + /* Might as well create the error-limiting table too. */ + init_error_limit(cinfo); + } +} + +#endif /* QUANT_2PASS_SUPPORTED */ diff --git a/mk4/modimage/jpeg-6b/jutils.c b/mk4/modimage/jpeg-6b/jutils.c new file mode 100644 index 0000000..d18a955 --- /dev/null +++ b/mk4/modimage/jpeg-6b/jutils.c @@ -0,0 +1,179 @@ +/* + * jutils.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains tables and miscellaneous utility routines needed + * for both compression and decompression. + * Note we prefix all global names with "j" to minimize conflicts with + * a surrounding application. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * jpeg_zigzag_order[i] is the zigzag-order position of the i'th element + * of a DCT block read in natural order (left to right, top to bottom). + */ + +#if 0 /* This table is not actually needed in v6a */ + +const int jpeg_zigzag_order[DCTSIZE2] = { + 0, 1, 5, 6, 14, 15, 27, 28, + 2, 4, 7, 13, 16, 26, 29, 42, + 3, 8, 12, 17, 25, 30, 41, 43, + 9, 11, 18, 24, 31, 40, 44, 53, + 10, 19, 23, 32, 39, 45, 52, 54, + 20, 22, 33, 38, 46, 51, 55, 60, + 21, 34, 37, 47, 50, 56, 59, 61, + 35, 36, 48, 49, 57, 58, 62, 63 +}; + +#endif + +/* + * jpeg_natural_order[i] is the natural-order position of the i'th element + * of zigzag order. + * + * When reading corrupted data, the Huffman decoders could attempt + * to reference an entry beyond the end of this array (if the decoded + * zero run length reaches past the end of the block). To prevent + * wild stores without adding an inner-loop test, we put some extra + * "63"s after the real entries. This will cause the extra coefficient + * to be stored in location 63 of the block, not somewhere random. + * The worst case would be a run-length of 15, which means we need 16 + * fake entries. + */ + +const int jpeg_natural_order[DCTSIZE2+16] = { + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63, + 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */ + 63, 63, 63, 63, 63, 63, 63, 63 +}; + + +/* + * Arithmetic utilities + */ + +GLOBAL(long) +jdiv_round_up (long a, long b) +/* Compute a/b rounded up to next integer, ie, ceil(a/b) */ +/* Assumes a >= 0, b > 0 */ +{ + return (a + b - 1L) / b; +} + + +GLOBAL(long) +jround_up (long a, long b) +/* Compute a rounded up to next multiple of b, ie, ceil(a/b)*b */ +/* Assumes a >= 0, b > 0 */ +{ + a += b - 1L; + return a - (a % b); +} + + +/* On normal machines we can apply MEMCOPY() and MEMZERO() to sample arrays + * and coefficient-block arrays. This won't work on 80x86 because the arrays + * are FAR and we're assuming a small-pointer memory model. However, some + * DOS compilers provide far-pointer versions of memcpy() and memset() even + * in the small-model libraries. These will be used if USE_FMEM is defined. + * Otherwise, the routines below do it the hard way. (The performance cost + * is not all that great, because these routines aren't very heavily used.) + */ + +#ifndef NEED_FAR_POINTERS /* normal case, same as regular macros */ +#define FMEMCOPY(dest,src,size) MEMCOPY(dest,src,size) +#define FMEMZERO(target,size) MEMZERO(target,size) +#else /* 80x86 case, define if we can */ +#ifdef USE_FMEM +#define FMEMCOPY(dest,src,size) _fmemcpy((void FAR *)(dest), (const void FAR *)(src), (size_t)(size)) +#define FMEMZERO(target,size) _fmemset((void FAR *)(target), 0, (size_t)(size)) +#endif +#endif + + +GLOBAL(void) +jcopy_sample_rows (JSAMPARRAY input_array, int source_row, + JSAMPARRAY output_array, int dest_row, + int num_rows, JDIMENSION num_cols) +/* Copy some rows of samples from one place to another. + * num_rows rows are copied from input_array[source_row++] + * to output_array[dest_row++]; these areas may overlap for duplication. + * The source and destination arrays must be at least as wide as num_cols. + */ +{ + register JSAMPROW inptr, outptr; +#ifdef FMEMCOPY + register size_t count = (size_t) (num_cols * SIZEOF(JSAMPLE)); +#else + register JDIMENSION count; +#endif + register int row; + + input_array += source_row; + output_array += dest_row; + + for (row = num_rows; row > 0; row--) { + inptr = *input_array++; + outptr = *output_array++; +#ifdef FMEMCOPY + FMEMCOPY(outptr, inptr, count); +#else + for (count = num_cols; count > 0; count--) + *outptr++ = *inptr++; /* needn't bother with GETJSAMPLE() here */ +#endif + } +} + + +GLOBAL(void) +jcopy_block_row (JBLOCKROW input_row, JBLOCKROW output_row, + JDIMENSION num_blocks) +/* Copy a row of coefficient blocks from one place to another. */ +{ +#ifdef FMEMCOPY + FMEMCOPY(output_row, input_row, num_blocks * (DCTSIZE2 * SIZEOF(JCOEF))); +#else + register JCOEFPTR inptr, outptr; + register long count; + + inptr = (JCOEFPTR) input_row; + outptr = (JCOEFPTR) output_row; + for (count = (long) num_blocks * DCTSIZE2; count > 0; count--) { + *outptr++ = *inptr++; + } +#endif +} + + +GLOBAL(void) +jzero_far (void FAR * target, size_t bytestozero) +/* Zero out a chunk of FAR memory. */ +/* This might be sample-array data, block-array data, or alloc_large data. */ +{ +#ifdef FMEMZERO + FMEMZERO(target, bytestozero); +#else + register char FAR * ptr = (char FAR *) target; + register size_t count; + + for (count = bytestozero; count > 0; count--) { + *ptr++ = 0; + } +#endif +} diff --git a/mk4/modimage/jpeg-6b/jversion.h b/mk4/modimage/jpeg-6b/jversion.h new file mode 100644 index 0000000..6472c58 --- /dev/null +++ b/mk4/modimage/jpeg-6b/jversion.h @@ -0,0 +1,14 @@ +/* + * jversion.h + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains software version identification. + */ + + +#define JVERSION "6b 27-Mar-1998" + +#define JCOPYRIGHT "Copyright (C) 1998, Thomas G. Lane" diff --git a/mk4/modimage/jpeg-6b/libjpeg.doc b/mk4/modimage/jpeg-6b/libjpeg.doc new file mode 100644 index 0000000..689b206 --- /dev/null +++ b/mk4/modimage/jpeg-6b/libjpeg.doc @@ -0,0 +1,3006 @@ +USING THE IJG JPEG LIBRARY + +Copyright (C) 1994-1998, Thomas G. Lane. +This file is part of the Independent JPEG Group's software. +For conditions of distribution and use, see the accompanying README file. + + +This file describes how to use the IJG JPEG library within an application +program. Read it if you want to write a program that uses the library. + +The file example.c provides heavily commented skeleton code for calling the +JPEG library. Also see jpeglib.h (the include file to be used by application +programs) for full details about data structures and function parameter lists. +The library source code, of course, is the ultimate reference. + +Note that there have been *major* changes from the application interface +presented by IJG version 4 and earlier versions. The old design had several +inherent limitations, and it had accumulated a lot of cruft as we added +features while trying to minimize application-interface changes. We have +sacrificed backward compatibility in the version 5 rewrite, but we think the +improvements justify this. + + +TABLE OF CONTENTS +----------------- + +Overview: + Functions provided by the library + Outline of typical usage +Basic library usage: + Data formats + Compression details + Decompression details + Mechanics of usage: include files, linking, etc +Advanced features: + Compression parameter selection + Decompression parameter selection + Special color spaces + Error handling + Compressed data handling (source and destination managers) + I/O suspension + Progressive JPEG support + Buffered-image mode + Abbreviated datastreams and multiple images + Special markers + Raw (downsampled) image data + Really raw data: DCT coefficients + Progress monitoring + Memory management + Memory usage + Library compile-time options + Portability considerations + Notes for MS-DOS implementors + +You should read at least the overview and basic usage sections before trying +to program with the library. The sections on advanced features can be read +if and when you need them. + + +OVERVIEW +======== + +Functions provided by the library +--------------------------------- + +The IJG JPEG library provides C code to read and write JPEG-compressed image +files. The surrounding application program receives or supplies image data a +scanline at a time, using a straightforward uncompressed image format. All +details of color conversion and other preprocessing/postprocessing can be +handled by the library. + +The library includes a substantial amount of code that is not covered by the +JPEG standard but is necessary for typical applications of JPEG. These +functions preprocess the image before JPEG compression or postprocess it after +decompression. They include colorspace conversion, downsampling/upsampling, +and color quantization. The application indirectly selects use of this code +by specifying the format in which it wishes to supply or receive image data. +For example, if colormapped output is requested, then the decompression +library automatically invokes color quantization. + +A wide range of quality vs. speed tradeoffs are possible in JPEG processing, +and even more so in decompression postprocessing. The decompression library +provides multiple implementations that cover most of the useful tradeoffs, +ranging from very-high-quality down to fast-preview operation. On the +compression side we have generally not provided low-quality choices, since +compression is normally less time-critical. It should be understood that the +low-quality modes may not meet the JPEG standard's accuracy requirements; +nonetheless, they are useful for viewers. + +A word about functions *not* provided by the library. We handle a subset of +the ISO JPEG standard; most baseline, extended-sequential, and progressive +JPEG processes are supported. (Our subset includes all features now in common +use.) Unsupported ISO options include: + * Hierarchical storage + * Lossless JPEG + * Arithmetic entropy coding (unsupported for legal reasons) + * DNL marker + * Nonintegral subsampling ratios +We support both 8- and 12-bit data precision, but this is a compile-time +choice rather than a run-time choice; hence it is difficult to use both +precisions in a single application. + +By itself, the library handles only interchange JPEG datastreams --- in +particular the widely used JFIF file format. The library can be used by +surrounding code to process interchange or abbreviated JPEG datastreams that +are embedded in more complex file formats. (For example, this library is +used by the free LIBTIFF library to support JPEG compression in TIFF.) + + +Outline of typical usage +------------------------ + +The rough outline of a JPEG compression operation is: + + Allocate and initialize a JPEG compression object + Specify the destination for the compressed data (eg, a file) + Set parameters for compression, including image size & colorspace + jpeg_start_compress(...); + while (scan lines remain to be written) + jpeg_write_scanlines(...); + jpeg_finish_compress(...); + Release the JPEG compression object + +A JPEG compression object holds parameters and working state for the JPEG +library. We make creation/destruction of the object separate from starting +or finishing compression of an image; the same object can be re-used for a +series of image compression operations. This makes it easy to re-use the +same parameter settings for a sequence of images. Re-use of a JPEG object +also has important implications for processing abbreviated JPEG datastreams, +as discussed later. + +The image data to be compressed is supplied to jpeg_write_scanlines() from +in-memory buffers. If the application is doing file-to-file compression, +reading image data from the source file is the application's responsibility. +The library emits compressed data by calling a "data destination manager", +which typically will write the data into a file; but the application can +provide its own destination manager to do something else. + +Similarly, the rough outline of a JPEG decompression operation is: + + Allocate and initialize a JPEG decompression object + Specify the source of the compressed data (eg, a file) + Call jpeg_read_header() to obtain image info + Set parameters for decompression + jpeg_start_decompress(...); + while (scan lines remain to be read) + jpeg_read_scanlines(...); + jpeg_finish_decompress(...); + Release the JPEG decompression object + +This is comparable to the compression outline except that reading the +datastream header is a separate step. This is helpful because information +about the image's size, colorspace, etc is available when the application +selects decompression parameters. For example, the application can choose an +output scaling ratio that will fit the image into the available screen size. + +The decompression library obtains compressed data by calling a data source +manager, which typically will read the data from a file; but other behaviors +can be obtained with a custom source manager. Decompressed data is delivered +into in-memory buffers passed to jpeg_read_scanlines(). + +It is possible to abort an incomplete compression or decompression operation +by calling jpeg_abort(); or, if you do not need to retain the JPEG object, +simply release it by calling jpeg_destroy(). + +JPEG compression and decompression objects are two separate struct types. +However, they share some common fields, and certain routines such as +jpeg_destroy() can work on either type of object. + +The JPEG library has no static variables: all state is in the compression +or decompression object. Therefore it is possible to process multiple +compression and decompression operations concurrently, using multiple JPEG +objects. + +Both compression and decompression can be done in an incremental memory-to- +memory fashion, if suitable source/destination managers are used. See the +section on "I/O suspension" for more details. + + +BASIC LIBRARY USAGE +=================== + +Data formats +------------ + +Before diving into procedural details, it is helpful to understand the +image data format that the JPEG library expects or returns. + +The standard input image format is a rectangular array of pixels, with each +pixel having the same number of "component" or "sample" values (color +channels). You must specify how many components there are and the colorspace +interpretation of the components. Most applications will use RGB data +(three components per pixel) or grayscale data (one component per pixel). +PLEASE NOTE THAT RGB DATA IS THREE SAMPLES PER PIXEL, GRAYSCALE ONLY ONE. +A remarkable number of people manage to miss this, only to find that their +programs don't work with grayscale JPEG files. + +There is no provision for colormapped input. JPEG files are always full-color +or full grayscale (or sometimes another colorspace such as CMYK). You can +feed in a colormapped image by expanding it to full-color format. However +JPEG often doesn't work very well with source data that has been colormapped, +because of dithering noise. This is discussed in more detail in the JPEG FAQ +and the other references mentioned in the README file. + +Pixels are stored by scanlines, with each scanline running from left to +right. The component values for each pixel are adjacent in the row; for +example, R,G,B,R,G,B,R,G,B,... for 24-bit RGB color. Each scanline is an +array of data type JSAMPLE --- which is typically "unsigned char", unless +you've changed jmorecfg.h. (You can also change the RGB pixel layout, say +to B,G,R order, by modifying jmorecfg.h. But see the restrictions listed in +that file before doing so.) + +A 2-D array of pixels is formed by making a list of pointers to the starts of +scanlines; so the scanlines need not be physically adjacent in memory. Even +if you process just one scanline at a time, you must make a one-element +pointer array to conform to this structure. Pointers to JSAMPLE rows are of +type JSAMPROW, and the pointer to the pointer array is of type JSAMPARRAY. + +The library accepts or supplies one or more complete scanlines per call. +It is not possible to process part of a row at a time. Scanlines are always +processed top-to-bottom. You can process an entire image in one call if you +have it all in memory, but usually it's simplest to process one scanline at +a time. + +For best results, source data values should have the precision specified by +BITS_IN_JSAMPLE (normally 8 bits). For instance, if you choose to compress +data that's only 6 bits/channel, you should left-justify each value in a +byte before passing it to the compressor. If you need to compress data +that has more than 8 bits/channel, compile with BITS_IN_JSAMPLE = 12. +(See "Library compile-time options", later.) + + +The data format returned by the decompressor is the same in all details, +except that colormapped output is supported. (Again, a JPEG file is never +colormapped. But you can ask the decompressor to perform on-the-fly color +quantization to deliver colormapped output.) If you request colormapped +output then the returned data array contains a single JSAMPLE per pixel; +its value is an index into a color map. The color map is represented as +a 2-D JSAMPARRAY in which each row holds the values of one color component, +that is, colormap[i][j] is the value of the i'th color component for pixel +value (map index) j. Note that since the colormap indexes are stored in +JSAMPLEs, the maximum number of colors is limited by the size of JSAMPLE +(ie, at most 256 colors for an 8-bit JPEG library). + + +Compression details +------------------- + +Here we revisit the JPEG compression outline given in the overview. + +1. Allocate and initialize a JPEG compression object. + +A JPEG compression object is a "struct jpeg_compress_struct". (It also has +a bunch of subsidiary structures which are allocated via malloc(), but the +application doesn't control those directly.) This struct can be just a local +variable in the calling routine, if a single routine is going to execute the +whole JPEG compression sequence. Otherwise it can be static or allocated +from malloc(). + +You will also need a structure representing a JPEG error handler. The part +of this that the library cares about is a "struct jpeg_error_mgr". If you +are providing your own error handler, you'll typically want to embed the +jpeg_error_mgr struct in a larger structure; this is discussed later under +"Error handling". For now we'll assume you are just using the default error +handler. The default error handler will print JPEG error/warning messages +on stderr, and it will call exit() if a fatal error occurs. + +You must initialize the error handler structure, store a pointer to it into +the JPEG object's "err" field, and then call jpeg_create_compress() to +initialize the rest of the JPEG object. + +Typical code for this step, if you are using the default error handler, is + + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; + ... + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_compress(&cinfo); + +jpeg_create_compress allocates a small amount of memory, so it could fail +if you are out of memory. In that case it will exit via the error handler; +that's why the error handler must be initialized first. + + +2. Specify the destination for the compressed data (eg, a file). + +As previously mentioned, the JPEG library delivers compressed data to a +"data destination" module. The library includes one data destination +module which knows how to write to a stdio stream. You can use your own +destination module if you want to do something else, as discussed later. + +If you use the standard destination module, you must open the target stdio +stream beforehand. Typical code for this step looks like: + + FILE * outfile; + ... + if ((outfile = fopen(filename, "wb")) == NULL) { + fprintf(stderr, "can't open %s\n", filename); + exit(1); + } + jpeg_stdio_dest(&cinfo, outfile); + +where the last line invokes the standard destination module. + +WARNING: it is critical that the binary compressed data be delivered to the +output file unchanged. On non-Unix systems the stdio library may perform +newline translation or otherwise corrupt binary data. To suppress this +behavior, you may need to use a "b" option to fopen (as shown above), or use +setmode() or another routine to put the stdio stream in binary mode. See +cjpeg.c and djpeg.c for code that has been found to work on many systems. + +You can select the data destination after setting other parameters (step 3), +if that's more convenient. You may not change the destination between +calling jpeg_start_compress() and jpeg_finish_compress(). + + +3. Set parameters for compression, including image size & colorspace. + +You must supply information about the source image by setting the following +fields in the JPEG object (cinfo structure): + + image_width Width of image, in pixels + image_height Height of image, in pixels + input_components Number of color channels (samples per pixel) + in_color_space Color space of source image + +The image dimensions are, hopefully, obvious. JPEG supports image dimensions +of 1 to 64K pixels in either direction. The input color space is typically +RGB or grayscale, and input_components is 3 or 1 accordingly. (See "Special +color spaces", later, for more info.) The in_color_space field must be +assigned one of the J_COLOR_SPACE enum constants, typically JCS_RGB or +JCS_GRAYSCALE. + +JPEG has a large number of compression parameters that determine how the +image is encoded. Most applications don't need or want to know about all +these parameters. You can set all the parameters to reasonable defaults by +calling jpeg_set_defaults(); then, if there are particular values you want +to change, you can do so after that. The "Compression parameter selection" +section tells about all the parameters. + +You must set in_color_space correctly before calling jpeg_set_defaults(), +because the defaults depend on the source image colorspace. However the +other three source image parameters need not be valid until you call +jpeg_start_compress(). There's no harm in calling jpeg_set_defaults() more +than once, if that happens to be convenient. + +Typical code for a 24-bit RGB source image is + + cinfo.image_width = Width; /* image width and height, in pixels */ + cinfo.image_height = Height; + cinfo.input_components = 3; /* # of color components per pixel */ + cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ + + jpeg_set_defaults(&cinfo); + /* Make optional parameter settings here */ + + +4. jpeg_start_compress(...); + +After you have established the data destination and set all the necessary +source image info and other parameters, call jpeg_start_compress() to begin +a compression cycle. This will initialize internal state, allocate working +storage, and emit the first few bytes of the JPEG datastream header. + +Typical code: + + jpeg_start_compress(&cinfo, TRUE); + +The "TRUE" parameter ensures that a complete JPEG interchange datastream +will be written. This is appropriate in most cases. If you think you might +want to use an abbreviated datastream, read the section on abbreviated +datastreams, below. + +Once you have called jpeg_start_compress(), you may not alter any JPEG +parameters or other fields of the JPEG object until you have completed +the compression cycle. + + +5. while (scan lines remain to be written) + jpeg_write_scanlines(...); + +Now write all the required image data by calling jpeg_write_scanlines() +one or more times. You can pass one or more scanlines in each call, up +to the total image height. In most applications it is convenient to pass +just one or a few scanlines at a time. The expected format for the passed +data is discussed under "Data formats", above. + +Image data should be written in top-to-bottom scanline order. The JPEG spec +contains some weasel wording about how top and bottom are application-defined +terms (a curious interpretation of the English language...) but if you want +your files to be compatible with everyone else's, you WILL use top-to-bottom +order. If the source data must be read in bottom-to-top order, you can use +the JPEG library's virtual array mechanism to invert the data efficiently. +Examples of this can be found in the sample application cjpeg. + +The library maintains a count of the number of scanlines written so far +in the next_scanline field of the JPEG object. Usually you can just use +this variable as the loop counter, so that the loop test looks like +"while (cinfo.next_scanline < cinfo.image_height)". + +Code for this step depends heavily on the way that you store the source data. +example.c shows the following code for the case of a full-size 2-D source +array containing 3-byte RGB pixels: + + JSAMPROW row_pointer[1]; /* pointer to a single row */ + int row_stride; /* physical row width in buffer */ + + row_stride = image_width * 3; /* JSAMPLEs per row in image_buffer */ + + while (cinfo.next_scanline < cinfo.image_height) { + row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride]; + jpeg_write_scanlines(&cinfo, row_pointer, 1); + } + +jpeg_write_scanlines() returns the number of scanlines actually written. +This will normally be equal to the number passed in, so you can usually +ignore the return value. It is different in just two cases: + * If you try to write more scanlines than the declared image height, + the additional scanlines are ignored. + * If you use a suspending data destination manager, output buffer overrun + will cause the compressor to return before accepting all the passed lines. + This feature is discussed under "I/O suspension", below. The normal + stdio destination manager will NOT cause this to happen. +In any case, the return value is the same as the change in the value of +next_scanline. + + +6. jpeg_finish_compress(...); + +After all the image data has been written, call jpeg_finish_compress() to +complete the compression cycle. This step is ESSENTIAL to ensure that the +last bufferload of data is written to the data destination. +jpeg_finish_compress() also releases working memory associated with the JPEG +object. + +Typical code: + + jpeg_finish_compress(&cinfo); + +If using the stdio destination manager, don't forget to close the output +stdio stream (if necessary) afterwards. + +If you have requested a multi-pass operating mode, such as Huffman code +optimization, jpeg_finish_compress() will perform the additional passes using +data buffered by the first pass. In this case jpeg_finish_compress() may take +quite a while to complete. With the default compression parameters, this will +not happen. + +It is an error to call jpeg_finish_compress() before writing the necessary +total number of scanlines. If you wish to abort compression, call +jpeg_abort() as discussed below. + +After completing a compression cycle, you may dispose of the JPEG object +as discussed next, or you may use it to compress another image. In that case +return to step 2, 3, or 4 as appropriate. If you do not change the +destination manager, the new datastream will be written to the same target. +If you do not change any JPEG parameters, the new datastream will be written +with the same parameters as before. Note that you can change the input image +dimensions freely between cycles, but if you change the input colorspace, you +should call jpeg_set_defaults() to adjust for the new colorspace; and then +you'll need to repeat all of step 3. + + +7. Release the JPEG compression object. + +When you are done with a JPEG compression object, destroy it by calling +jpeg_destroy_compress(). This will free all subsidiary memory (regardless of +the previous state of the object). Or you can call jpeg_destroy(), which +works for either compression or decompression objects --- this may be more +convenient if you are sharing code between compression and decompression +cases. (Actually, these routines are equivalent except for the declared type +of the passed pointer. To avoid gripes from ANSI C compilers, jpeg_destroy() +should be passed a j_common_ptr.) + +If you allocated the jpeg_compress_struct structure from malloc(), freeing +it is your responsibility --- jpeg_destroy() won't. Ditto for the error +handler structure. + +Typical code: + + jpeg_destroy_compress(&cinfo); + + +8. Aborting. + +If you decide to abort a compression cycle before finishing, you can clean up +in either of two ways: + +* If you don't need the JPEG object any more, just call + jpeg_destroy_compress() or jpeg_destroy() to release memory. This is + legitimate at any point after calling jpeg_create_compress() --- in fact, + it's safe even if jpeg_create_compress() fails. + +* If you want to re-use the JPEG object, call jpeg_abort_compress(), or call + jpeg_abort() which works on both compression and decompression objects. + This will return the object to an idle state, releasing any working memory. + jpeg_abort() is allowed at any time after successful object creation. + +Note that cleaning up the data destination, if required, is your +responsibility; neither of these routines will call term_destination(). +(See "Compressed data handling", below, for more about that.) + +jpeg_destroy() and jpeg_abort() are the only safe calls to make on a JPEG +object that has reported an error by calling error_exit (see "Error handling" +for more info). The internal state of such an object is likely to be out of +whack. Either of these two routines will return the object to a known state. + + +Decompression details +--------------------- + +Here we revisit the JPEG decompression outline given in the overview. + +1. Allocate and initialize a JPEG decompression object. + +This is just like initialization for compression, as discussed above, +except that the object is a "struct jpeg_decompress_struct" and you +call jpeg_create_decompress(). Error handling is exactly the same. + +Typical code: + + struct jpeg_decompress_struct cinfo; + struct jpeg_error_mgr jerr; + ... + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_decompress(&cinfo); + +(Both here and in the IJG code, we usually use variable name "cinfo" for +both compression and decompression objects.) + + +2. Specify the source of the compressed data (eg, a file). + +As previously mentioned, the JPEG library reads compressed data from a "data +source" module. The library includes one data source module which knows how +to read from a stdio stream. You can use your own source module if you want +to do something else, as discussed later. + +If you use the standard source module, you must open the source stdio stream +beforehand. Typical code for this step looks like: + + FILE * infile; + ... + if ((infile = fopen(filename, "rb")) == NULL) { + fprintf(stderr, "can't open %s\n", filename); + exit(1); + } + jpeg_stdio_src(&cinfo, infile); + +where the last line invokes the standard source module. + +WARNING: it is critical that the binary compressed data be read unchanged. +On non-Unix systems the stdio library may perform newline translation or +otherwise corrupt binary data. To suppress this behavior, you may need to use +a "b" option to fopen (as shown above), or use setmode() or another routine to +put the stdio stream in binary mode. See cjpeg.c and djpeg.c for code that +has been found to work on many systems. + +You may not change the data source between calling jpeg_read_header() and +jpeg_finish_decompress(). If you wish to read a series of JPEG images from +a single source file, you should repeat the jpeg_read_header() to +jpeg_finish_decompress() sequence without reinitializing either the JPEG +object or the data source module; this prevents buffered input data from +being discarded. + + +3. Call jpeg_read_header() to obtain image info. + +Typical code for this step is just + + jpeg_read_header(&cinfo, TRUE); + +This will read the source datastream header markers, up to the beginning +of the compressed data proper. On return, the image dimensions and other +info have been stored in the JPEG object. The application may wish to +consult this information before selecting decompression parameters. + +More complex code is necessary if + * A suspending data source is used --- in that case jpeg_read_header() + may return before it has read all the header data. See "I/O suspension", + below. The normal stdio source manager will NOT cause this to happen. + * Abbreviated JPEG files are to be processed --- see the section on + abbreviated datastreams. Standard applications that deal only in + interchange JPEG files need not be concerned with this case either. + +It is permissible to stop at this point if you just wanted to find out the +image dimensions and other header info for a JPEG file. In that case, +call jpeg_destroy() when you are done with the JPEG object, or call +jpeg_abort() to return it to an idle state before selecting a new data +source and reading another header. + + +4. Set parameters for decompression. + +jpeg_read_header() sets appropriate default decompression parameters based on +the properties of the image (in particular, its colorspace). However, you +may well want to alter these defaults before beginning the decompression. +For example, the default is to produce full color output from a color file. +If you want colormapped output you must ask for it. Other options allow the +returned image to be scaled and allow various speed/quality tradeoffs to be +selected. "Decompression parameter selection", below, gives details. + +If the defaults are appropriate, nothing need be done at this step. + +Note that all default values are set by each call to jpeg_read_header(). +If you reuse a decompression object, you cannot expect your parameter +settings to be preserved across cycles, as you can for compression. +You must set desired parameter values each time. + + +5. jpeg_start_decompress(...); + +Once the parameter values are satisfactory, call jpeg_start_decompress() to +begin decompression. This will initialize internal state, allocate working +memory, and prepare for returning data. + +Typical code is just + + jpeg_start_decompress(&cinfo); + +If you have requested a multi-pass operating mode, such as 2-pass color +quantization, jpeg_start_decompress() will do everything needed before data +output can begin. In this case jpeg_start_decompress() may take quite a while +to complete. With a single-scan (non progressive) JPEG file and default +decompression parameters, this will not happen; jpeg_start_decompress() will +return quickly. + +After this call, the final output image dimensions, including any requested +scaling, are available in the JPEG object; so is the selected colormap, if +colormapped output has been requested. Useful fields include + + output_width image width and height, as scaled + output_height + out_color_components # of color components in out_color_space + output_components # of color components returned per pixel + colormap the selected colormap, if any + actual_number_of_colors number of entries in colormap + +output_components is 1 (a colormap index) when quantizing colors; otherwise it +equals out_color_components. It is the number of JSAMPLE values that will be +emitted per pixel in the output arrays. + +Typically you will need to allocate data buffers to hold the incoming image. +You will need output_width * output_components JSAMPLEs per scanline in your +output buffer, and a total of output_height scanlines will be returned. + +Note: if you are using the JPEG library's internal memory manager to allocate +data buffers (as djpeg does), then the manager's protocol requires that you +request large buffers *before* calling jpeg_start_decompress(). This is a +little tricky since the output_XXX fields are not normally valid then. You +can make them valid by calling jpeg_calc_output_dimensions() after setting the +relevant parameters (scaling, output color space, and quantization flag). + + +6. while (scan lines remain to be read) + jpeg_read_scanlines(...); + +Now you can read the decompressed image data by calling jpeg_read_scanlines() +one or more times. At each call, you pass in the maximum number of scanlines +to be read (ie, the height of your working buffer); jpeg_read_scanlines() +will return up to that many lines. The return value is the number of lines +actually read. The format of the returned data is discussed under "Data +formats", above. Don't forget that grayscale and color JPEGs will return +different data formats! + +Image data is returned in top-to-bottom scanline order. If you must write +out the image in bottom-to-top order, you can use the JPEG library's virtual +array mechanism to invert the data efficiently. Examples of this can be +found in the sample application djpeg. + +The library maintains a count of the number of scanlines returned so far +in the output_scanline field of the JPEG object. Usually you can just use +this variable as the loop counter, so that the loop test looks like +"while (cinfo.output_scanline < cinfo.output_height)". (Note that the test +should NOT be against image_height, unless you never use scaling. The +image_height field is the height of the original unscaled image.) +The return value always equals the change in the value of output_scanline. + +If you don't use a suspending data source, it is safe to assume that +jpeg_read_scanlines() reads at least one scanline per call, until the +bottom of the image has been reached. + +If you use a buffer larger than one scanline, it is NOT safe to assume that +jpeg_read_scanlines() fills it. (The current implementation returns only a +few scanlines per call, no matter how large a buffer you pass.) So you must +always provide a loop that calls jpeg_read_scanlines() repeatedly until the +whole image has been read. + + +7. jpeg_finish_decompress(...); + +After all the image data has been read, call jpeg_finish_decompress() to +complete the decompression cycle. This causes working memory associated +with the JPEG object to be released. + +Typical code: + + jpeg_finish_decompress(&cinfo); + +If using the stdio source manager, don't forget to close the source stdio +stream if necessary. + +It is an error to call jpeg_finish_decompress() before reading the correct +total number of scanlines. If you wish to abort decompression, call +jpeg_abort() as discussed below. + +After completing a decompression cycle, you may dispose of the JPEG object as +discussed next, or you may use it to decompress another image. In that case +return to step 2 or 3 as appropriate. If you do not change the source +manager, the next image will be read from the same source. + + +8. Release the JPEG decompression object. + +When you are done with a JPEG decompression object, destroy it by calling +jpeg_destroy_decompress() or jpeg_destroy(). The previous discussion of +destroying compression objects applies here too. + +Typical code: + + jpeg_destroy_decompress(&cinfo); + + +9. Aborting. + +You can abort a decompression cycle by calling jpeg_destroy_decompress() or +jpeg_destroy() if you don't need the JPEG object any more, or +jpeg_abort_decompress() or jpeg_abort() if you want to reuse the object. +The previous discussion of aborting compression cycles applies here too. + + +Mechanics of usage: include files, linking, etc +----------------------------------------------- + +Applications using the JPEG library should include the header file jpeglib.h +to obtain declarations of data types and routines. Before including +jpeglib.h, include system headers that define at least the typedefs FILE and +size_t. On ANSI-conforming systems, including is sufficient; on +older Unix systems, you may need to define size_t. + +If the application needs to refer to individual JPEG library error codes, also +include jerror.h to define those symbols. + +jpeglib.h indirectly includes the files jconfig.h and jmorecfg.h. If you are +installing the JPEG header files in a system directory, you will want to +install all four files: jpeglib.h, jerror.h, jconfig.h, jmorecfg.h. + +The most convenient way to include the JPEG code into your executable program +is to prepare a library file ("libjpeg.a", or a corresponding name on non-Unix +machines) and reference it at your link step. If you use only half of the +library (only compression or only decompression), only that much code will be +included from the library, unless your linker is hopelessly brain-damaged. +The supplied makefiles build libjpeg.a automatically (see install.doc). + +While you can build the JPEG library as a shared library if the whim strikes +you, we don't really recommend it. The trouble with shared libraries is that +at some point you'll probably try to substitute a new version of the library +without recompiling the calling applications. That generally doesn't work +because the parameter struct declarations usually change with each new +version. In other words, the library's API is *not* guaranteed binary +compatible across versions; we only try to ensure source-code compatibility. +(In hindsight, it might have been smarter to hide the parameter structs from +applications and introduce a ton of access functions instead. Too late now, +however.) + +On some systems your application may need to set up a signal handler to ensure +that temporary files are deleted if the program is interrupted. This is most +critical if you are on MS-DOS and use the jmemdos.c memory manager back end; +it will try to grab extended memory for temp files, and that space will NOT be +freed automatically. See cjpeg.c or djpeg.c for an example signal handler. + +It may be worth pointing out that the core JPEG library does not actually +require the stdio library: only the default source/destination managers and +error handler need it. You can use the library in a stdio-less environment +if you replace those modules and use jmemnobs.c (or another memory manager of +your own devising). More info about the minimum system library requirements +may be found in jinclude.h. + + +ADVANCED FEATURES +================= + +Compression parameter selection +------------------------------- + +This section describes all the optional parameters you can set for JPEG +compression, as well as the "helper" routines provided to assist in this +task. Proper setting of some parameters requires detailed understanding +of the JPEG standard; if you don't know what a parameter is for, it's best +not to mess with it! See REFERENCES in the README file for pointers to +more info about JPEG. + +It's a good idea to call jpeg_set_defaults() first, even if you plan to set +all the parameters; that way your code is more likely to work with future JPEG +libraries that have additional parameters. For the same reason, we recommend +you use a helper routine where one is provided, in preference to twiddling +cinfo fields directly. + +The helper routines are: + +jpeg_set_defaults (j_compress_ptr cinfo) + This routine sets all JPEG parameters to reasonable defaults, using + only the input image's color space (field in_color_space, which must + already be set in cinfo). Many applications will only need to use + this routine and perhaps jpeg_set_quality(). + +jpeg_set_colorspace (j_compress_ptr cinfo, J_COLOR_SPACE colorspace) + Sets the JPEG file's colorspace (field jpeg_color_space) as specified, + and sets other color-space-dependent parameters appropriately. See + "Special color spaces", below, before using this. A large number of + parameters, including all per-component parameters, are set by this + routine; if you want to twiddle individual parameters you should call + jpeg_set_colorspace() before rather than after. + +jpeg_default_colorspace (j_compress_ptr cinfo) + Selects an appropriate JPEG colorspace based on cinfo->in_color_space, + and calls jpeg_set_colorspace(). This is actually a subroutine of + jpeg_set_defaults(). It's broken out in case you want to change + just the colorspace-dependent JPEG parameters. + +jpeg_set_quality (j_compress_ptr cinfo, int quality, boolean force_baseline) + Constructs JPEG quantization tables appropriate for the indicated + quality setting. The quality value is expressed on the 0..100 scale + recommended by IJG (cjpeg's "-quality" switch uses this routine). + Note that the exact mapping from quality values to tables may change + in future IJG releases as more is learned about DCT quantization. + If the force_baseline parameter is TRUE, then the quantization table + entries are constrained to the range 1..255 for full JPEG baseline + compatibility. In the current implementation, this only makes a + difference for quality settings below 25, and it effectively prevents + very small/low quality files from being generated. The IJG decoder + is capable of reading the non-baseline files generated at low quality + settings when force_baseline is FALSE, but other decoders may not be. + +jpeg_set_linear_quality (j_compress_ptr cinfo, int scale_factor, + boolean force_baseline) + Same as jpeg_set_quality() except that the generated tables are the + sample tables given in the JPEC spec section K.1, multiplied by the + specified scale factor (which is expressed as a percentage; thus + scale_factor = 100 reproduces the spec's tables). Note that larger + scale factors give lower quality. This entry point is useful for + conforming to the Adobe PostScript DCT conventions, but we do not + recommend linear scaling as a user-visible quality scale otherwise. + force_baseline again constrains the computed table entries to 1..255. + +int jpeg_quality_scaling (int quality) + Converts a value on the IJG-recommended quality scale to a linear + scaling percentage. Note that this routine may change or go away + in future releases --- IJG may choose to adopt a scaling method that + can't be expressed as a simple scalar multiplier, in which case the + premise of this routine collapses. Caveat user. + +jpeg_add_quant_table (j_compress_ptr cinfo, int which_tbl, + const unsigned int *basic_table, + int scale_factor, boolean force_baseline) + Allows an arbitrary quantization table to be created. which_tbl + indicates which table slot to fill. basic_table points to an array + of 64 unsigned ints given in normal array order. These values are + multiplied by scale_factor/100 and then clamped to the range 1..65535 + (or to 1..255 if force_baseline is TRUE). + CAUTION: prior to library version 6a, jpeg_add_quant_table expected + the basic table to be given in JPEG zigzag order. If you need to + write code that works with either older or newer versions of this + routine, you must check the library version number. Something like + "#if JPEG_LIB_VERSION >= 61" is the right test. + +jpeg_simple_progression (j_compress_ptr cinfo) + Generates a default scan script for writing a progressive-JPEG file. + This is the recommended method of creating a progressive file, + unless you want to make a custom scan sequence. You must ensure that + the JPEG color space is set correctly before calling this routine. + + +Compression parameters (cinfo fields) include: + +J_DCT_METHOD dct_method + Selects the algorithm used for the DCT step. Choices are: + JDCT_ISLOW: slow but accurate integer algorithm + JDCT_IFAST: faster, less accurate integer method + JDCT_FLOAT: floating-point method + JDCT_DEFAULT: default method (normally JDCT_ISLOW) + JDCT_FASTEST: fastest method (normally JDCT_IFAST) + The FLOAT method is very slightly more accurate than the ISLOW method, + but may give different results on different machines due to varying + roundoff behavior. The integer methods should give the same results + on all machines. On machines with sufficiently fast FP hardware, the + floating-point method may also be the fastest. The IFAST method is + considerably less accurate than the other two; its use is not + recommended if high quality is a concern. JDCT_DEFAULT and + JDCT_FASTEST are macros configurable by each installation. + +J_COLOR_SPACE jpeg_color_space +int num_components + The JPEG color space and corresponding number of components; see + "Special color spaces", below, for more info. We recommend using + jpeg_set_color_space() if you want to change these. + +boolean optimize_coding + TRUE causes the compressor to compute optimal Huffman coding tables + for the image. This requires an extra pass over the data and + therefore costs a good deal of space and time. The default is + FALSE, which tells the compressor to use the supplied or default + Huffman tables. In most cases optimal tables save only a few percent + of file size compared to the default tables. Note that when this is + TRUE, you need not supply Huffman tables at all, and any you do + supply will be overwritten. + +unsigned int restart_interval +int restart_in_rows + To emit restart markers in the JPEG file, set one of these nonzero. + Set restart_interval to specify the exact interval in MCU blocks. + Set restart_in_rows to specify the interval in MCU rows. (If + restart_in_rows is not 0, then restart_interval is set after the + image width in MCUs is computed.) Defaults are zero (no restarts). + One restart marker per MCU row is often a good choice. + NOTE: the overhead of restart markers is higher in grayscale JPEG + files than in color files, and MUCH higher in progressive JPEGs. + If you use restarts, you may want to use larger intervals in those + cases. + +const jpeg_scan_info * scan_info +int num_scans + By default, scan_info is NULL; this causes the compressor to write a + single-scan sequential JPEG file. If not NULL, scan_info points to + an array of scan definition records of length num_scans. The + compressor will then write a JPEG file having one scan for each scan + definition record. This is used to generate noninterleaved or + progressive JPEG files. The library checks that the scan array + defines a valid JPEG scan sequence. (jpeg_simple_progression creates + a suitable scan definition array for progressive JPEG.) This is + discussed further under "Progressive JPEG support". + +int smoothing_factor + If non-zero, the input image is smoothed; the value should be 1 for + minimal smoothing to 100 for maximum smoothing. Consult jcsample.c + for details of the smoothing algorithm. The default is zero. + +boolean write_JFIF_header + If TRUE, a JFIF APP0 marker is emitted. jpeg_set_defaults() and + jpeg_set_colorspace() set this TRUE if a JFIF-legal JPEG color space + (ie, YCbCr or grayscale) is selected, otherwise FALSE. + +UINT8 JFIF_major_version +UINT8 JFIF_minor_version + The version number to be written into the JFIF marker. + jpeg_set_defaults() initializes the version to 1.01 (major=minor=1). + You should set it to 1.02 (major=1, minor=2) if you plan to write + any JFIF 1.02 extension markers. + +UINT8 density_unit +UINT16 X_density +UINT16 Y_density + The resolution information to be written into the JFIF marker; + not used otherwise. density_unit may be 0 for unknown, + 1 for dots/inch, or 2 for dots/cm. The default values are 0,1,1 + indicating square pixels of unknown size. + +boolean write_Adobe_marker + If TRUE, an Adobe APP14 marker is emitted. jpeg_set_defaults() and + jpeg_set_colorspace() set this TRUE if JPEG color space RGB, CMYK, + or YCCK is selected, otherwise FALSE. It is generally a bad idea + to set both write_JFIF_header and write_Adobe_marker. In fact, + you probably shouldn't change the default settings at all --- the + default behavior ensures that the JPEG file's color space can be + recognized by the decoder. + +JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS] + Pointers to coefficient quantization tables, one per table slot, + or NULL if no table is defined for a slot. Usually these should + be set via one of the above helper routines; jpeg_add_quant_table() + is general enough to define any quantization table. The other + routines will set up table slot 0 for luminance quality and table + slot 1 for chrominance. + +JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS] +JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS] + Pointers to Huffman coding tables, one per table slot, or NULL if + no table is defined for a slot. Slots 0 and 1 are filled with the + JPEG sample tables by jpeg_set_defaults(). If you need to allocate + more table structures, jpeg_alloc_huff_table() may be used. + Note that optimal Huffman tables can be computed for an image + by setting optimize_coding, as discussed above; there's seldom + any need to mess with providing your own Huffman tables. + +There are some additional cinfo fields which are not documented here +because you currently can't change them; for example, you can't set +arith_code TRUE because arithmetic coding is unsupported. + + +Per-component parameters are stored in the struct cinfo.comp_info[i] for +component number i. Note that components here refer to components of the +JPEG color space, *not* the source image color space. A suitably large +comp_info[] array is allocated by jpeg_set_defaults(); if you choose not +to use that routine, it's up to you to allocate the array. + +int component_id + The one-byte identifier code to be recorded in the JPEG file for + this component. For the standard color spaces, we recommend you + leave the default values alone. + +int h_samp_factor +int v_samp_factor + Horizontal and vertical sampling factors for the component; must + be 1..4 according to the JPEG standard. Note that larger sampling + factors indicate a higher-resolution component; many people find + this behavior quite unintuitive. The default values are 2,2 for + luminance components and 1,1 for chrominance components, except + for grayscale where 1,1 is used. + +int quant_tbl_no + Quantization table number for component. The default value is + 0 for luminance components and 1 for chrominance components. + +int dc_tbl_no +int ac_tbl_no + DC and AC entropy coding table numbers. The default values are + 0 for luminance components and 1 for chrominance components. + +int component_index + Must equal the component's index in comp_info[]. (Beginning in + release v6, the compressor library will fill this in automatically; + you don't have to.) + + +Decompression parameter selection +--------------------------------- + +Decompression parameter selection is somewhat simpler than compression +parameter selection, since all of the JPEG internal parameters are +recorded in the source file and need not be supplied by the application. +(Unless you are working with abbreviated files, in which case see +"Abbreviated datastreams", below.) Decompression parameters control +the postprocessing done on the image to deliver it in a format suitable +for the application's use. Many of the parameters control speed/quality +tradeoffs, in which faster decompression may be obtained at the price of +a poorer-quality image. The defaults select the highest quality (slowest) +processing. + +The following fields in the JPEG object are set by jpeg_read_header() and +may be useful to the application in choosing decompression parameters: + +JDIMENSION image_width Width and height of image +JDIMENSION image_height +int num_components Number of color components +J_COLOR_SPACE jpeg_color_space Colorspace of image +boolean saw_JFIF_marker TRUE if a JFIF APP0 marker was seen + UINT8 JFIF_major_version Version information from JFIF marker + UINT8 JFIF_minor_version + UINT8 density_unit Resolution data from JFIF marker + UINT16 X_density + UINT16 Y_density +boolean saw_Adobe_marker TRUE if an Adobe APP14 marker was seen + UINT8 Adobe_transform Color transform code from Adobe marker + +The JPEG color space, unfortunately, is something of a guess since the JPEG +standard proper does not provide a way to record it. In practice most files +adhere to the JFIF or Adobe conventions, and the decoder will recognize these +correctly. See "Special color spaces", below, for more info. + + +The decompression parameters that determine the basic properties of the +returned image are: + +J_COLOR_SPACE out_color_space + Output color space. jpeg_read_header() sets an appropriate default + based on jpeg_color_space; typically it will be RGB or grayscale. + The application can change this field to request output in a different + colorspace. For example, set it to JCS_GRAYSCALE to get grayscale + output from a color file. (This is useful for previewing: grayscale + output is faster than full color since the color components need not + be processed.) Note that not all possible color space transforms are + currently implemented; you may need to extend jdcolor.c if you want an + unusual conversion. + +unsigned int scale_num, scale_denom + Scale the image by the fraction scale_num/scale_denom. Default is + 1/1, or no scaling. Currently, the only supported scaling ratios + are 1/1, 1/2, 1/4, and 1/8. (The library design allows for arbitrary + scaling ratios but this is not likely to be implemented any time soon.) + Smaller scaling ratios permit significantly faster decoding since + fewer pixels need be processed and a simpler IDCT method can be used. + +boolean quantize_colors + If set TRUE, colormapped output will be delivered. Default is FALSE, + meaning that full-color output will be delivered. + +The next three parameters are relevant only if quantize_colors is TRUE. + +int desired_number_of_colors + Maximum number of colors to use in generating a library-supplied color + map (the actual number of colors is returned in a different field). + Default 256. Ignored when the application supplies its own color map. + +boolean two_pass_quantize + If TRUE, an extra pass over the image is made to select a custom color + map for the image. This usually looks a lot better than the one-size- + fits-all colormap that is used otherwise. Default is TRUE. Ignored + when the application supplies its own color map. + +J_DITHER_MODE dither_mode + Selects color dithering method. Supported values are: + JDITHER_NONE no dithering: fast, very low quality + JDITHER_ORDERED ordered dither: moderate speed and quality + JDITHER_FS Floyd-Steinberg dither: slow, high quality + Default is JDITHER_FS. (At present, ordered dither is implemented + only in the single-pass, standard-colormap case. If you ask for + ordered dither when two_pass_quantize is TRUE or when you supply + an external color map, you'll get F-S dithering.) + +When quantize_colors is TRUE, the target color map is described by the next +two fields. colormap is set to NULL by jpeg_read_header(). The application +can supply a color map by setting colormap non-NULL and setting +actual_number_of_colors to the map size. Otherwise, jpeg_start_decompress() +selects a suitable color map and sets these two fields itself. +[Implementation restriction: at present, an externally supplied colormap is +only accepted for 3-component output color spaces.] + +JSAMPARRAY colormap + The color map, represented as a 2-D pixel array of out_color_components + rows and actual_number_of_colors columns. Ignored if not quantizing. + CAUTION: if the JPEG library creates its own colormap, the storage + pointed to by this field is released by jpeg_finish_decompress(). + Copy the colormap somewhere else first, if you want to save it. + +int actual_number_of_colors + The number of colors in the color map. + +Additional decompression parameters that the application may set include: + +J_DCT_METHOD dct_method + Selects the algorithm used for the DCT step. Choices are the same + as described above for compression. + +boolean do_fancy_upsampling + If TRUE, do careful upsampling of chroma components. If FALSE, + a faster but sloppier method is used. Default is TRUE. The visual + impact of the sloppier method is often very small. + +boolean do_block_smoothing + If TRUE, interblock smoothing is applied in early stages of decoding + progressive JPEG files; if FALSE, not. Default is TRUE. Early + progression stages look "fuzzy" with smoothing, "blocky" without. + In any case, block smoothing ceases to be applied after the first few + AC coefficients are known to full accuracy, so it is relevant only + when using buffered-image mode for progressive images. + +boolean enable_1pass_quant +boolean enable_external_quant +boolean enable_2pass_quant + These are significant only in buffered-image mode, which is + described in its own section below. + + +The output image dimensions are given by the following fields. These are +computed from the source image dimensions and the decompression parameters +by jpeg_start_decompress(). You can also call jpeg_calc_output_dimensions() +to obtain the values that will result from the current parameter settings. +This can be useful if you are trying to pick a scaling ratio that will get +close to a desired target size. It's also important if you are using the +JPEG library's memory manager to allocate output buffer space, because you +are supposed to request such buffers *before* jpeg_start_decompress(). + +JDIMENSION output_width Actual dimensions of output image. +JDIMENSION output_height +int out_color_components Number of color components in out_color_space. +int output_components Number of color components returned. +int rec_outbuf_height Recommended height of scanline buffer. + +When quantizing colors, output_components is 1, indicating a single color map +index per pixel. Otherwise it equals out_color_components. The output arrays +are required to be output_width * output_components JSAMPLEs wide. + +rec_outbuf_height is the recommended minimum height (in scanlines) of the +buffer passed to jpeg_read_scanlines(). If the buffer is smaller, the +library will still work, but time will be wasted due to unnecessary data +copying. In high-quality modes, rec_outbuf_height is always 1, but some +faster, lower-quality modes set it to larger values (typically 2 to 4). +If you are going to ask for a high-speed processing mode, you may as well +go to the trouble of honoring rec_outbuf_height so as to avoid data copying. +(An output buffer larger than rec_outbuf_height lines is OK, but won't +provide any material speed improvement over that height.) + + +Special color spaces +-------------------- + +The JPEG standard itself is "color blind" and doesn't specify any particular +color space. It is customary to convert color data to a luminance/chrominance +color space before compressing, since this permits greater compression. The +existing de-facto JPEG file format standards specify YCbCr or grayscale data +(JFIF), or grayscale, RGB, YCbCr, CMYK, or YCCK (Adobe). For special +applications such as multispectral images, other color spaces can be used, +but it must be understood that such files will be unportable. + +The JPEG library can handle the most common colorspace conversions (namely +RGB <=> YCbCr and CMYK <=> YCCK). It can also deal with data of an unknown +color space, passing it through without conversion. If you deal extensively +with an unusual color space, you can easily extend the library to understand +additional color spaces and perform appropriate conversions. + +For compression, the source data's color space is specified by field +in_color_space. This is transformed to the JPEG file's color space given +by jpeg_color_space. jpeg_set_defaults() chooses a reasonable JPEG color +space depending on in_color_space, but you can override this by calling +jpeg_set_colorspace(). Of course you must select a supported transformation. +jccolor.c currently supports the following transformations: + RGB => YCbCr + RGB => GRAYSCALE + YCbCr => GRAYSCALE + CMYK => YCCK +plus the null transforms: GRAYSCALE => GRAYSCALE, RGB => RGB, +YCbCr => YCbCr, CMYK => CMYK, YCCK => YCCK, and UNKNOWN => UNKNOWN. + +The de-facto file format standards (JFIF and Adobe) specify APPn markers that +indicate the color space of the JPEG file. It is important to ensure that +these are written correctly, or omitted if the JPEG file's color space is not +one of the ones supported by the de-facto standards. jpeg_set_colorspace() +will set the compression parameters to include or omit the APPn markers +properly, so long as it is told the truth about the JPEG color space. +For example, if you are writing some random 3-component color space without +conversion, don't try to fake out the library by setting in_color_space and +jpeg_color_space to JCS_YCbCr; use JCS_UNKNOWN. You may want to write an +APPn marker of your own devising to identify the colorspace --- see "Special +markers", below. + +When told that the color space is UNKNOWN, the library will default to using +luminance-quality compression parameters for all color components. You may +well want to change these parameters. See the source code for +jpeg_set_colorspace(), in jcparam.c, for details. + +For decompression, the JPEG file's color space is given in jpeg_color_space, +and this is transformed to the output color space out_color_space. +jpeg_read_header's setting of jpeg_color_space can be relied on if the file +conforms to JFIF or Adobe conventions, but otherwise it is no better than a +guess. If you know the JPEG file's color space for certain, you can override +jpeg_read_header's guess by setting jpeg_color_space. jpeg_read_header also +selects a default output color space based on (its guess of) jpeg_color_space; +set out_color_space to override this. Again, you must select a supported +transformation. jdcolor.c currently supports + YCbCr => GRAYSCALE + YCbCr => RGB + GRAYSCALE => RGB + YCCK => CMYK +as well as the null transforms. (Since GRAYSCALE=>RGB is provided, an +application can force grayscale JPEGs to look like color JPEGs if it only +wants to handle one case.) + +The two-pass color quantizer, jquant2.c, is specialized to handle RGB data +(it weights distances appropriately for RGB colors). You'll need to modify +the code if you want to use it for non-RGB output color spaces. Note that +jquant2.c is used to map to an application-supplied colormap as well as for +the normal two-pass colormap selection process. + +CAUTION: it appears that Adobe Photoshop writes inverted data in CMYK JPEG +files: 0 represents 100% ink coverage, rather than 0% ink as you'd expect. +This is arguably a bug in Photoshop, but if you need to work with Photoshop +CMYK files, you will have to deal with it in your application. We cannot +"fix" this in the library by inverting the data during the CMYK<=>YCCK +transform, because that would break other applications, notably Ghostscript. +Photoshop versions prior to 3.0 write EPS files containing JPEG-encoded CMYK +data in the same inverted-YCCK representation used in bare JPEG files, but +the surrounding PostScript code performs an inversion using the PS image +operator. I am told that Photoshop 3.0 will write uninverted YCCK in +EPS/JPEG files, and will omit the PS-level inversion. (But the data +polarity used in bare JPEG files will not change in 3.0.) In either case, +the JPEG library must not invert the data itself, or else Ghostscript would +read these EPS files incorrectly. + + +Error handling +-------------- + +When the default error handler is used, any error detected inside the JPEG +routines will cause a message to be printed on stderr, followed by exit(). +You can supply your own error handling routines to override this behavior +and to control the treatment of nonfatal warnings and trace/debug messages. +The file example.c illustrates the most common case, which is to have the +application regain control after an error rather than exiting. + +The JPEG library never writes any message directly; it always goes through +the error handling routines. Three classes of messages are recognized: + * Fatal errors: the library cannot continue. + * Warnings: the library can continue, but the data is corrupt, and a + damaged output image is likely to result. + * Trace/informational messages. These come with a trace level indicating + the importance of the message; you can control the verbosity of the + program by adjusting the maximum trace level that will be displayed. + +You may, if you wish, simply replace the entire JPEG error handling module +(jerror.c) with your own code. However, you can avoid code duplication by +only replacing some of the routines depending on the behavior you need. +This is accomplished by calling jpeg_std_error() as usual, but then overriding +some of the method pointers in the jpeg_error_mgr struct, as illustrated by +example.c. + +All of the error handling routines will receive a pointer to the JPEG object +(a j_common_ptr which points to either a jpeg_compress_struct or a +jpeg_decompress_struct; if you need to tell which, test the is_decompressor +field). This struct includes a pointer to the error manager struct in its +"err" field. Frequently, custom error handler routines will need to access +additional data which is not known to the JPEG library or the standard error +handler. The most convenient way to do this is to embed either the JPEG +object or the jpeg_error_mgr struct in a larger structure that contains +additional fields; then casting the passed pointer provides access to the +additional fields. Again, see example.c for one way to do it. (Beginning +with IJG version 6b, there is also a void pointer "client_data" in each +JPEG object, which the application can also use to find related data. +The library does not touch client_data at all.) + +The individual methods that you might wish to override are: + +error_exit (j_common_ptr cinfo) + Receives control for a fatal error. Information sufficient to + generate the error message has been stored in cinfo->err; call + output_message to display it. Control must NOT return to the caller; + generally this routine will exit() or longjmp() somewhere. + Typically you would override this routine to get rid of the exit() + default behavior. Note that if you continue processing, you should + clean up the JPEG object with jpeg_abort() or jpeg_destroy(). + +output_message (j_common_ptr cinfo) + Actual output of any JPEG message. Override this to send messages + somewhere other than stderr. Note that this method does not know + how to generate a message, only where to send it. + +format_message (j_common_ptr cinfo, char * buffer) + Constructs a readable error message string based on the error info + stored in cinfo->err. This method is called by output_message. Few + applications should need to override this method. One possible + reason for doing so is to implement dynamic switching of error message + language. + +emit_message (j_common_ptr cinfo, int msg_level) + Decide whether or not to emit a warning or trace message; if so, + calls output_message. The main reason for overriding this method + would be to abort on warnings. msg_level is -1 for warnings, + 0 and up for trace messages. + +Only error_exit() and emit_message() are called from the rest of the JPEG +library; the other two are internal to the error handler. + +The actual message texts are stored in an array of strings which is pointed to +by the field err->jpeg_message_table. The messages are numbered from 0 to +err->last_jpeg_message, and it is these code numbers that are used in the +JPEG library code. You could replace the message texts (for instance, with +messages in French or German) by changing the message table pointer. See +jerror.h for the default texts. CAUTION: this table will almost certainly +change or grow from one library version to the next. + +It may be useful for an application to add its own message texts that are +handled by the same mechanism. The error handler supports a second "add-on" +message table for this purpose. To define an addon table, set the pointer +err->addon_message_table and the message numbers err->first_addon_message and +err->last_addon_message. If you number the addon messages beginning at 1000 +or so, you won't have to worry about conflicts with the library's built-in +messages. See the sample applications cjpeg/djpeg for an example of using +addon messages (the addon messages are defined in cderror.h). + +Actual invocation of the error handler is done via macros defined in jerror.h: + ERREXITn(...) for fatal errors + WARNMSn(...) for corrupt-data warnings + TRACEMSn(...) for trace and informational messages. +These macros store the message code and any additional parameters into the +error handler struct, then invoke the error_exit() or emit_message() method. +The variants of each macro are for varying numbers of additional parameters. +The additional parameters are inserted into the generated message using +standard printf() format codes. + +See jerror.h and jerror.c for further details. + + +Compressed data handling (source and destination managers) +---------------------------------------------------------- + +The JPEG compression library sends its compressed data to a "destination +manager" module. The default destination manager just writes the data to a +stdio stream, but you can provide your own manager to do something else. +Similarly, the decompression library calls a "source manager" to obtain the +compressed data; you can provide your own source manager if you want the data +to come from somewhere other than a stdio stream. + +In both cases, compressed data is processed a bufferload at a time: the +destination or source manager provides a work buffer, and the library invokes +the manager only when the buffer is filled or emptied. (You could define a +one-character buffer to force the manager to be invoked for each byte, but +that would be rather inefficient.) The buffer's size and location are +controlled by the manager, not by the library. For example, if you desired to +decompress a JPEG datastream that was all in memory, you could just make the +buffer pointer and length point to the original data in memory. Then the +buffer-reload procedure would be invoked only if the decompressor ran off the +end of the datastream, which would indicate an erroneous datastream. + +The work buffer is defined as an array of datatype JOCTET, which is generally +"char" or "unsigned char". On a machine where char is not exactly 8 bits +wide, you must define JOCTET as a wider data type and then modify the data +source and destination modules to transcribe the work arrays into 8-bit units +on external storage. + +A data destination manager struct contains a pointer and count defining the +next byte to write in the work buffer and the remaining free space: + + JOCTET * next_output_byte; /* => next byte to write in buffer */ + size_t free_in_buffer; /* # of byte spaces remaining in buffer */ + +The library increments the pointer and decrements the count until the buffer +is filled. The manager's empty_output_buffer method must reset the pointer +and count. The manager is expected to remember the buffer's starting address +and total size in private fields not visible to the library. + +A data destination manager provides three methods: + +init_destination (j_compress_ptr cinfo) + Initialize destination. This is called by jpeg_start_compress() + before any data is actually written. It must initialize + next_output_byte and free_in_buffer. free_in_buffer must be + initialized to a positive value. + +empty_output_buffer (j_compress_ptr cinfo) + This is called whenever the buffer has filled (free_in_buffer + reaches zero). In typical applications, it should write out the + *entire* buffer (use the saved start address and buffer length; + ignore the current state of next_output_byte and free_in_buffer). + Then reset the pointer & count to the start of the buffer, and + return TRUE indicating that the buffer has been dumped. + free_in_buffer must be set to a positive value when TRUE is + returned. A FALSE return should only be used when I/O suspension is + desired (this operating mode is discussed in the next section). + +term_destination (j_compress_ptr cinfo) + Terminate destination --- called by jpeg_finish_compress() after all + data has been written. In most applications, this must flush any + data remaining in the buffer. Use either next_output_byte or + free_in_buffer to determine how much data is in the buffer. + +term_destination() is NOT called by jpeg_abort() or jpeg_destroy(). If you +want the destination manager to be cleaned up during an abort, you must do it +yourself. + +You will also need code to create a jpeg_destination_mgr struct, fill in its +method pointers, and insert a pointer to the struct into the "dest" field of +the JPEG compression object. This can be done in-line in your setup code if +you like, but it's probably cleaner to provide a separate routine similar to +the jpeg_stdio_dest() routine of the supplied destination manager. + +Decompression source managers follow a parallel design, but with some +additional frammishes. The source manager struct contains a pointer and count +defining the next byte to read from the work buffer and the number of bytes +remaining: + + const JOCTET * next_input_byte; /* => next byte to read from buffer */ + size_t bytes_in_buffer; /* # of bytes remaining in buffer */ + +The library increments the pointer and decrements the count until the buffer +is emptied. The manager's fill_input_buffer method must reset the pointer and +count. In most applications, the manager must remember the buffer's starting +address and total size in private fields not visible to the library. + +A data source manager provides five methods: + +init_source (j_decompress_ptr cinfo) + Initialize source. This is called by jpeg_read_header() before any + data is actually read. Unlike init_destination(), it may leave + bytes_in_buffer set to 0 (in which case a fill_input_buffer() call + will occur immediately). + +fill_input_buffer (j_decompress_ptr cinfo) + This is called whenever bytes_in_buffer has reached zero and more + data is wanted. In typical applications, it should read fresh data + into the buffer (ignoring the current state of next_input_byte and + bytes_in_buffer), reset the pointer & count to the start of the + buffer, and return TRUE indicating that the buffer has been reloaded. + It is not necessary to fill the buffer entirely, only to obtain at + least one more byte. bytes_in_buffer MUST be set to a positive value + if TRUE is returned. A FALSE return should only be used when I/O + suspension is desired (this mode is discussed in the next section). + +skip_input_data (j_decompress_ptr cinfo, long num_bytes) + Skip num_bytes worth of data. The buffer pointer and count should + be advanced over num_bytes input bytes, refilling the buffer as + needed. This is used to skip over a potentially large amount of + uninteresting data (such as an APPn marker). In some applications + it may be possible to optimize away the reading of the skipped data, + but it's not clear that being smart is worth much trouble; large + skips are uncommon. bytes_in_buffer may be zero on return. + A zero or negative skip count should be treated as a no-op. + +resync_to_restart (j_decompress_ptr cinfo, int desired) + This routine is called only when the decompressor has failed to find + a restart (RSTn) marker where one is expected. Its mission is to + find a suitable point for resuming decompression. For most + applications, we recommend that you just use the default resync + procedure, jpeg_resync_to_restart(). However, if you are able to back + up in the input data stream, or if you have a-priori knowledge about + the likely location of restart markers, you may be able to do better. + Read the read_restart_marker() and jpeg_resync_to_restart() routines + in jdmarker.c if you think you'd like to implement your own resync + procedure. + +term_source (j_decompress_ptr cinfo) + Terminate source --- called by jpeg_finish_decompress() after all + data has been read. Often a no-op. + +For both fill_input_buffer() and skip_input_data(), there is no such thing +as an EOF return. If the end of the file has been reached, the routine has +a choice of exiting via ERREXIT() or inserting fake data into the buffer. +In most cases, generating a warning message and inserting a fake EOI marker +is the best course of action --- this will allow the decompressor to output +however much of the image is there. In pathological cases, the decompressor +may swallow the EOI and again demand data ... just keep feeding it fake EOIs. +jdatasrc.c illustrates the recommended error recovery behavior. + +term_source() is NOT called by jpeg_abort() or jpeg_destroy(). If you want +the source manager to be cleaned up during an abort, you must do it yourself. + +You will also need code to create a jpeg_source_mgr struct, fill in its method +pointers, and insert a pointer to the struct into the "src" field of the JPEG +decompression object. This can be done in-line in your setup code if you +like, but it's probably cleaner to provide a separate routine similar to the +jpeg_stdio_src() routine of the supplied source manager. + +For more information, consult the stdio source and destination managers +in jdatasrc.c and jdatadst.c. + + +I/O suspension +-------------- + +Some applications need to use the JPEG library as an incremental memory-to- +memory filter: when the compressed data buffer is filled or emptied, they want +control to return to the outer loop, rather than expecting that the buffer can +be emptied or reloaded within the data source/destination manager subroutine. +The library supports this need by providing an "I/O suspension" mode, which we +describe in this section. + +The I/O suspension mode is not a panacea: nothing is guaranteed about the +maximum amount of time spent in any one call to the library, so it will not +eliminate response-time problems in single-threaded applications. If you +need guaranteed response time, we suggest you "bite the bullet" and implement +a real multi-tasking capability. + +To use I/O suspension, cooperation is needed between the calling application +and the data source or destination manager; you will always need a custom +source/destination manager. (Please read the previous section if you haven't +already.) The basic idea is that the empty_output_buffer() or +fill_input_buffer() routine is a no-op, merely returning FALSE to indicate +that it has done nothing. Upon seeing this, the JPEG library suspends +operation and returns to its caller. The surrounding application is +responsible for emptying or refilling the work buffer before calling the +JPEG library again. + +Compression suspension: + +For compression suspension, use an empty_output_buffer() routine that returns +FALSE; typically it will not do anything else. This will cause the +compressor to return to the caller of jpeg_write_scanlines(), with the return +value indicating that not all the supplied scanlines have been accepted. +The application must make more room in the output buffer, adjust the output +buffer pointer/count appropriately, and then call jpeg_write_scanlines() +again, pointing to the first unconsumed scanline. + +When forced to suspend, the compressor will backtrack to a convenient stopping +point (usually the start of the current MCU); it will regenerate some output +data when restarted. Therefore, although empty_output_buffer() is only +called when the buffer is filled, you should NOT write out the entire buffer +after a suspension. Write only the data up to the current position of +next_output_byte/free_in_buffer. The data beyond that point will be +regenerated after resumption. + +Because of the backtracking behavior, a good-size output buffer is essential +for efficiency; you don't want the compressor to suspend often. (In fact, an +overly small buffer could lead to infinite looping, if a single MCU required +more data than would fit in the buffer.) We recommend a buffer of at least +several Kbytes. You may want to insert explicit code to ensure that you don't +call jpeg_write_scanlines() unless there is a reasonable amount of space in +the output buffer; in other words, flush the buffer before trying to compress +more data. + +The compressor does not allow suspension while it is trying to write JPEG +markers at the beginning and end of the file. This means that: + * At the beginning of a compression operation, there must be enough free + space in the output buffer to hold the header markers (typically 600 or + so bytes). The recommended buffer size is bigger than this anyway, so + this is not a problem as long as you start with an empty buffer. However, + this restriction might catch you if you insert large special markers, such + as a JFIF thumbnail image, without flushing the buffer afterwards. + * When you call jpeg_finish_compress(), there must be enough space in the + output buffer to emit any buffered data and the final EOI marker. In the + current implementation, half a dozen bytes should suffice for this, but + for safety's sake we recommend ensuring that at least 100 bytes are free + before calling jpeg_finish_compress(). + +A more significant restriction is that jpeg_finish_compress() cannot suspend. +This means you cannot use suspension with multi-pass operating modes, namely +Huffman code optimization and multiple-scan output. Those modes write the +whole file during jpeg_finish_compress(), which will certainly result in +buffer overrun. (Note that this restriction applies only to compression, +not decompression. The decompressor supports input suspension in all of its +operating modes.) + +Decompression suspension: + +For decompression suspension, use a fill_input_buffer() routine that simply +returns FALSE (except perhaps during error recovery, as discussed below). +This will cause the decompressor to return to its caller with an indication +that suspension has occurred. This can happen at four places: + * jpeg_read_header(): will return JPEG_SUSPENDED. + * jpeg_start_decompress(): will return FALSE, rather than its usual TRUE. + * jpeg_read_scanlines(): will return the number of scanlines already + completed (possibly 0). + * jpeg_finish_decompress(): will return FALSE, rather than its usual TRUE. +The surrounding application must recognize these cases, load more data into +the input buffer, and repeat the call. In the case of jpeg_read_scanlines(), +increment the passed pointers past any scanlines successfully read. + +Just as with compression, the decompressor will typically backtrack to a +convenient restart point before suspending. When fill_input_buffer() is +called, next_input_byte/bytes_in_buffer point to the current restart point, +which is where the decompressor will backtrack to if FALSE is returned. +The data beyond that position must NOT be discarded if you suspend; it needs +to be re-read upon resumption. In most implementations, you'll need to shift +this data down to the start of your work buffer and then load more data after +it. Again, this behavior means that a several-Kbyte work buffer is essential +for decent performance; furthermore, you should load a reasonable amount of +new data before resuming decompression. (If you loaded, say, only one new +byte each time around, you could waste a LOT of cycles.) + +The skip_input_data() source manager routine requires special care in a +suspension scenario. This routine is NOT granted the ability to suspend the +decompressor; it can decrement bytes_in_buffer to zero, but no more. If the +requested skip distance exceeds the amount of data currently in the input +buffer, then skip_input_data() must set bytes_in_buffer to zero and record the +additional skip distance somewhere else. The decompressor will immediately +call fill_input_buffer(), which should return FALSE, which will cause a +suspension return. The surrounding application must then arrange to discard +the recorded number of bytes before it resumes loading the input buffer. +(Yes, this design is rather baroque, but it avoids complexity in the far more +common case where a non-suspending source manager is used.) + +If the input data has been exhausted, we recommend that you emit a warning +and insert dummy EOI markers just as a non-suspending data source manager +would do. This can be handled either in the surrounding application logic or +within fill_input_buffer(); the latter is probably more efficient. If +fill_input_buffer() knows that no more data is available, it can set the +pointer/count to point to a dummy EOI marker and then return TRUE just as +though it had read more data in a non-suspending situation. + +The decompressor does not attempt to suspend within standard JPEG markers; +instead it will backtrack to the start of the marker and reprocess the whole +marker next time. Hence the input buffer must be large enough to hold the +longest standard marker in the file. Standard JPEG markers should normally +not exceed a few hundred bytes each (DHT tables are typically the longest). +We recommend at least a 2K buffer for performance reasons, which is much +larger than any correct marker is likely to be. For robustness against +damaged marker length counts, you may wish to insert a test in your +application for the case that the input buffer is completely full and yet +the decoder has suspended without consuming any data --- otherwise, if this +situation did occur, it would lead to an endless loop. (The library can't +provide this test since it has no idea whether "the buffer is full", or +even whether there is a fixed-size input buffer.) + +The input buffer would need to be 64K to allow for arbitrary COM or APPn +markers, but these are handled specially: they are either saved into allocated +memory, or skipped over by calling skip_input_data(). In the former case, +suspension is handled correctly, and in the latter case, the problem of +buffer overrun is placed on skip_input_data's shoulders, as explained above. +Note that if you provide your own marker handling routine for large markers, +you should consider how to deal with buffer overflow. + +Multiple-buffer management: + +In some applications it is desirable to store the compressed data in a linked +list of buffer areas, so as to avoid data copying. This can be handled by +having empty_output_buffer() or fill_input_buffer() set the pointer and count +to reference the next available buffer; FALSE is returned only if no more +buffers are available. Although seemingly straightforward, there is a +pitfall in this approach: the backtrack that occurs when FALSE is returned +could back up into an earlier buffer. For example, when fill_input_buffer() +is called, the current pointer & count indicate the backtrack restart point. +Since fill_input_buffer() will set the pointer and count to refer to a new +buffer, the restart position must be saved somewhere else. Suppose a second +call to fill_input_buffer() occurs in the same library call, and no +additional input data is available, so fill_input_buffer must return FALSE. +If the JPEG library has not moved the pointer/count forward in the current +buffer, then *the correct restart point is the saved position in the prior +buffer*. Prior buffers may be discarded only after the library establishes +a restart point within a later buffer. Similar remarks apply for output into +a chain of buffers. + +The library will never attempt to backtrack over a skip_input_data() call, +so any skipped data can be permanently discarded. You still have to deal +with the case of skipping not-yet-received data, however. + +It's much simpler to use only a single buffer; when fill_input_buffer() is +called, move any unconsumed data (beyond the current pointer/count) down to +the beginning of this buffer and then load new data into the remaining buffer +space. This approach requires a little more data copying but is far easier +to get right. + + +Progressive JPEG support +------------------------ + +Progressive JPEG rearranges the stored data into a series of scans of +increasing quality. In situations where a JPEG file is transmitted across a +slow communications link, a decoder can generate a low-quality image very +quickly from the first scan, then gradually improve the displayed quality as +more scans are received. The final image after all scans are complete is +identical to that of a regular (sequential) JPEG file of the same quality +setting. Progressive JPEG files are often slightly smaller than equivalent +sequential JPEG files, but the possibility of incremental display is the main +reason for using progressive JPEG. + +The IJG encoder library generates progressive JPEG files when given a +suitable "scan script" defining how to divide the data into scans. +Creation of progressive JPEG files is otherwise transparent to the encoder. +Progressive JPEG files can also be read transparently by the decoder library. +If the decoding application simply uses the library as defined above, it +will receive a final decoded image without any indication that the file was +progressive. Of course, this approach does not allow incremental display. +To perform incremental display, an application needs to use the decoder +library's "buffered-image" mode, in which it receives a decoded image +multiple times. + +Each displayed scan requires about as much work to decode as a full JPEG +image of the same size, so the decoder must be fairly fast in relation to the +data transmission rate in order to make incremental display useful. However, +it is possible to skip displaying the image and simply add the incoming bits +to the decoder's coefficient buffer. This is fast because only Huffman +decoding need be done, not IDCT, upsampling, colorspace conversion, etc. +The IJG decoder library allows the application to switch dynamically between +displaying the image and simply absorbing the incoming bits. A properly +coded application can automatically adapt the number of display passes to +suit the time available as the image is received. Also, a final +higher-quality display cycle can be performed from the buffered data after +the end of the file is reached. + +Progressive compression: + +To create a progressive JPEG file (or a multiple-scan sequential JPEG file), +set the scan_info cinfo field to point to an array of scan descriptors, and +perform compression as usual. Instead of constructing your own scan list, +you can call the jpeg_simple_progression() helper routine to create a +recommended progression sequence; this method should be used by all +applications that don't want to get involved in the nitty-gritty of +progressive scan sequence design. (If you want to provide user control of +scan sequences, you may wish to borrow the scan script reading code found +in rdswitch.c, so that you can read scan script files just like cjpeg's.) +When scan_info is not NULL, the compression library will store DCT'd data +into a buffer array as jpeg_write_scanlines() is called, and will emit all +the requested scans during jpeg_finish_compress(). This implies that +multiple-scan output cannot be created with a suspending data destination +manager, since jpeg_finish_compress() does not support suspension. We +should also note that the compressor currently forces Huffman optimization +mode when creating a progressive JPEG file, because the default Huffman +tables are unsuitable for progressive files. + +Progressive decompression: + +When buffered-image mode is not used, the decoder library will read all of +a multi-scan file during jpeg_start_decompress(), so that it can provide a +final decoded image. (Here "multi-scan" means either progressive or +multi-scan sequential.) This makes multi-scan files transparent to the +decoding application. However, existing applications that used suspending +input with version 5 of the IJG library will need to be modified to check +for a suspension return from jpeg_start_decompress(). + +To perform incremental display, an application must use the library's +buffered-image mode. This is described in the next section. + + +Buffered-image mode +------------------- + +In buffered-image mode, the library stores the partially decoded image in a +coefficient buffer, from which it can be read out as many times as desired. +This mode is typically used for incremental display of progressive JPEG files, +but it can be used with any JPEG file. Each scan of a progressive JPEG file +adds more data (more detail) to the buffered image. The application can +display in lockstep with the source file (one display pass per input scan), +or it can allow input processing to outrun display processing. By making +input and display processing run independently, it is possible for the +application to adapt progressive display to a wide range of data transmission +rates. + +The basic control flow for buffered-image decoding is + + jpeg_create_decompress() + set data source + jpeg_read_header() + set overall decompression parameters + cinfo.buffered_image = TRUE; /* select buffered-image mode */ + jpeg_start_decompress() + for (each output pass) { + adjust output decompression parameters if required + jpeg_start_output() /* start a new output pass */ + for (all scanlines in image) { + jpeg_read_scanlines() + display scanlines + } + jpeg_finish_output() /* terminate output pass */ + } + jpeg_finish_decompress() + jpeg_destroy_decompress() + +This differs from ordinary unbuffered decoding in that there is an additional +level of looping. The application can choose how many output passes to make +and how to display each pass. + +The simplest approach to displaying progressive images is to do one display +pass for each scan appearing in the input file. In this case the outer loop +condition is typically + while (! jpeg_input_complete(&cinfo)) +and the start-output call should read + jpeg_start_output(&cinfo, cinfo.input_scan_number); +The second parameter to jpeg_start_output() indicates which scan of the input +file is to be displayed; the scans are numbered starting at 1 for this +purpose. (You can use a loop counter starting at 1 if you like, but using +the library's input scan counter is easier.) The library automatically reads +data as necessary to complete each requested scan, and jpeg_finish_output() +advances to the next scan or end-of-image marker (hence input_scan_number +will be incremented by the time control arrives back at jpeg_start_output()). +With this technique, data is read from the input file only as needed, and +input and output processing run in lockstep. + +After reading the final scan and reaching the end of the input file, the +buffered image remains available; it can be read additional times by +repeating the jpeg_start_output()/jpeg_read_scanlines()/jpeg_finish_output() +sequence. For example, a useful technique is to use fast one-pass color +quantization for display passes made while the image is arriving, followed by +a final display pass using two-pass quantization for highest quality. This +is done by changing the library parameters before the final output pass. +Changing parameters between passes is discussed in detail below. + +In general the last scan of a progressive file cannot be recognized as such +until after it is read, so a post-input display pass is the best approach if +you want special processing in the final pass. + +When done with the image, be sure to call jpeg_finish_decompress() to release +the buffered image (or just use jpeg_destroy_decompress()). + +If input data arrives faster than it can be displayed, the application can +cause the library to decode input data in advance of what's needed to produce +output. This is done by calling the routine jpeg_consume_input(). +The return value is one of the following: + JPEG_REACHED_SOS: reached an SOS marker (the start of a new scan) + JPEG_REACHED_EOI: reached the EOI marker (end of image) + JPEG_ROW_COMPLETED: completed reading one MCU row of compressed data + JPEG_SCAN_COMPLETED: completed reading last MCU row of current scan + JPEG_SUSPENDED: suspended before completing any of the above +(JPEG_SUSPENDED can occur only if a suspending data source is used.) This +routine can be called at any time after initializing the JPEG object. It +reads some additional data and returns when one of the indicated significant +events occurs. (If called after the EOI marker is reached, it will +immediately return JPEG_REACHED_EOI without attempting to read more data.) + +The library's output processing will automatically call jpeg_consume_input() +whenever the output processing overtakes the input; thus, simple lockstep +display requires no direct calls to jpeg_consume_input(). But by adding +calls to jpeg_consume_input(), you can absorb data in advance of what is +being displayed. This has two benefits: + * You can limit buildup of unprocessed data in your input buffer. + * You can eliminate extra display passes by paying attention to the + state of the library's input processing. + +The first of these benefits only requires interspersing calls to +jpeg_consume_input() with your display operations and any other processing +you may be doing. To avoid wasting cycles due to backtracking, it's best to +call jpeg_consume_input() only after a hundred or so new bytes have arrived. +This is discussed further under "I/O suspension", above. (Note: the JPEG +library currently is not thread-safe. You must not call jpeg_consume_input() +from one thread of control if a different library routine is working on the +same JPEG object in another thread.) + +When input arrives fast enough that more than one new scan is available +before you start a new output pass, you may as well skip the output pass +corresponding to the completed scan. This occurs for free if you pass +cinfo.input_scan_number as the target scan number to jpeg_start_output(). +The input_scan_number field is simply the index of the scan currently being +consumed by the input processor. You can ensure that this is up-to-date by +emptying the input buffer just before calling jpeg_start_output(): call +jpeg_consume_input() repeatedly until it returns JPEG_SUSPENDED or +JPEG_REACHED_EOI. + +The target scan number passed to jpeg_start_output() is saved in the +cinfo.output_scan_number field. The library's output processing calls +jpeg_consume_input() whenever the current input scan number and row within +that scan is less than or equal to the current output scan number and row. +Thus, input processing can "get ahead" of the output processing but is not +allowed to "fall behind". You can achieve several different effects by +manipulating this interlock rule. For example, if you pass a target scan +number greater than the current input scan number, the output processor will +wait until that scan starts to arrive before producing any output. (To avoid +an infinite loop, the target scan number is automatically reset to the last +scan number when the end of image is reached. Thus, if you specify a large +target scan number, the library will just absorb the entire input file and +then perform an output pass. This is effectively the same as what +jpeg_start_decompress() does when you don't select buffered-image mode.) +When you pass a target scan number equal to the current input scan number, +the image is displayed no faster than the current input scan arrives. The +final possibility is to pass a target scan number less than the current input +scan number; this disables the input/output interlock and causes the output +processor to simply display whatever it finds in the image buffer, without +waiting for input. (However, the library will not accept a target scan +number less than one, so you can't avoid waiting for the first scan.) + +When data is arriving faster than the output display processing can advance +through the image, jpeg_consume_input() will store data into the buffered +image beyond the point at which the output processing is reading data out +again. If the input arrives fast enough, it may "wrap around" the buffer to +the point where the input is more than one whole scan ahead of the output. +If the output processing simply proceeds through its display pass without +paying attention to the input, the effect seen on-screen is that the lower +part of the image is one or more scans better in quality than the upper part. +Then, when the next output scan is started, you have a choice of what target +scan number to use. The recommended choice is to use the current input scan +number at that time, which implies that you've skipped the output scans +corresponding to the input scans that were completed while you processed the +previous output scan. In this way, the decoder automatically adapts its +speed to the arriving data, by skipping output scans as necessary to keep up +with the arriving data. + +When using this strategy, you'll want to be sure that you perform a final +output pass after receiving all the data; otherwise your last display may not +be full quality across the whole screen. So the right outer loop logic is +something like this: + do { + absorb any waiting input by calling jpeg_consume_input() + final_pass = jpeg_input_complete(&cinfo); + adjust output decompression parameters if required + jpeg_start_output(&cinfo, cinfo.input_scan_number); + ... + jpeg_finish_output() + } while (! final_pass); +rather than quitting as soon as jpeg_input_complete() returns TRUE. This +arrangement makes it simple to use higher-quality decoding parameters +for the final pass. But if you don't want to use special parameters for +the final pass, the right loop logic is like this: + for (;;) { + absorb any waiting input by calling jpeg_consume_input() + jpeg_start_output(&cinfo, cinfo.input_scan_number); + ... + jpeg_finish_output() + if (jpeg_input_complete(&cinfo) && + cinfo.input_scan_number == cinfo.output_scan_number) + break; + } +In this case you don't need to know in advance whether an output pass is to +be the last one, so it's not necessary to have reached EOF before starting +the final output pass; rather, what you want to test is whether the output +pass was performed in sync with the final input scan. This form of the loop +will avoid an extra output pass whenever the decoder is able (or nearly able) +to keep up with the incoming data. + +When the data transmission speed is high, you might begin a display pass, +then find that much or all of the file has arrived before you can complete +the pass. (You can detect this by noting the JPEG_REACHED_EOI return code +from jpeg_consume_input(), or equivalently by testing jpeg_input_complete().) +In this situation you may wish to abort the current display pass and start a +new one using the newly arrived information. To do so, just call +jpeg_finish_output() and then start a new pass with jpeg_start_output(). + +A variant strategy is to abort and restart display if more than one complete +scan arrives during an output pass; this can be detected by noting +JPEG_REACHED_SOS returns and/or examining cinfo.input_scan_number. This +idea should be employed with caution, however, since the display process +might never get to the bottom of the image before being aborted, resulting +in the lower part of the screen being several passes worse than the upper. +In most cases it's probably best to abort an output pass only if the whole +file has arrived and you want to begin the final output pass immediately. + +When receiving data across a communication link, we recommend always using +the current input scan number for the output target scan number; if a +higher-quality final pass is to be done, it should be started (aborting any +incomplete output pass) as soon as the end of file is received. However, +many other strategies are possible. For example, the application can examine +the parameters of the current input scan and decide whether to display it or +not. If the scan contains only chroma data, one might choose not to use it +as the target scan, expecting that the scan will be small and will arrive +quickly. To skip to the next scan, call jpeg_consume_input() until it +returns JPEG_REACHED_SOS or JPEG_REACHED_EOI. Or just use the next higher +number as the target scan for jpeg_start_output(); but that method doesn't +let you inspect the next scan's parameters before deciding to display it. + + +In buffered-image mode, jpeg_start_decompress() never performs input and +thus never suspends. An application that uses input suspension with +buffered-image mode must be prepared for suspension returns from these +routines: +* jpeg_start_output() performs input only if you request 2-pass quantization + and the target scan isn't fully read yet. (This is discussed below.) +* jpeg_read_scanlines(), as always, returns the number of scanlines that it + was able to produce before suspending. +* jpeg_finish_output() will read any markers following the target scan, + up to the end of the file or the SOS marker that begins another scan. + (But it reads no input if jpeg_consume_input() has already reached the + end of the file or a SOS marker beyond the target output scan.) +* jpeg_finish_decompress() will read until the end of file, and thus can + suspend if the end hasn't already been reached (as can be tested by + calling jpeg_input_complete()). +jpeg_start_output(), jpeg_finish_output(), and jpeg_finish_decompress() +all return TRUE if they completed their tasks, FALSE if they had to suspend. +In the event of a FALSE return, the application must load more input data +and repeat the call. Applications that use non-suspending data sources need +not check the return values of these three routines. + + +It is possible to change decoding parameters between output passes in the +buffered-image mode. The decoder library currently supports only very +limited changes of parameters. ONLY THE FOLLOWING parameter changes are +allowed after jpeg_start_decompress() is called: +* dct_method can be changed before each call to jpeg_start_output(). + For example, one could use a fast DCT method for early scans, changing + to a higher quality method for the final scan. +* dither_mode can be changed before each call to jpeg_start_output(); + of course this has no impact if not using color quantization. Typically + one would use ordered dither for initial passes, then switch to + Floyd-Steinberg dither for the final pass. Caution: changing dither mode + can cause more memory to be allocated by the library. Although the amount + of memory involved is not large (a scanline or so), it may cause the + initial max_memory_to_use specification to be exceeded, which in the worst + case would result in an out-of-memory failure. +* do_block_smoothing can be changed before each call to jpeg_start_output(). + This setting is relevant only when decoding a progressive JPEG image. + During the first DC-only scan, block smoothing provides a very "fuzzy" look + instead of the very "blocky" look seen without it; which is better seems a + matter of personal taste. But block smoothing is nearly always a win + during later stages, especially when decoding a successive-approximation + image: smoothing helps to hide the slight blockiness that otherwise shows + up on smooth gradients until the lowest coefficient bits are sent. +* Color quantization mode can be changed under the rules described below. + You *cannot* change between full-color and quantized output (because that + would alter the required I/O buffer sizes), but you can change which + quantization method is used. + +When generating color-quantized output, changing quantization method is a +very useful way of switching between high-speed and high-quality display. +The library allows you to change among its three quantization methods: +1. Single-pass quantization to a fixed color cube. + Selected by cinfo.two_pass_quantize = FALSE and cinfo.colormap = NULL. +2. Single-pass quantization to an application-supplied colormap. + Selected by setting cinfo.colormap to point to the colormap (the value of + two_pass_quantize is ignored); also set cinfo.actual_number_of_colors. +3. Two-pass quantization to a colormap chosen specifically for the image. + Selected by cinfo.two_pass_quantize = TRUE and cinfo.colormap = NULL. + (This is the default setting selected by jpeg_read_header, but it is + probably NOT what you want for the first pass of progressive display!) +These methods offer successively better quality and lesser speed. However, +only the first method is available for quantizing in non-RGB color spaces. + +IMPORTANT: because the different quantizer methods have very different +working-storage requirements, the library requires you to indicate which +one(s) you intend to use before you call jpeg_start_decompress(). (If we did +not require this, the max_memory_to_use setting would be a complete fiction.) +You do this by setting one or more of these three cinfo fields to TRUE: + enable_1pass_quant Fixed color cube colormap + enable_external_quant Externally-supplied colormap + enable_2pass_quant Two-pass custom colormap +All three are initialized FALSE by jpeg_read_header(). But +jpeg_start_decompress() automatically sets TRUE the one selected by the +current two_pass_quantize and colormap settings, so you only need to set the +enable flags for any other quantization methods you plan to change to later. + +After setting the enable flags correctly at jpeg_start_decompress() time, you +can change to any enabled quantization method by setting two_pass_quantize +and colormap properly just before calling jpeg_start_output(). The following +special rules apply: +1. You must explicitly set cinfo.colormap to NULL when switching to 1-pass + or 2-pass mode from a different mode, or when you want the 2-pass + quantizer to be re-run to generate a new colormap. +2. To switch to an external colormap, or to change to a different external + colormap than was used on the prior pass, you must call + jpeg_new_colormap() after setting cinfo.colormap. +NOTE: if you want to use the same colormap as was used in the prior pass, +you should not do either of these things. This will save some nontrivial +switchover costs. +(These requirements exist because cinfo.colormap will always be non-NULL +after completing a prior output pass, since both the 1-pass and 2-pass +quantizers set it to point to their output colormaps. Thus you have to +do one of these two things to notify the library that something has changed. +Yup, it's a bit klugy, but it's necessary to do it this way for backwards +compatibility.) + +Note that in buffered-image mode, the library generates any requested colormap +during jpeg_start_output(), not during jpeg_start_decompress(). + +When using two-pass quantization, jpeg_start_output() makes a pass over the +buffered image to determine the optimum color map; it therefore may take a +significant amount of time, whereas ordinarily it does little work. The +progress monitor hook is called during this pass, if defined. It is also +important to realize that if the specified target scan number is greater than +or equal to the current input scan number, jpeg_start_output() will attempt +to consume input as it makes this pass. If you use a suspending data source, +you need to check for a FALSE return from jpeg_start_output() under these +conditions. The combination of 2-pass quantization and a not-yet-fully-read +target scan is the only case in which jpeg_start_output() will consume input. + + +Application authors who support buffered-image mode may be tempted to use it +for all JPEG images, even single-scan ones. This will work, but it is +inefficient: there is no need to create an image-sized coefficient buffer for +single-scan images. Requesting buffered-image mode for such an image wastes +memory. Worse, it can cost time on large images, since the buffered data has +to be swapped out or written to a temporary file. If you are concerned about +maximum performance on baseline JPEG files, you should use buffered-image +mode only when the incoming file actually has multiple scans. This can be +tested by calling jpeg_has_multiple_scans(), which will return a correct +result at any time after jpeg_read_header() completes. + +It is also worth noting that when you use jpeg_consume_input() to let input +processing get ahead of output processing, the resulting pattern of access to +the coefficient buffer is quite nonsequential. It's best to use the memory +manager jmemnobs.c if you can (ie, if you have enough real or virtual main +memory). If not, at least make sure that max_memory_to_use is set as high as +possible. If the JPEG memory manager has to use a temporary file, you will +probably see a lot of disk traffic and poor performance. (This could be +improved with additional work on the memory manager, but we haven't gotten +around to it yet.) + +In some applications it may be convenient to use jpeg_consume_input() for all +input processing, including reading the initial markers; that is, you may +wish to call jpeg_consume_input() instead of jpeg_read_header() during +startup. This works, but note that you must check for JPEG_REACHED_SOS and +JPEG_REACHED_EOI return codes as the equivalent of jpeg_read_header's codes. +Once the first SOS marker has been reached, you must call +jpeg_start_decompress() before jpeg_consume_input() will consume more input; +it'll just keep returning JPEG_REACHED_SOS until you do. If you read a +tables-only file this way, jpeg_consume_input() will return JPEG_REACHED_EOI +without ever returning JPEG_REACHED_SOS; be sure to check for this case. +If this happens, the decompressor will not read any more input until you call +jpeg_abort() to reset it. It is OK to call jpeg_consume_input() even when not +using buffered-image mode, but in that case it's basically a no-op after the +initial markers have been read: it will just return JPEG_SUSPENDED. + + +Abbreviated datastreams and multiple images +------------------------------------------- + +A JPEG compression or decompression object can be reused to process multiple +images. This saves a small amount of time per image by eliminating the +"create" and "destroy" operations, but that isn't the real purpose of the +feature. Rather, reuse of an object provides support for abbreviated JPEG +datastreams. Object reuse can also simplify processing a series of images in +a single input or output file. This section explains these features. + +A JPEG file normally contains several hundred bytes worth of quantization +and Huffman tables. In a situation where many images will be stored or +transmitted with identical tables, this may represent an annoying overhead. +The JPEG standard therefore permits tables to be omitted. The standard +defines three classes of JPEG datastreams: + * "Interchange" datastreams contain an image and all tables needed to decode + the image. These are the usual kind of JPEG file. + * "Abbreviated image" datastreams contain an image, but are missing some or + all of the tables needed to decode that image. + * "Abbreviated table specification" (henceforth "tables-only") datastreams + contain only table specifications. +To decode an abbreviated image, it is necessary to load the missing table(s) +into the decoder beforehand. This can be accomplished by reading a separate +tables-only file. A variant scheme uses a series of images in which the first +image is an interchange (complete) datastream, while subsequent ones are +abbreviated and rely on the tables loaded by the first image. It is assumed +that once the decoder has read a table, it will remember that table until a +new definition for the same table number is encountered. + +It is the application designer's responsibility to figure out how to associate +the correct tables with an abbreviated image. While abbreviated datastreams +can be useful in a closed environment, their use is strongly discouraged in +any situation where data exchange with other applications might be needed. +Caveat designer. + +The JPEG library provides support for reading and writing any combination of +tables-only datastreams and abbreviated images. In both compression and +decompression objects, a quantization or Huffman table will be retained for +the lifetime of the object, unless it is overwritten by a new table definition. + + +To create abbreviated image datastreams, it is only necessary to tell the +compressor not to emit some or all of the tables it is using. Each +quantization and Huffman table struct contains a boolean field "sent_table", +which normally is initialized to FALSE. For each table used by the image, the +header-writing process emits the table and sets sent_table = TRUE unless it is +already TRUE. (In normal usage, this prevents outputting the same table +definition multiple times, as would otherwise occur because the chroma +components typically share tables.) Thus, setting this field to TRUE before +calling jpeg_start_compress() will prevent the table from being written at +all. + +If you want to create a "pure" abbreviated image file containing no tables, +just call "jpeg_suppress_tables(&cinfo, TRUE)" after constructing all the +tables. If you want to emit some but not all tables, you'll need to set the +individual sent_table fields directly. + +To create an abbreviated image, you must also call jpeg_start_compress() +with a second parameter of FALSE, not TRUE. Otherwise jpeg_start_compress() +will force all the sent_table fields to FALSE. (This is a safety feature to +prevent abbreviated images from being created accidentally.) + +To create a tables-only file, perform the same parameter setup that you +normally would, but instead of calling jpeg_start_compress() and so on, call +jpeg_write_tables(&cinfo). This will write an abbreviated datastream +containing only SOI, DQT and/or DHT markers, and EOI. All the quantization +and Huffman tables that are currently defined in the compression object will +be emitted unless their sent_tables flag is already TRUE, and then all the +sent_tables flags will be set TRUE. + +A sure-fire way to create matching tables-only and abbreviated image files +is to proceed as follows: + + create JPEG compression object + set JPEG parameters + set destination to tables-only file + jpeg_write_tables(&cinfo); + set destination to image file + jpeg_start_compress(&cinfo, FALSE); + write data... + jpeg_finish_compress(&cinfo); + +Since the JPEG parameters are not altered between writing the table file and +the abbreviated image file, the same tables are sure to be used. Of course, +you can repeat the jpeg_start_compress() ... jpeg_finish_compress() sequence +many times to produce many abbreviated image files matching the table file. + +You cannot suppress output of the computed Huffman tables when Huffman +optimization is selected. (If you could, there'd be no way to decode the +image...) Generally, you don't want to set optimize_coding = TRUE when +you are trying to produce abbreviated files. + +In some cases you might want to compress an image using tables which are +not stored in the application, but are defined in an interchange or +tables-only file readable by the application. This can be done by setting up +a JPEG decompression object to read the specification file, then copying the +tables into your compression object. See jpeg_copy_critical_parameters() +for an example of copying quantization tables. + + +To read abbreviated image files, you simply need to load the proper tables +into the decompression object before trying to read the abbreviated image. +If the proper tables are stored in the application program, you can just +allocate the table structs and fill in their contents directly. For example, +to load a fixed quantization table into table slot "n": + + if (cinfo.quant_tbl_ptrs[n] == NULL) + cinfo.quant_tbl_ptrs[n] = jpeg_alloc_quant_table((j_common_ptr) &cinfo); + quant_ptr = cinfo.quant_tbl_ptrs[n]; /* quant_ptr is JQUANT_TBL* */ + for (i = 0; i < 64; i++) { + /* Qtable[] is desired quantization table, in natural array order */ + quant_ptr->quantval[i] = Qtable[i]; + } + +Code to load a fixed Huffman table is typically (for AC table "n"): + + if (cinfo.ac_huff_tbl_ptrs[n] == NULL) + cinfo.ac_huff_tbl_ptrs[n] = jpeg_alloc_huff_table((j_common_ptr) &cinfo); + huff_ptr = cinfo.ac_huff_tbl_ptrs[n]; /* huff_ptr is JHUFF_TBL* */ + for (i = 1; i <= 16; i++) { + /* counts[i] is number of Huffman codes of length i bits, i=1..16 */ + huff_ptr->bits[i] = counts[i]; + } + for (i = 0; i < 256; i++) { + /* symbols[] is the list of Huffman symbols, in code-length order */ + huff_ptr->huffval[i] = symbols[i]; + } + +(Note that trying to set cinfo.quant_tbl_ptrs[n] to point directly at a +constant JQUANT_TBL object is not safe. If the incoming file happened to +contain a quantization table definition, your master table would get +overwritten! Instead allocate a working table copy and copy the master table +into it, as illustrated above. Ditto for Huffman tables, of course.) + +You might want to read the tables from a tables-only file, rather than +hard-wiring them into your application. The jpeg_read_header() call is +sufficient to read a tables-only file. You must pass a second parameter of +FALSE to indicate that you do not require an image to be present. Thus, the +typical scenario is + + create JPEG decompression object + set source to tables-only file + jpeg_read_header(&cinfo, FALSE); + set source to abbreviated image file + jpeg_read_header(&cinfo, TRUE); + set decompression parameters + jpeg_start_decompress(&cinfo); + read data... + jpeg_finish_decompress(&cinfo); + +In some cases, you may want to read a file without knowing whether it contains +an image or just tables. In that case, pass FALSE and check the return value +from jpeg_read_header(): it will be JPEG_HEADER_OK if an image was found, +JPEG_HEADER_TABLES_ONLY if only tables were found. (A third return value, +JPEG_SUSPENDED, is possible when using a suspending data source manager.) +Note that jpeg_read_header() will not complain if you read an abbreviated +image for which you haven't loaded the missing tables; the missing-table check +occurs later, in jpeg_start_decompress(). + + +It is possible to read a series of images from a single source file by +repeating the jpeg_read_header() ... jpeg_finish_decompress() sequence, +without releasing/recreating the JPEG object or the data source module. +(If you did reinitialize, any partial bufferload left in the data source +buffer at the end of one image would be discarded, causing you to lose the +start of the next image.) When you use this method, stored tables are +automatically carried forward, so some of the images can be abbreviated images +that depend on tables from earlier images. + +If you intend to write a series of images into a single destination file, +you might want to make a specialized data destination module that doesn't +flush the output buffer at term_destination() time. This would speed things +up by some trifling amount. Of course, you'd need to remember to flush the +buffer after the last image. You can make the later images be abbreviated +ones by passing FALSE to jpeg_start_compress(). + + +Special markers +--------------- + +Some applications may need to insert or extract special data in the JPEG +datastream. The JPEG standard provides marker types "COM" (comment) and +"APP0" through "APP15" (application) to hold application-specific data. +Unfortunately, the use of these markers is not specified by the standard. +COM markers are fairly widely used to hold user-supplied text. The JFIF file +format spec uses APP0 markers with specified initial strings to hold certain +data. Adobe applications use APP14 markers beginning with the string "Adobe" +for miscellaneous data. Other APPn markers are rarely seen, but might +contain almost anything. + +If you wish to store user-supplied text, we recommend you use COM markers +and place readable 7-bit ASCII text in them. Newline conventions are not +standardized --- expect to find LF (Unix style), CR/LF (DOS style), or CR +(Mac style). A robust COM reader should be able to cope with random binary +garbage, including nulls, since some applications generate COM markers +containing non-ASCII junk. (But yours should not be one of them.) + +For program-supplied data, use an APPn marker, and be sure to begin it with an +identifying string so that you can tell whether the marker is actually yours. +It's probably best to avoid using APP0 or APP14 for any private markers. +(NOTE: the upcoming SPIFF standard will use APP8 markers; we recommend you +not use APP8 markers for any private purposes, either.) + +Keep in mind that at most 65533 bytes can be put into one marker, but you +can have as many markers as you like. + +By default, the IJG compression library will write a JFIF APP0 marker if the +selected JPEG colorspace is grayscale or YCbCr, or an Adobe APP14 marker if +the selected colorspace is RGB, CMYK, or YCCK. You can disable this, but +we don't recommend it. The decompression library will recognize JFIF and +Adobe markers and will set the JPEG colorspace properly when one is found. + + +You can write special markers immediately following the datastream header by +calling jpeg_write_marker() after jpeg_start_compress() and before the first +call to jpeg_write_scanlines(). When you do this, the markers appear after +the SOI and the JFIF APP0 and Adobe APP14 markers (if written), but before +all else. Specify the marker type parameter as "JPEG_COM" for COM or +"JPEG_APP0 + n" for APPn. (Actually, jpeg_write_marker will let you write +any marker type, but we don't recommend writing any other kinds of marker.) +For example, to write a user comment string pointed to by comment_text: + jpeg_write_marker(cinfo, JPEG_COM, comment_text, strlen(comment_text)); + +If it's not convenient to store all the marker data in memory at once, +you can instead call jpeg_write_m_header() followed by multiple calls to +jpeg_write_m_byte(). If you do it this way, it's your responsibility to +call jpeg_write_m_byte() exactly the number of times given in the length +parameter to jpeg_write_m_header(). (This method lets you empty the +output buffer partway through a marker, which might be important when +using a suspending data destination module. In any case, if you are using +a suspending destination, you should flush its buffer after inserting +any special markers. See "I/O suspension".) + +Or, if you prefer to synthesize the marker byte sequence yourself, +you can just cram it straight into the data destination module. + +If you are writing JFIF 1.02 extension markers (thumbnail images), don't +forget to set cinfo.JFIF_minor_version = 2 so that the encoder will write the +correct JFIF version number in the JFIF header marker. The library's default +is to write version 1.01, but that's wrong if you insert any 1.02 extension +markers. (We could probably get away with just defaulting to 1.02, but there +used to be broken decoders that would complain about unknown minor version +numbers. To reduce compatibility risks it's safest not to write 1.02 unless +you are actually using 1.02 extensions.) + + +When reading, two methods of handling special markers are available: +1. You can ask the library to save the contents of COM and/or APPn markers +into memory, and then examine them at your leisure afterwards. +2. You can supply your own routine to process COM and/or APPn markers +on-the-fly as they are read. +The first method is simpler to use, especially if you are using a suspending +data source; writing a marker processor that copes with input suspension is +not easy (consider what happens if the marker is longer than your available +input buffer). However, the second method conserves memory since the marker +data need not be kept around after it's been processed. + +For either method, you'd normally set up marker handling after creating a +decompression object and before calling jpeg_read_header(), because the +markers of interest will typically be near the head of the file and so will +be scanned by jpeg_read_header. Once you've established a marker handling +method, it will be used for the life of that decompression object +(potentially many datastreams), unless you change it. Marker handling is +determined separately for COM markers and for each APPn marker code. + + +To save the contents of special markers in memory, call + jpeg_save_markers(cinfo, marker_code, length_limit) +where marker_code is the marker type to save, JPEG_COM or JPEG_APP0+n. +(To arrange to save all the special marker types, you need to call this +routine 17 times, for COM and APP0-APP15.) If the incoming marker is longer +than length_limit data bytes, only length_limit bytes will be saved; this +parameter allows you to avoid chewing up memory when you only need to see the +first few bytes of a potentially large marker. If you want to save all the +data, set length_limit to 0xFFFF; that is enough since marker lengths are only +16 bits. As a special case, setting length_limit to 0 prevents that marker +type from being saved at all. (That is the default behavior, in fact.) + +After jpeg_read_header() completes, you can examine the special markers by +following the cinfo->marker_list pointer chain. All the special markers in +the file appear in this list, in order of their occurrence in the file (but +omitting any markers of types you didn't ask for). Both the original data +length and the saved data length are recorded for each list entry; the latter +will not exceed length_limit for the particular marker type. Note that these +lengths exclude the marker length word, whereas the stored representation +within the JPEG file includes it. (Hence the maximum data length is really +only 65533.) + +It is possible that additional special markers appear in the file beyond the +SOS marker at which jpeg_read_header stops; if so, the marker list will be +extended during reading of the rest of the file. This is not expected to be +common, however. If you are short on memory you may want to reset the length +limit to zero for all marker types after finishing jpeg_read_header, to +ensure that the max_memory_to_use setting cannot be exceeded due to addition +of later markers. + +The marker list remains stored until you call jpeg_finish_decompress or +jpeg_abort, at which point the memory is freed and the list is set to empty. +(jpeg_destroy also releases the storage, of course.) + +Note that the library is internally interested in APP0 and APP14 markers; +if you try to set a small nonzero length limit on these types, the library +will silently force the length up to the minimum it wants. (But you can set +a zero length limit to prevent them from being saved at all.) Also, in a +16-bit environment, the maximum length limit may be constrained to less than +65533 by malloc() limitations. It is therefore best not to assume that the +effective length limit is exactly what you set it to be. + + +If you want to supply your own marker-reading routine, you do it by calling +jpeg_set_marker_processor(). A marker processor routine must have the +signature + boolean jpeg_marker_parser_method (j_decompress_ptr cinfo) +Although the marker code is not explicitly passed, the routine can find it +in cinfo->unread_marker. At the time of call, the marker proper has been +read from the data source module. The processor routine is responsible for +reading the marker length word and the remaining parameter bytes, if any. +Return TRUE to indicate success. (FALSE should be returned only if you are +using a suspending data source and it tells you to suspend. See the standard +marker processors in jdmarker.c for appropriate coding methods if you need to +use a suspending data source.) + +If you override the default APP0 or APP14 processors, it is up to you to +recognize JFIF and Adobe markers if you want colorspace recognition to occur +properly. We recommend copying and extending the default processors if you +want to do that. (A better idea is to save these marker types for later +examination by calling jpeg_save_markers(); that method doesn't interfere +with the library's own processing of these markers.) + +jpeg_set_marker_processor() and jpeg_save_markers() are mutually exclusive +--- if you call one it overrides any previous call to the other, for the +particular marker type specified. + +A simple example of an external COM processor can be found in djpeg.c. +Also, see jpegtran.c for an example of using jpeg_save_markers. + + +Raw (downsampled) image data +---------------------------- + +Some applications need to supply already-downsampled image data to the JPEG +compressor, or to receive raw downsampled data from the decompressor. The +library supports this requirement by allowing the application to write or +read raw data, bypassing the normal preprocessing or postprocessing steps. +The interface is different from the standard one and is somewhat harder to +use. If your interest is merely in bypassing color conversion, we recommend +that you use the standard interface and simply set jpeg_color_space = +in_color_space (or jpeg_color_space = out_color_space for decompression). +The mechanism described in this section is necessary only to supply or +receive downsampled image data, in which not all components have the same +dimensions. + + +To compress raw data, you must supply the data in the colorspace to be used +in the JPEG file (please read the earlier section on Special color spaces) +and downsampled to the sampling factors specified in the JPEG parameters. +You must supply the data in the format used internally by the JPEG library, +namely a JSAMPIMAGE array. This is an array of pointers to two-dimensional +arrays, each of type JSAMPARRAY. Each 2-D array holds the values for one +color component. This structure is necessary since the components are of +different sizes. If the image dimensions are not a multiple of the MCU size, +you must also pad the data correctly (usually, this is done by replicating +the last column and/or row). The data must be padded to a multiple of a DCT +block in each component: that is, each downsampled row must contain a +multiple of 8 valid samples, and there must be a multiple of 8 sample rows +for each component. (For applications such as conversion of digital TV +images, the standard image size is usually a multiple of the DCT block size, +so that no padding need actually be done.) + +The procedure for compression of raw data is basically the same as normal +compression, except that you call jpeg_write_raw_data() in place of +jpeg_write_scanlines(). Before calling jpeg_start_compress(), you must do +the following: + * Set cinfo->raw_data_in to TRUE. (It is set FALSE by jpeg_set_defaults().) + This notifies the library that you will be supplying raw data. + * Ensure jpeg_color_space is correct --- an explicit jpeg_set_colorspace() + call is a good idea. Note that since color conversion is bypassed, + in_color_space is ignored, except that jpeg_set_defaults() uses it to + choose the default jpeg_color_space setting. + * Ensure the sampling factors, cinfo->comp_info[i].h_samp_factor and + cinfo->comp_info[i].v_samp_factor, are correct. Since these indicate the + dimensions of the data you are supplying, it's wise to set them + explicitly, rather than assuming the library's defaults are what you want. + +To pass raw data to the library, call jpeg_write_raw_data() in place of +jpeg_write_scanlines(). The two routines work similarly except that +jpeg_write_raw_data takes a JSAMPIMAGE data array rather than JSAMPARRAY. +The scanlines count passed to and returned from jpeg_write_raw_data is +measured in terms of the component with the largest v_samp_factor. + +jpeg_write_raw_data() processes one MCU row per call, which is to say +v_samp_factor*DCTSIZE sample rows of each component. The passed num_lines +value must be at least max_v_samp_factor*DCTSIZE, and the return value will +be exactly that amount (or possibly some multiple of that amount, in future +library versions). This is true even on the last call at the bottom of the +image; don't forget to pad your data as necessary. + +The required dimensions of the supplied data can be computed for each +component as + cinfo->comp_info[i].width_in_blocks*DCTSIZE samples per row + cinfo->comp_info[i].height_in_blocks*DCTSIZE rows in image +after jpeg_start_compress() has initialized those fields. If the valid data +is smaller than this, it must be padded appropriately. For some sampling +factors and image sizes, additional dummy DCT blocks are inserted to make +the image a multiple of the MCU dimensions. The library creates such dummy +blocks itself; it does not read them from your supplied data. Therefore you +need never pad by more than DCTSIZE samples. An example may help here. +Assume 2h2v downsampling of YCbCr data, that is + cinfo->comp_info[0].h_samp_factor = 2 for Y + cinfo->comp_info[0].v_samp_factor = 2 + cinfo->comp_info[1].h_samp_factor = 1 for Cb + cinfo->comp_info[1].v_samp_factor = 1 + cinfo->comp_info[2].h_samp_factor = 1 for Cr + cinfo->comp_info[2].v_samp_factor = 1 +and suppose that the nominal image dimensions (cinfo->image_width and +cinfo->image_height) are 101x101 pixels. Then jpeg_start_compress() will +compute downsampled_width = 101 and width_in_blocks = 13 for Y, +downsampled_width = 51 and width_in_blocks = 7 for Cb and Cr (and the same +for the height fields). You must pad the Y data to at least 13*8 = 104 +columns and rows, the Cb/Cr data to at least 7*8 = 56 columns and rows. The +MCU height is max_v_samp_factor = 2 DCT rows so you must pass at least 16 +scanlines on each call to jpeg_write_raw_data(), which is to say 16 actual +sample rows of Y and 8 each of Cb and Cr. A total of 7 MCU rows are needed, +so you must pass a total of 7*16 = 112 "scanlines". The last DCT block row +of Y data is dummy, so it doesn't matter what you pass for it in the data +arrays, but the scanlines count must total up to 112 so that all of the Cb +and Cr data gets passed. + +Output suspension is supported with raw-data compression: if the data +destination module suspends, jpeg_write_raw_data() will return 0. +In this case the same data rows must be passed again on the next call. + + +Decompression with raw data output implies bypassing all postprocessing: +you cannot ask for rescaling or color quantization, for instance. More +seriously, you must deal with the color space and sampling factors present in +the incoming file. If your application only handles, say, 2h1v YCbCr data, +you must check for and fail on other color spaces or other sampling factors. +The library will not convert to a different color space for you. + +To obtain raw data output, set cinfo->raw_data_out = TRUE before +jpeg_start_decompress() (it is set FALSE by jpeg_read_header()). Be sure to +verify that the color space and sampling factors are ones you can handle. +Then call jpeg_read_raw_data() in place of jpeg_read_scanlines(). The +decompression process is otherwise the same as usual. + +jpeg_read_raw_data() returns one MCU row per call, and thus you must pass a +buffer of at least max_v_samp_factor*DCTSIZE scanlines (scanline counting is +the same as for raw-data compression). The buffer you pass must be large +enough to hold the actual data plus padding to DCT-block boundaries. As with +compression, any entirely dummy DCT blocks are not processed so you need not +allocate space for them, but the total scanline count includes them. The +above example of computing buffer dimensions for raw-data compression is +equally valid for decompression. + +Input suspension is supported with raw-data decompression: if the data source +module suspends, jpeg_read_raw_data() will return 0. You can also use +buffered-image mode to read raw data in multiple passes. + + +Really raw data: DCT coefficients +--------------------------------- + +It is possible to read or write the contents of a JPEG file as raw DCT +coefficients. This facility is mainly intended for use in lossless +transcoding between different JPEG file formats. Other possible applications +include lossless cropping of a JPEG image, lossless reassembly of a +multi-strip or multi-tile TIFF/JPEG file into a single JPEG datastream, etc. + +To read the contents of a JPEG file as DCT coefficients, open the file and do +jpeg_read_header() as usual. But instead of calling jpeg_start_decompress() +and jpeg_read_scanlines(), call jpeg_read_coefficients(). This will read the +entire image into a set of virtual coefficient-block arrays, one array per +component. The return value is a pointer to an array of virtual-array +descriptors. Each virtual array can be accessed directly using the JPEG +memory manager's access_virt_barray method (see Memory management, below, +and also read structure.doc's discussion of virtual array handling). Or, +for simple transcoding to a different JPEG file format, the array list can +just be handed directly to jpeg_write_coefficients(). + +Each block in the block arrays contains quantized coefficient values in +normal array order (not JPEG zigzag order). The block arrays contain only +DCT blocks containing real data; any entirely-dummy blocks added to fill out +interleaved MCUs at the right or bottom edges of the image are discarded +during reading and are not stored in the block arrays. (The size of each +block array can be determined from the width_in_blocks and height_in_blocks +fields of the component's comp_info entry.) This is also the data format +expected by jpeg_write_coefficients(). + +When you are done using the virtual arrays, call jpeg_finish_decompress() +to release the array storage and return the decompression object to an idle +state; or just call jpeg_destroy() if you don't need to reuse the object. + +If you use a suspending data source, jpeg_read_coefficients() will return +NULL if it is forced to suspend; a non-NULL return value indicates successful +completion. You need not test for a NULL return value when using a +non-suspending data source. + +It is also possible to call jpeg_read_coefficients() to obtain access to the +decoder's coefficient arrays during a normal decode cycle in buffered-image +mode. This frammish might be useful for progressively displaying an incoming +image and then re-encoding it without loss. To do this, decode in buffered- +image mode as discussed previously, then call jpeg_read_coefficients() after +the last jpeg_finish_output() call. The arrays will be available for your use +until you call jpeg_finish_decompress(). + + +To write the contents of a JPEG file as DCT coefficients, you must provide +the DCT coefficients stored in virtual block arrays. You can either pass +block arrays read from an input JPEG file by jpeg_read_coefficients(), or +allocate virtual arrays from the JPEG compression object and fill them +yourself. In either case, jpeg_write_coefficients() is substituted for +jpeg_start_compress() and jpeg_write_scanlines(). Thus the sequence is + * Create compression object + * Set all compression parameters as necessary + * Request virtual arrays if needed + * jpeg_write_coefficients() + * jpeg_finish_compress() + * Destroy or re-use compression object +jpeg_write_coefficients() is passed a pointer to an array of virtual block +array descriptors; the number of arrays is equal to cinfo.num_components. + +The virtual arrays need only have been requested, not realized, before +jpeg_write_coefficients() is called. A side-effect of +jpeg_write_coefficients() is to realize any virtual arrays that have been +requested from the compression object's memory manager. Thus, when obtaining +the virtual arrays from the compression object, you should fill the arrays +after calling jpeg_write_coefficients(). The data is actually written out +when you call jpeg_finish_compress(); jpeg_write_coefficients() only writes +the file header. + +When writing raw DCT coefficients, it is crucial that the JPEG quantization +tables and sampling factors match the way the data was encoded, or the +resulting file will be invalid. For transcoding from an existing JPEG file, +we recommend using jpeg_copy_critical_parameters(). This routine initializes +all the compression parameters to default values (like jpeg_set_defaults()), +then copies the critical information from a source decompression object. +The decompression object should have just been used to read the entire +JPEG input file --- that is, it should be awaiting jpeg_finish_decompress(). + +jpeg_write_coefficients() marks all tables stored in the compression object +as needing to be written to the output file (thus, it acts like +jpeg_start_compress(cinfo, TRUE)). This is for safety's sake, to avoid +emitting abbreviated JPEG files by accident. If you really want to emit an +abbreviated JPEG file, call jpeg_suppress_tables(), or set the tables' +individual sent_table flags, between calling jpeg_write_coefficients() and +jpeg_finish_compress(). + + +Progress monitoring +------------------- + +Some applications may need to regain control from the JPEG library every so +often. The typical use of this feature is to produce a percent-done bar or +other progress display. (For a simple example, see cjpeg.c or djpeg.c.) +Although you do get control back frequently during the data-transferring pass +(the jpeg_read_scanlines or jpeg_write_scanlines loop), any additional passes +will occur inside jpeg_finish_compress or jpeg_start_decompress; those +routines may take a long time to execute, and you don't get control back +until they are done. + +You can define a progress-monitor routine which will be called periodically +by the library. No guarantees are made about how often this call will occur, +so we don't recommend you use it for mouse tracking or anything like that. +At present, a call will occur once per MCU row, scanline, or sample row +group, whichever unit is convenient for the current processing mode; so the +wider the image, the longer the time between calls. During the data +transferring pass, only one call occurs per call of jpeg_read_scanlines or +jpeg_write_scanlines, so don't pass a large number of scanlines at once if +you want fine resolution in the progress count. (If you really need to use +the callback mechanism for time-critical tasks like mouse tracking, you could +insert additional calls inside some of the library's inner loops.) + +To establish a progress-monitor callback, create a struct jpeg_progress_mgr, +fill in its progress_monitor field with a pointer to your callback routine, +and set cinfo->progress to point to the struct. The callback will be called +whenever cinfo->progress is non-NULL. (This pointer is set to NULL by +jpeg_create_compress or jpeg_create_decompress; the library will not change +it thereafter. So if you allocate dynamic storage for the progress struct, +make sure it will live as long as the JPEG object does. Allocating from the +JPEG memory manager with lifetime JPOOL_PERMANENT will work nicely.) You +can use the same callback routine for both compression and decompression. + +The jpeg_progress_mgr struct contains four fields which are set by the library: + long pass_counter; /* work units completed in this pass */ + long pass_limit; /* total number of work units in this pass */ + int completed_passes; /* passes completed so far */ + int total_passes; /* total number of passes expected */ +During any one pass, pass_counter increases from 0 up to (not including) +pass_limit; the step size is usually but not necessarily 1. The pass_limit +value may change from one pass to another. The expected total number of +passes is in total_passes, and the number of passes already completed is in +completed_passes. Thus the fraction of work completed may be estimated as + completed_passes + (pass_counter/pass_limit) + -------------------------------------------- + total_passes +ignoring the fact that the passes may not be equal amounts of work. + +When decompressing, pass_limit can even change within a pass, because it +depends on the number of scans in the JPEG file, which isn't always known in +advance. The computed fraction-of-work-done may jump suddenly (if the library +discovers it has overestimated the number of scans) or even decrease (in the +opposite case). It is not wise to put great faith in the work estimate. + +When using the decompressor's buffered-image mode, the progress monitor work +estimate is likely to be completely unhelpful, because the library has no way +to know how many output passes will be demanded of it. Currently, the library +sets total_passes based on the assumption that there will be one more output +pass if the input file end hasn't yet been read (jpeg_input_complete() isn't +TRUE), but no more output passes if the file end has been reached when the +output pass is started. This means that total_passes will rise as additional +output passes are requested. If you have a way of determining the input file +size, estimating progress based on the fraction of the file that's been read +will probably be more useful than using the library's value. + + +Memory management +----------------- + +This section covers some key facts about the JPEG library's built-in memory +manager. For more info, please read structure.doc's section about the memory +manager, and consult the source code if necessary. + +All memory and temporary file allocation within the library is done via the +memory manager. If necessary, you can replace the "back end" of the memory +manager to control allocation yourself (for example, if you don't want the +library to use malloc() and free() for some reason). + +Some data is allocated "permanently" and will not be freed until the JPEG +object is destroyed. Most data is allocated "per image" and is freed by +jpeg_finish_compress, jpeg_finish_decompress, or jpeg_abort. You can call the +memory manager yourself to allocate structures that will automatically be +freed at these times. Typical code for this is + ptr = (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, size); +Use JPOOL_PERMANENT to get storage that lasts as long as the JPEG object. +Use alloc_large instead of alloc_small for anything bigger than a few Kbytes. +There are also alloc_sarray and alloc_barray routines that automatically +build 2-D sample or block arrays. + +The library's minimum space requirements to process an image depend on the +image's width, but not on its height, because the library ordinarily works +with "strip" buffers that are as wide as the image but just a few rows high. +Some operating modes (eg, two-pass color quantization) require full-image +buffers. Such buffers are treated as "virtual arrays": only the current strip +need be in memory, and the rest can be swapped out to a temporary file. + +If you use the simplest memory manager back end (jmemnobs.c), then no +temporary files are used; virtual arrays are simply malloc()'d. Images bigger +than memory can be processed only if your system supports virtual memory. +The other memory manager back ends support temporary files of various flavors +and thus work in machines without virtual memory. They may also be useful on +Unix machines if you need to process images that exceed available swap space. + +When using temporary files, the library will make the in-memory buffers for +its virtual arrays just big enough to stay within a "maximum memory" setting. +Your application can set this limit by setting cinfo->mem->max_memory_to_use +after creating the JPEG object. (Of course, there is still a minimum size for +the buffers, so the max-memory setting is effective only if it is bigger than +the minimum space needed.) If you allocate any large structures yourself, you +must allocate them before jpeg_start_compress() or jpeg_start_decompress() in +order to have them counted against the max memory limit. Also keep in mind +that space allocated with alloc_small() is ignored, on the assumption that +it's too small to be worth worrying about; so a reasonable safety margin +should be left when setting max_memory_to_use. + +If you use the jmemname.c or jmemdos.c memory manager back end, it is +important to clean up the JPEG object properly to ensure that the temporary +files get deleted. (This is especially crucial with jmemdos.c, where the +"temporary files" may be extended-memory segments; if they are not freed, +DOS will require a reboot to recover the memory.) Thus, with these memory +managers, it's a good idea to provide a signal handler that will trap any +early exit from your program. The handler should call either jpeg_abort() +or jpeg_destroy() for any active JPEG objects. A handler is not needed with +jmemnobs.c, and shouldn't be necessary with jmemansi.c or jmemmac.c either, +since the C library is supposed to take care of deleting files made with +tmpfile(). + + +Memory usage +------------ + +Working memory requirements while performing compression or decompression +depend on image dimensions, image characteristics (such as colorspace and +JPEG process), and operating mode (application-selected options). + +As of v6b, the decompressor requires: + 1. About 24K in more-or-less-fixed-size data. This varies a bit depending + on operating mode and image characteristics (particularly color vs. + grayscale), but it doesn't depend on image dimensions. + 2. Strip buffers (of size proportional to the image width) for IDCT and + upsampling results. The worst case for commonly used sampling factors + is about 34 bytes * width in pixels for a color image. A grayscale image + only needs about 8 bytes per pixel column. + 3. A full-image DCT coefficient buffer is needed to decode a multi-scan JPEG + file (including progressive JPEGs), or whenever you select buffered-image + mode. This takes 2 bytes/coefficient. At typical 2x2 sampling, that's + 3 bytes per pixel for a color image. Worst case (1x1 sampling) requires + 6 bytes/pixel. For grayscale, figure 2 bytes/pixel. + 4. To perform 2-pass color quantization, the decompressor also needs a + 128K color lookup table and a full-image pixel buffer (3 bytes/pixel). +This does not count any memory allocated by the application, such as a +buffer to hold the final output image. + +The above figures are valid for 8-bit JPEG data precision and a machine with +32-bit ints. For 12-bit JPEG data, double the size of the strip buffers and +quantization pixel buffer. The "fixed-size" data will be somewhat smaller +with 16-bit ints, larger with 64-bit ints. Also, CMYK or other unusual +color spaces will require different amounts of space. + +The full-image coefficient and pixel buffers, if needed at all, do not +have to be fully RAM resident; you can have the library use temporary +files instead when the total memory usage would exceed a limit you set. +(But if your OS supports virtual memory, it's probably better to just use +jmemnobs and let the OS do the swapping.) + +The compressor's memory requirements are similar, except that it has no need +for color quantization. Also, it needs a full-image DCT coefficient buffer +if Huffman-table optimization is asked for, even if progressive mode is not +requested. + +If you need more detailed information about memory usage in a particular +situation, you can enable the MEM_STATS code in jmemmgr.c. + + +Library compile-time options +---------------------------- + +A number of compile-time options are available by modifying jmorecfg.h. + +The JPEG standard provides for both the baseline 8-bit DCT process and +a 12-bit DCT process. The IJG code supports 12-bit lossy JPEG if you define +BITS_IN_JSAMPLE as 12 rather than 8. Note that this causes JSAMPLE to be +larger than a char, so it affects the surrounding application's image data. +The sample applications cjpeg and djpeg can support 12-bit mode only for PPM +and GIF file formats; you must disable the other file formats to compile a +12-bit cjpeg or djpeg. (install.doc has more information about that.) +At present, a 12-bit library can handle *only* 12-bit images, not both +precisions. (If you need to include both 8- and 12-bit libraries in a single +application, you could probably do it by defining NEED_SHORT_EXTERNAL_NAMES +for just one of the copies. You'd have to access the 8-bit and 12-bit copies +from separate application source files. This is untested ... if you try it, +we'd like to hear whether it works!) + +Note that a 12-bit library always compresses in Huffman optimization mode, +in order to generate valid Huffman tables. This is necessary because our +default Huffman tables only cover 8-bit data. If you need to output 12-bit +files in one pass, you'll have to supply suitable default Huffman tables. +You may also want to supply your own DCT quantization tables; the existing +quality-scaling code has been developed for 8-bit use, and probably doesn't +generate especially good tables for 12-bit. + +The maximum number of components (color channels) in the image is determined +by MAX_COMPONENTS. The JPEG standard allows up to 255 components, but we +expect that few applications will need more than four or so. + +On machines with unusual data type sizes, you may be able to improve +performance or reduce memory space by tweaking the various typedefs in +jmorecfg.h. In particular, on some RISC CPUs, access to arrays of "short"s +is quite slow; consider trading memory for speed by making JCOEF, INT16, and +UINT16 be "int" or "unsigned int". UINT8 is also a candidate to become int. +You probably don't want to make JSAMPLE be int unless you have lots of memory +to burn. + +You can reduce the size of the library by compiling out various optional +functions. To do this, undefine xxx_SUPPORTED symbols as necessary. + +You can also save a few K by not having text error messages in the library; +the standard error message table occupies about 5Kb. This is particularly +reasonable for embedded applications where there's no good way to display +a message anyway. To do this, remove the creation of the message table +(jpeg_std_message_table[]) from jerror.c, and alter format_message to do +something reasonable without it. You could output the numeric value of the +message code number, for example. If you do this, you can also save a couple +more K by modifying the TRACEMSn() macros in jerror.h to expand to nothing; +you don't need trace capability anyway, right? + + +Portability considerations +-------------------------- + +The JPEG library has been written to be extremely portable; the sample +applications cjpeg and djpeg are slightly less so. This section summarizes +the design goals in this area. (If you encounter any bugs that cause the +library to be less portable than is claimed here, we'd appreciate hearing +about them.) + +The code works fine on ANSI C, C++, and pre-ANSI C compilers, using any of +the popular system include file setups, and some not-so-popular ones too. +See install.doc for configuration procedures. + +The code is not dependent on the exact sizes of the C data types. As +distributed, we make the assumptions that + char is at least 8 bits wide + short is at least 16 bits wide + int is at least 16 bits wide + long is at least 32 bits wide +(These are the minimum requirements of the ANSI C standard.) Wider types will +work fine, although memory may be used inefficiently if char is much larger +than 8 bits or short is much bigger than 16 bits. The code should work +equally well with 16- or 32-bit ints. + +In a system where these assumptions are not met, you may be able to make the +code work by modifying the typedefs in jmorecfg.h. However, you will probably +have difficulty if int is less than 16 bits wide, since references to plain +int abound in the code. + +char can be either signed or unsigned, although the code runs faster if an +unsigned char type is available. If char is wider than 8 bits, you will need +to redefine JOCTET and/or provide custom data source/destination managers so +that JOCTET represents exactly 8 bits of data on external storage. + +The JPEG library proper does not assume ASCII representation of characters. +But some of the image file I/O modules in cjpeg/djpeg do have ASCII +dependencies in file-header manipulation; so does cjpeg's select_file_type() +routine. + +The JPEG library does not rely heavily on the C library. In particular, C +stdio is used only by the data source/destination modules and the error +handler, all of which are application-replaceable. (cjpeg/djpeg are more +heavily dependent on stdio.) malloc and free are called only from the memory +manager "back end" module, so you can use a different memory allocator by +replacing that one file. + +The code generally assumes that C names must be unique in the first 15 +characters. However, global function names can be made unique in the +first 6 characters by defining NEED_SHORT_EXTERNAL_NAMES. + +More info about porting the code may be gleaned by reading jconfig.doc, +jmorecfg.h, and jinclude.h. + + +Notes for MS-DOS implementors +----------------------------- + +The IJG code is designed to work efficiently in 80x86 "small" or "medium" +memory models (i.e., data pointers are 16 bits unless explicitly declared +"far"; code pointers can be either size). You may be able to use small +model to compile cjpeg or djpeg by itself, but you will probably have to use +medium model for any larger application. This won't make much difference in +performance. You *will* take a noticeable performance hit if you use a +large-data memory model (perhaps 10%-25%), and you should avoid "huge" model +if at all possible. + +The JPEG library typically needs 2Kb-3Kb of stack space. It will also +malloc about 20K-30K of near heap space while executing (and lots of far +heap, but that doesn't count in this calculation). This figure will vary +depending on selected operating mode, and to a lesser extent on image size. +There is also about 5Kb-6Kb of constant data which will be allocated in the +near data segment (about 4Kb of this is the error message table). +Thus you have perhaps 20K available for other modules' static data and near +heap space before you need to go to a larger memory model. The C library's +static data will account for several K of this, but that still leaves a good +deal for your needs. (If you are tight on space, you could reduce the sizes +of the I/O buffers allocated by jdatasrc.c and jdatadst.c, say from 4K to +1K. Another possibility is to move the error message table to far memory; +this should be doable with only localized hacking on jerror.c.) + +About 2K of the near heap space is "permanent" memory that will not be +released until you destroy the JPEG object. This is only an issue if you +save a JPEG object between compression or decompression operations. + +Far data space may also be a tight resource when you are dealing with large +images. The most memory-intensive case is decompression with two-pass color +quantization, or single-pass quantization to an externally supplied color +map. This requires a 128Kb color lookup table plus strip buffers amounting +to about 40 bytes per column for typical sampling ratios (eg, about 25600 +bytes for a 640-pixel-wide image). You may not be able to process wide +images if you have large data structures of your own. + +Of course, all of these concerns vanish if you use a 32-bit flat-memory-model +compiler, such as DJGPP or Watcom C. We highly recommend flat model if you +can use it; the JPEG library is significantly faster in flat model. diff --git a/mk4/modimage/jpeg-6b/ltconfig b/mk4/modimage/jpeg-6b/ltconfig new file mode 100644 index 0000000..2347e69 --- /dev/null +++ b/mk4/modimage/jpeg-6b/ltconfig @@ -0,0 +1,1512 @@ +#! /bin/sh + +# ltconfig - Create a system-specific libtool. +# Copyright (C) 1996-1998 Free Software Foundation, Inc. +# Gordon Matzigkeit , 1996 +# +# 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. + +# A lot of this script is taken from autoconf-2.10. + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +if test "${CDPATH+set}" = set; then CDPATH=; export CDPATH; fi + +echo=echo +if test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then : +else + # The Solaris and AIX default echo program unquotes backslashes. + # This makes it impossible to quote backslashes using + # echo "$something" | sed 's/\\/\\\\/g' + # So, we emulate echo with printf '%s\n' + echo="printf %s\\n" + if test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then : + else + # Oops. We have no working printf. Try to find a not-so-buggy echo. + echo=echo + IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}:" + for dir in $PATH /usr/ucb; do + if test -f $dir/echo && test "X`$dir/echo '\t'`" = 'X\t'; then + echo="$dir/echo" + break + fi + done + IFS="$save_ifs" + fi +fi + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='sed -e s/^X//' +sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g' + +# The name of this program. +progname=`$echo "X$0" | $Xsed -e 's%^.*/%%'` + +# Constants: +PROGRAM=ltconfig +PACKAGE=libtool +VERSION=1.2 +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.c 1>&5' +ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.c $LIBS 1>&5' +rm="rm -f" + +help="Try \`$progname --help' for more information." + +# Global variables: +can_build_shared=yes +enable_shared=yes +# All known linkers require a `.a' archive for static linking. +enable_static=yes +ltmain= +silent= +srcdir= +ac_config_guess= +ac_config_sub= +host= +nonopt= +verify_host=yes +with_gcc=no +with_gnu_ld=no + +old_AR="$AR" +old_CC="$CC" +old_CFLAGS="$CFLAGS" +old_CPPFLAGS="$CPPFLAGS" +old_LD="$LD" +old_LN_S="$LN_S" +old_NM="$NM" +old_RANLIB="$RANLIB" + +# Parse the command line options. +args= +prev= +for option +do + case "$option" in + -*=*) optarg=`echo "$option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) optarg= ;; + esac + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + eval "$prev=\$option" + prev= + continue + fi + + case "$option" in + --help) cat <&2 + echo "$help" 1>&2 + exit 1 + ;; + + *) + if test -z "$ltmain"; then + ltmain="$option" + elif test -z "$host"; then +# This generates an unnecessary warning for sparc-sun-solaris4.1.3_U1 +# if test -n "`echo $option| sed 's/[-a-z0-9.]//g'`"; then +# echo "$progname: warning \`$option' is not a valid host type" 1>&2 +# fi + host="$option" + else + echo "$progname: too many arguments" 1>&2 + echo "$help" 1>&2 + exit 1 + fi ;; + esac +done + +if test -z "$ltmain"; then + echo "$progname: you must specify a LTMAIN file" 1>&2 + echo "$help" 1>&2 + exit 1 +fi + +if test -f "$ltmain"; then : +else + echo "$progname: \`$ltmain' does not exist" 1>&2 + echo "$help" 1>&2 + exit 1 +fi + +# Quote any args containing shell metacharacters. +ltconfig_args= +for arg +do + case "$arg" in + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) + ltconfig_args="$ltconfig_args '$arg'" ;; + *) ltconfig_args="$ltconfig_args $arg" ;; + esac +done + +# A relevant subset of AC_INIT. + +# File descriptor usage: +# 0 standard input +# 1 file creation +# 2 errors and warnings +# 3 some systems may open it to /dev/tty +# 4 used on the Kubota Titan +# 5 compiler messages saved in config.log +# 6 checking for... messages and results +if test "$silent" = yes; then + exec 6>/dev/null +else + exec 6>&1 +fi +exec 5>>./config.log + +# NLS nuisances. +# Only set LANG and LC_ALL to C if already set. +# These must not be set unconditionally because not all systems understand +# e.g. LANG=C (notably SCO). +if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi +if test "${LANG+set}" = set; then LANG=C; export LANG; fi + +if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then + # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. + if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then + ac_n= ac_c=' +' ac_t=' ' + else + ac_n=-n ac_c= ac_t= + fi +else + ac_n= ac_c='\c' ac_t= +fi + +if test -z "$srcdir"; then + # Assume the source directory is the same one as the path to ltmain.sh. + srcdir=`$echo "$ltmain" | $Xsed -e 's%/[^/]*$%%'` + test "$srcdir" = "$ltmain" && srcdir=. +fi + +trap "$rm conftest*; exit 1" 1 2 15 +if test "$verify_host" = yes; then + # Check for config.guess and config.sub. + ac_aux_dir= + for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do + if test -f $ac_dir/config.guess; then + ac_aux_dir=$ac_dir + break + fi + done + if test -z "$ac_aux_dir"; then + echo "$progname: cannot find config.guess in $srcdir $srcdir/.. $srcdir/../.." 1>&2 + echo "$help" 1>&2 + exit 1 + fi + ac_config_guess=$ac_aux_dir/config.guess + ac_config_sub=$ac_aux_dir/config.sub + + # Make sure we can run config.sub. + if $ac_config_sub sun4 >/dev/null 2>&1; then : + else + echo "$progname: cannot run $ac_config_sub" 1>&2 + echo "$help" 1>&2 + exit 1 + fi + + echo $ac_n "checking host system type""... $ac_c" 1>&6 + + host_alias=$host + case "$host_alias" in + "") + if host_alias=`$ac_config_guess`; then : + else + echo "$progname: cannot guess host type; you must specify one" 1>&2 + echo "$help" 1>&2 + exit 1 + fi ;; + esac + host=`$ac_config_sub $host_alias` + echo "$ac_t$host" 1>&6 + + # Make sure the host verified. + test -z "$host" && exit 1 + +elif test -z "$host"; then + echo "$progname: you must specify a host type if you use \`--no-verify'" 1>&2 + echo "$help" 1>&2 + exit 1 +else + host_alias=$host +fi + +# Transform linux* to *-*-linux-gnu*, to support old configure scripts. +case "$host_os" in +linux-gnu*) ;; +linux*) host=`echo $host | sed 's/^\(.*-.*-linux\)\(.*\)$/\1-gnu\2/'` +esac + +host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` + +case "$host_os" in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "${COLLECT_NAMES+set}" != set; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR cru $oldlib$oldobjs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +# Set a sane default for `AR'. +test -z "$AR" && AR=ar + +# If RANLIB is not set, then run the test. +if test "${RANLIB+set}" != "set"; then + result=no + + echo $ac_n "checking for ranlib... $ac_c" 1>&6 + IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}:" + for dir in $PATH; do + test -z "$dir" && dir=. + if test -f $dir/ranlib; then + RANLIB="ranlib" + result="ranlib" + break + fi + done + IFS="$save_ifs" + + echo "$ac_t$result" 1>&6 +fi + +if test -n "$RANLIB"; then + old_archive_cmds="$old_archive_cmds;\$RANLIB \$oldlib" + old_postinstall_cmds="\$RANLIB \$oldlib;$old_postinstall_cmds" +fi + +# Check to see if we are using GCC. +if test "$with_gcc" != yes || test -z "$CC"; then + # If CC is not set, then try to find GCC or a usable CC. + if test -z "$CC"; then + echo $ac_n "checking for gcc... $ac_c" 1>&6 + IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}:" + for dir in $PATH; do + IFS="$save_ifs" + test -z "$dir" && dir=. + if test -f $dir/gcc; then + CC="gcc" + break + fi + done + IFS="$save_ifs" + + if test -n "$CC"; then + echo "$ac_t$CC" 1>&6 + else + echo "$ac_t"no 1>&6 + fi + fi + + # Not "gcc", so try "cc", rejecting "/usr/ucb/cc". + if test -z "$CC"; then + echo $ac_n "checking for cc... $ac_c" 1>&6 + IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}:" + cc_rejected=no + for dir in $PATH; do + test -z "$dir" && dir=. + if test -f $dir/cc; then + if test "$dir/cc" = "/usr/ucb/cc"; then + cc_rejected=yes + continue + fi + CC="cc" + break + fi + done + IFS="$save_ifs" + if test $cc_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $CC + shift + if test $# -gt 0; then + # We chose a different compiler from the bogus one. + # However, it has the same name, so the bogon will be chosen + # first if we set CC to just the name; use the full file name. + shift + set dummy "$dir/cc" "$@" + shift + CC="$@" + fi + fi + + if test -n "$CC"; then + echo "$ac_t$CC" 1>&6 + else + echo "$ac_t"no 1>&6 + fi + + if test -z "$CC"; then + echo "$progname: error: no acceptable cc found in \$PATH" 1>&2 + exit 1 + fi + fi + + # Now see if the compiler is really GCC. + with_gcc=no + echo $ac_n "checking whether we are using GNU C... $ac_c" 1>&6 + echo "$progname:424: checking whether we are using GNU C" >&5 + + $rm conftest.c + cat > conftest.c <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + with_gcc=yes + fi + $rm conftest.c + echo "$ac_t$with_gcc" 1>&6 +fi + +# Allow CC to be a program name with arguments. +set dummy $CC +compiler="$2" + +echo $ac_n "checking for $compiler option to produce PIC... $ac_c" 1>&6 +pic_flag= +special_shlib_compile_flags= +wl= +link_static_flag= +no_builtin_flag= + +if test "$with_gcc" = yes; then + wl='-Wl,' + link_static_flag='-static' + no_builtin_flag=' -fno-builtin' + + case "$host_os" in + aix3* | aix4* | irix5* | irix6* | osf3* | osf4*) + # PIC is the default for these OSes. + ;; + os2*) + # We can build DLLs from non-PIC. + ;; + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + pic_flag='-m68020 -resident32 -malways-restore-a4' + ;; + *) + pic_flag='-fPIC' + ;; + esac +else + # PORTME Check for PIC flags for the system compiler. + case "$host_os" in + aix3* | aix4*) + # All AIX code is PIC. + link_static_flag='-bnso -bI:/lib/syscalls.exp' + ;; + + hpux9* | hpux10*) + # Is there a better link_static_flag that works with the bundled CC? + wl='-Wl,' + link_static_flag="${wl}-a ${wl}archive" + pic_flag='+Z' + ;; + + irix5* | irix6*) + wl='-Wl,' + link_static_flag='-non_shared' + # PIC (with -KPIC) is the default. + ;; + + os2*) + # We can build DLLs from non-PIC. + ;; + + osf3* | osf4*) + # All OSF/1 code is PIC. + wl='-Wl,' + link_static_flag='-non_shared' + ;; + + sco3.2v5*) + pic_flag='-Kpic' + link_static_flag='-dn' + special_shlib_compile_flags='-belf' + ;; + + solaris2*) + pic_flag='-KPIC' + link_static_flag='-Bstatic' + wl='-Wl,' + ;; + + sunos4*) + pic_flag='-PIC' + link_static_flag='-Bstatic' + wl='-Qoption ld ' + ;; + + sysv4.2uw2*) + pic_flag='-KPIC' + link_static_flag='-Bstatic' + wl='-Wl,' + ;; + + uts4*) + pic_flag='-pic' + link_static_flag='-Bstatic' + ;; + + *) + can_build_shared=no + ;; + esac +fi + +if test -n "$pic_flag"; then + echo "$ac_t$pic_flag" 1>&6 + + # Check to make sure the pic_flag actually works. + echo $ac_n "checking if $compiler PIC flag $pic_flag works... $ac_c" 1>&6 + $rm conftest* + echo > conftest.c + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $pic_flag -DPIC" + echo "$progname:547: checking if $compiler PIC flag $pic_flag works" >&5 + if { (eval echo $progname:548: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>conftest.err; } && test -s conftest.o; then + # Append any warnings to the config.log. + cat conftest.err 1>&5 + + # On HP-UX, both CC and GCC only warn that PIC is supported... then they + # create non-PIC objects. So, if there were any warnings, we assume that + # PIC is not supported. + if test -s conftest.err; then + echo "$ac_t"no 1>&6 + can_build_shared=no + pic_flag= + else + echo "$ac_t"yes 1>&6 + pic_flag=" $pic_flag" + fi + else + # Append any errors to the config.log. + cat conftest.err 1>&5 + can_build_shared=no + pic_flag= + echo "$ac_t"no 1>&6 + fi + CFLAGS="$save_CFLAGS" + $rm conftest* +else + echo "$ac_t"none 1>&6 +fi + +# Check for any special shared library compilation flags. +if test -n "$special_shlib_compile_flags"; then + echo "$progname: warning: \`$CC' requires \`$special_shlib_compile_flags' to build shared libraries" 1>&2 + if echo "$old_CC $old_CFLAGS " | egrep -e "[ ]$special_shlib_compile_flags[ ]" >/dev/null; then : + else + echo "$progname: add \`$special_shlib_compile_flags' to the CC or CFLAGS env variable and reconfigure" 1>&2 + can_build_shared=no + fi +fi + +echo $ac_n "checking if $compiler static flag $link_static_flag works... $ac_c" 1>&6 +$rm conftest* +echo 'main(){return(0);}' > conftest.c +save_LDFLAGS="$LDFLAGS" +LDFLAGS="$LDFLAGS $link_static_flag" +echo "$progname:591: checking if $compiler static flag $link_static_flag works" >&5 +if { (eval echo $progname:592: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + echo "$ac_t$link_static_flag" 1>&6 +else + echo "$ac_t"none 1>&6 + link_static_flag= +fi +LDFLAGS="$save_LDFLAGS" +$rm conftest* + +if test -z "$LN_S"; then + # Check to see if we can use ln -s, or we need hard links. + echo $ac_n "checking whether ln -s works... $ac_c" 1>&6 + $rm conftestdata + if ln -s X conftestdata 2>/dev/null; then + $rm conftestdata + LN_S="ln -s" + else + LN_S=ln + fi + if test "$LN_S" = "ln -s"; then + echo "$ac_t"yes 1>&6 + else + echo "$ac_t"no 1>&6 + fi +fi + +# Make sure LD is an absolute path. +if test -z "$LD"; then + ac_prog=ld + if test "$with_gcc" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + echo $ac_n "checking for ld used by GCC... $ac_c" 1>&6 + echo "$progname:624: checking for ld used by GCC" >&5 + ac_prog=`($CC -print-prog-name=ld) 2>&5` + case "$ac_prog" in + # Accept absolute paths. + /* | [A-Za-z]:\\*) + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we are not using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac + elif test "$with_gnu_ld" = yes; then + echo $ac_n "checking for GNU ld... $ac_c" 1>&6 + echo "$progname:642: checking for GNU ld" >&5 + else + echo $ac_n "checking for non-GNU ld""... $ac_c" 1>&6 + echo "$progname:645: checking for non-GNU ld" >&5 + fi + + if test -z "$LD"; then + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog"; then + LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + if "$LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then + test "$with_gnu_ld" != no && break + else + test "$with_gnu_ld" != yes && break + fi + fi + done + IFS="$ac_save_ifs" + fi + + if test -n "$LD"; then + echo "$ac_t$LD" 1>&6 + else + echo "$ac_t"no 1>&6 + fi + + if test -z "$LD"; then + echo "$progname: error: no acceptable ld found in \$PATH" 1>&2 + exit 1 + fi +fi + +# Check to see if it really is or is not GNU ld. +echo $ac_n "checking if the linker ($LD) is GNU ld... $ac_c" 1>&6 +# I'd rather use --version here, but apparently some GNU ld's only accept -v. +if $LD -v 2>&1 &5; then + with_gnu_ld=yes +else + with_gnu_ld=no +fi +echo "$ac_t$with_gnu_ld" 1>&6 + +# See if the linker supports building shared libraries. +echo $ac_n "checking whether the linker ($LD) supports shared libraries... $ac_c" 1>&6 + +allow_undefined_flag= +no_undefined_flag= +archive_cmds= +old_archive_from_new_cmds= +export_dynamic_flag_spec= +hardcode_libdir_flag_spec= +hardcode_libdir_separator= +hardcode_direct=no +hardcode_minus_L=no +hardcode_shlibpath_var=unsupported +runpath_var= + +case "$host_os" in +amigaos* | sunos4*) + # On these operating systems, we should treat GNU ld like the system ld. + gnu_ld_acts_native=yes + ;; +*) + gnu_ld_acts_native=no + ;; +esac + +ld_shlibs=yes +if test "$with_gnu_ld" = yes && test "$gnu_ld_acts_native" != yes; then + + # See if GNU ld supports shared libraries. + if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared ${wl}-soname $wl$soname -o $lib$libobjs' + runpath_var=LD_RUN_PATH + ld_shlibs=yes + else + ld_shlibs=no + fi + + if test "$ld_shlibs" = yes; then + hardcode_libdir_flag_spec='${wl}--rpath ${wl}$libdir' + export_dynamic_flag_spec='${wl}--export-dynamic' + fi +else + # PORTME fill in a description of your system's linker (not GNU ld) + case "$host_os" in + aix3*) + allow_undefined_flag=unsupported + archive_cmds='$NM$libobjs | $global_symbol_pipe | sed '\''s/.* //'\'' > $lib.exp;$LD -o $objdir/$soname$libobjs -bE:$lib.exp -T512 -H512 -bM:SRE;$AR cru $lib $objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L=yes + if test "$with_gcc" = yes && test -z "$link_static_flag"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct=unsupported + fi + ;; + + aix4*) + allow_undefined_flag=unsupported + archive_cmds='$NM$libobjs | $global_symbol_pipe | sed '\''s/.* //'\'' > $lib.exp;$CC -o $objdir/$soname$libobjs ${wl}-bE:$lib.exp ${wl}-bM:SRE ${wl}-bnoentry;$AR cru $lib $objdir/$soname' + hardcode_direct=yes + hardcode_minus_L=yes + ;; + + amigaos*) + archive_cmds='$rm $objdir/a2ixlibrary.data;$echo "#define NAME $libname" > $objdir/a2ixlibrary.data;$echo "#define LIBRARY_ID 1" >> $objdir/a2ixlibrary.data;$echo "#define VERSION $major" >> $objdir/a2ixlibrary.data;$echo "#define REVISION $revision" >> $objdir/a2ixlibrary.data;$AR cru $lib$libobjs;$RANLIB $lib;(cd $objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + archive_cmds='$LD -Bshareable -o $lib$libobjs /usr/lib/c++rt0.o' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + archive_cmds='$LD -Bshareable -o $lib$libobjs' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + # FreeBSD 3, at last, uses gcc -shared to do shared libraries. + freebsd3*) + archive_cmds='$CC -shared -o $lib$libobjs' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + hpux9*) + archive_cmds='$rm $objdir/$soname;$LD -b +s +b $install_libdir -o $objdir/$soname$libobjs;mv $objdir/$soname $lib' + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + export_dynamic_flag_spec='${wl}-E' + ;; + + hpux10*) + archive_cmds='$LD -b +h $soname +s +b $install_libdir -o $lib$libobjs' + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + export_dynamic_flag_spec='${wl}-E' + ;; + + irix5* | irix6*) + archive_cmds='$LD -shared -o $lib -soname $soname -set_version $verstring$libobjs' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + ;; + + netbsd*) + # Tested with NetBSD 1.2 ld + archive_cmds='$LD -Bshareable -o $lib$libobjs' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + openbsd*) + archive_cmds='$LD -Bshareable -o $lib$libobjs' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + allow_undefined_flag=unsupported + archive_cmds='$echo "LIBRARY $libname INITINSTANCE" > $objdir/$libname.def;$echo "DESCRIPTION \"$libname\"" >> $objdir/$libname.def;$echo DATA >> $objdir/$libname.def;$echo " SINGLE NONSHARED" >> $objdir/$libname.def;$echo EXPORTS >> $objdir/$libname.def;emxexp$libobjs >> $objdir/$libname.def;$CC -Zdll -Zcrtdll -o $lib$libobjs $objdir/$libname.def' + old_archive_from_new_cmds='emximp -o $objdir/$libname.a $objdir/$libname.def' + ;; + + osf3* | osf4*) + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$LD -shared${allow_undefined_flag} -o $lib -soname $soname -set_version $verstring$libobjs$deplibs' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + + sco3.2v5*) + archive_cmds='$LD -G -o $lib$libobjs' + hardcode_direct=yes + ;; + + solaris2*) + no_undefined_flag=' -z text' + archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib$libobjs' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_shlibpath_var=no + + # Solaris 2 before 2.5 hardcodes -L paths. + case "$host_os" in + solaris2.[0-4]*) + hardcode_minus_L=yes + ;; + esac + ;; + + sunos4*) + if test "$with_gcc" = yes; then + archive_cmds='$CC -shared -o $lib$libobjs' + else + archive_cmds='$LD -assert pure-text -Bstatic -o $lib$libobjs' + fi + + if test "$with_gnu_ld" = yes; then + export_dynamic_flag_spec='${wl}-export-dynamic' + fi + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + uts4*) + archive_cmds='$LD -G -h $soname -o $lib$libobjs' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=no + hardcode_minus_L=no + hardcode_shlibpath_var=no + ;; + + *) + ld_shlibs=no + can_build_shared=no + ;; + esac +fi +echo "$ac_t$ld_shlibs" 1>&6 + +if test -z "$NM"; then + echo $ac_n "checking for BSD-compatible nm... $ac_c" 1>&6 + case "$NM" in + /* | [A-Za-z]:\\*) ;; # Let the user override the test with a path. + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in /usr/ucb /usr/ccs/bin $PATH /bin; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/nm; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + if ($ac_dir/nm -B /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then + NM="$ac_dir/nm -B" + elif ($ac_dir/nm -p /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then + NM="$ac_dir/nm -p" + else + NM="$ac_dir/nm" + fi + break + fi + done + IFS="$ac_save_ifs" + test -z "$NM" && NM=nm + ;; + esac + echo "$ac_t$NM" 1>&6 +fi + +# Check for command to grab the raw symbol name followed by C symbol from nm. +echo $ac_n "checking command to parse $NM output... $ac_c" 1>&6 + +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[BCDEGRSTU]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([_A-Za-z][_A-Za-z0-9]*\)' + +# Transform the above into a raw symbol and a C symbol. +symxfrm='\1 \1' + +# Define system-specific variables. +case "$host_os" in +aix*) + symcode='[BCDTU]' + ;; +irix*) + # Cannot use undefined symbols on IRIX because inlined functions mess us up. + symcode='[BCDEGRST]' + ;; +solaris2*) + symcode='[BDTU]' + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +if $NM -V 2>&1 | egrep '(GNU|with BFD)' > /dev/null; then + symcode='[ABCDGISTUW]' +fi + +# Write the raw and C identifiers. +global_symbol_pipe="sed -n -e 's/^.* $symcode $sympat$/$symxfrm/p'" + +# Check to see that the pipe works correctly. +pipe_works=no +$rm conftest* +cat > conftest.c <&5 +if { (eval echo $progname:972: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; } && test -s conftest.o; then + # Now try to grab the symbols. + nlist=conftest.nm + if { echo "$progname:975: eval \"$NM conftest.o | $global_symbol_pipe > $nlist\"" >&5; eval "$NM conftest.o | $global_symbol_pipe > $nlist 2>&5"; } && test -s "$nlist"; then + + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + wcout=`wc "$nlist" 2>/dev/null` + count=`$echo "X$wcout" | $Xsed -e 's/^[ ]*\([0-9][0-9]*\).*$/\1/'` + (test "$count" -ge 0) 2>/dev/null || count=-1 + else + rm -f "$nlist"T + count=-1 + fi + + # Make sure that we snagged all the symbols we need. + if egrep ' nm_test_var$' "$nlist" >/dev/null; then + if egrep ' nm_test_func$' "$nlist" >/dev/null; then + cat < conftest.c +#ifdef __cplusplus +extern "C" { +#endif + +EOF + # Now generate the symbol file. + sed 's/^.* \(.*\)$/extern char \1;/' < "$nlist" >> conftest.c + + cat <> conftest.c +#if defined (__STDC__) && __STDC__ +# define __ptr_t void * +#else +# define __ptr_t char * +#endif + +/* The number of symbols in dld_preloaded_symbols, -1 if unsorted. */ +int dld_preloaded_symbol_count = $count; + +/* The mapping between symbol names and symbols. */ +struct { + char *name; + __ptr_t address; +} +dld_preloaded_symbols[] = +{ +EOF + sed 's/^\(.*\) \(.*\)$/ {"\1", (__ptr_t) \&\2},/' < "$nlist" >> conftest.c + cat <<\EOF >> conftest.c + {0, (__ptr_t) 0} +}; + +#ifdef __cplusplus +} +#endif +EOF + # Now try linking the two files. + mv conftest.o conftestm.o + save_LIBS="$LIBS" + save_CFLAGS="$CFLAGS" + LIBS='conftestm.o' + CFLAGS="$CFLAGS$no_builtin_flag" + if { (eval echo $progname:1033: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + pipe_works=yes + else + echo "$progname: failed program was:" >&5 + cat conftest.c >&5 + fi + LIBS="$save_LIBS" + else + echo "cannot find nm_test_func in $nlist" >&5 + fi + else + echo "cannot find nm_test_var in $nlist" >&5 + fi + else + echo "cannot run $global_symbol_pipe" >&5 + fi +else + echo "$progname: failed program was:" >&5 + cat conftest.c >&5 +fi +$rm conftest* + +# Do not use the global_symbol_pipe unless it works. +echo "$ac_t$pipe_works" 1>&6 +test "$pipe_works" = yes || global_symbol_pipe= + +# Check hardcoding attributes. +echo $ac_n "checking how to hardcode library paths into programs... $ac_c" 1>&6 +hardcode_action= +if test -n "$hardcode_libdir_flag_spec" || \ + test -n "$runpath_var"; then + + # We can hardcode non-existant directories. + if test "$hardcode_direct" != no && \ + test "$hardcode_minus_L" != no && \ + test "$hardcode_shlibpath_var" != no; then + + # Linking always hardcodes the temporary library directory. + hardcode_action=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action=immediate + fi +elif test "$hardcode_direct" != yes && \ + test "$hardcode_minus_L" != yes && \ + test "$hardcode_shlibpath_var" != yes; then + # We cannot hardcode anything. + hardcode_action=unsupported +else + # We can only hardcode existing directories. + hardcode_action=relink +fi +echo "$ac_t$hardcode_action" 1>&6 +test "$hardcode_action" = unsupported && can_build_shared=no + + +reload_flag= +reload_cmds='$LD$reload_flag -o $output$reload_objs' +echo $ac_n "checking for $LD option to reload object files... $ac_c" 1>&6 +# PORTME Some linker may need a different reload flag. +reload_flag='-r' +echo "$ac_t$reload_flag" +test -n "$reload_flag" && reload_flag=" $reload_flag" + +# PORTME Fill in your ld.so characteristics +library_names_spec= +libname_spec='lib$name' +soname_spec= +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +version_type=none +dynamic_linker="$host_os ld.so" + +echo $ac_n "checking dynamic linker characteristics... $ac_c" 1>&6 +case "$host_os" in +aix3* | aix4*) + version_type=linux + library_names_spec='${libname}${release}.so.$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}.so.$major' + ;; + +amigaos*) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "(cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a)"; (cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a) || exit 1; done' + ;; + +freebsd2* | freebsd3*) + version_type=sunos + library_names_spec='${libname}${release}.so.$versuffix $libname.so' + finish_cmds='PATH="$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + ;; + +gnu*) + version_type=sunos + library_names_spec='${libname}${release}.so.$versuffix' + shlibpath_var=LD_LIBRARY_PATH + ;; + +hpux9* | hpux10*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + dynamic_linker="$host_os dld.sl" + version_type=sunos + shlibpath_var=SHLIB_PATH + library_names_spec='${libname}${release}.sl.$versuffix ${libname}${release}.sl.$major $libname.sl' + soname_spec='${libname}${release}.sl.$major' + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +irix5* | irix6*) + version_type=osf + soname_spec='${libname}${release}.so' + library_names_spec='${libname}${release}.so.$versuffix $libname.so' + shlibpath_var=LD_LIBRARY_PATH + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux-gnuoldld* | linux-gnuaout* | linux-gnucoff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux-gnu*) + version_type=linux + library_names_spec='${libname}${release}.so.$versuffix ${libname}${release}.so.$major $libname.so' + soname_spec='${libname}${release}.so.$major' + finish_cmds='PATH="$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + + if test -f /lib/ld.so.1; then + dynamic_linker='GNU ld.so' + else + # Only the GNU ld.so supports shared libraries on MkLinux. + case "$host_cpu" in + powerpc*) dynamic_linker=no ;; + *) dynamic_linker='Linux ld.so' ;; + esac + fi + ;; + +netbsd* | openbsd*) + version_type=sunos + library_names_spec='${libname}${release}.so.$versuffix' + finish_cmds='PATH="$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + ;; + +os2*) + libname_spec='$name' + library_names_spec='$libname.dll $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4*) + version_type=osf + soname_spec='${libname}${release}.so' + library_names_spec='${libname}${release}.so.$versuffix $libname.so' + shlibpath_var=LD_LIBRARY_PATH + ;; + +sco3.2v5*) + version_type=osf + soname_spec='${libname}${release}.so.$major' + library_names_spec='${libname}${release}.so.$versuffix ${libname}${release}.so.$major $libname.so' + shlibpath_var=LD_LIBRARY_PATH + ;; + +solaris2*) + version_type=linux + library_names_spec='${libname}${release}.so.$versuffix ${libname}${release}.so.$major $libname.so' + soname_spec='${libname}${release}.so.$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}.so.$versuffix' + finish_cmds='PATH="$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + ;; + +sysv4.2uw2*) + version_type=linux + library_names_spec='${libname}${release}.so.$versuffix ${libname}${release}.so.$major $libname.so' + soname_spec='${libname}${release}.so.$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}.so.$versuffix ${libname}${release}.so.$major $libname.so' + soname_spec='${libname}${release}.so.$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +echo "$ac_t$dynamic_linker" +test "$dynamic_linker" = no && can_build_shared=no + +# Report the final consequences. +echo "checking if libtool supports shared libraries... $can_build_shared" 1>&6 + +echo $ac_n "checking whether to build shared libraries... $ac_c" 1>&6 +test "$can_build_shared" = "no" && enable_shared=no + +# On AIX, shared libraries and static libraries use the same namespace, and +# are all built from PIC. +case "$host_os" in +aix*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds;\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; +esac + +echo "$ac_t$enable_shared" 1>&6 + +# Make sure either enable_shared or enable_static is yes. +test "$enable_shared" = yes || enable_static=yes + +echo "checking whether to build static libraries... $enable_static" 1>&6 + +echo $ac_n "checking for objdir... $ac_c" 1>&6 +rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + objdir=_libs +fi +rmdir .libs 2>/dev/null +echo "$ac_t$objdir" 1>&6 + +# Copy echo and quote the copy, instead of the original, because it is +# used later. +ltecho="$echo" + +# Now quote all the things that may contain metacharacters. +for var in ltecho old_CC old_CFLAGS old_CPPFLAGS old_LD old_NM old_RANLIB \ + old_LN_S AR CC LD LN_S NM reload_flag reload_cmds wl pic_flag \ + link_static_flag no_builtin_flag export_dynamic_flag_spec \ + libname_spec library_names_spec soname_spec RANLIB \ + old_archive_cmds old_archive_from_new_cmds old_postinstall_cmds \ + old_postuninstall_cmds archive_cmds postinstall_cmds postuninstall_cmds \ + allow_undefined_flag no_undefined_flag \ + finish_cmds finish_eval global_symbol_pipe \ + hardcode_libdir_flag_spec hardcode_libdir_separator; do + + case "$var" in + reload_cmds | old_archive_cmds | old_archive_from_new_cmds | \ + old_postinstall_cmds | old_postuninstall_cmds | archive_cmds | \ + postinstall_cmds | postuninstall_cmds | finish_cmds) + # Double-quote double-evaled strings. + eval "$var=\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\"\`" + ;; + *) + eval "$var=\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`" + ;; + esac +done + +ofile=libtool +trap "$rm $ofile; exit 1" 1 2 15 +echo creating $ofile +$rm $ofile +cat < $ofile +#! /bin/sh + +# libtool - Provide generalized library-building support services. +# Generated automatically by $PROGRAM - GNU $PACKAGE $VERSION +# NOTE: Changes made to this file will be lost: look at ltconfig or ltmain.sh. +# +# Copyright (C) 1996-1998 Free Software Foundation, Inc. +# Gordon Matzigkeit , 1996 +# +# 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. +# +# 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. + +# This program was configured as follows, +# on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# +# CC="$old_CC" CFLAGS="$old_CFLAGS" CPPFLAGS="$old_CPPFLAGS" \\ +# LD="$old_LD" NM="$old_NM" RANLIB="$old_RANLIB" LN_S="$old_LN_S" \\ +# $0$ltconfig_args +# +# Compiler and other test output produced by $progname, useful for +# debugging $progname, is in ./config.log if it exists. + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="sed -e s/^X//" + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +if test "\${CDPATH+set}" = set; then CDPATH=; export CDPATH; fi + +# An echo program that does not interpret backslashes. +echo="$ltecho" + +# The version of $progname that generated this script. +LTCONFIG_VERSION="$VERSION" + +# Shell to use when invoking shell scripts. +SHELL=${CONFIG_SHELL-/bin/sh} + +# Whether or not to build libtool libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build old-style libraries. +build_old_libs=$enable_static + +# The host system. +host_alias="$host_alias" +host="$host" + +# The archiver. +AR="$AR" + +# The default C compiler. +CC="$CC" + +# The linker used to build libraries. +LD="$LD" + +# Whether we need hard or soft links. +LN_S="$LN_S" + +# A BSD-compatible nm program. +NM="$NM" + +# The name of the directory that contains temporary libtool files. +objdir="$objdir" + +# How to create reloadable object files. +reload_flag="$reload_flag" +reload_cmds="$reload_cmds" + +# How to pass a linker flag through the compiler. +wl="$wl" + +# Additional compiler flags for building library objects. +pic_flag="$pic_flag" + +# Compiler flag to prevent dynamic linking. +link_static_flag="$link_static_flag" + +# Compiler flag to turn off builtin functions. +no_builtin_flag="$no_builtin_flag" + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec="$export_dynamic_flag_spec" + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec="$libname_spec" + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec="$library_names_spec" + +# The coded name of the library, if different from the real name. +soname_spec="$soname_spec" + +# Commands used to build and install an old-style archive. +RANLIB="$RANLIB" +old_archive_cmds="$old_archive_cmds" +old_postinstall_cmds="$old_postinstall_cmds" +old_postuninstall_cmds="$old_postuninstall_cmds" + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds="$old_archive_from_new_cmds" + +# Commands used to build and install a shared archive. +archive_cmds="$archive_cmds" +postinstall_cmds="$postinstall_cmds" +postuninstall_cmds="$postuninstall_cmds" + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag="$allow_undefined_flag" + +# Flag that forces no undefined symbols. +no_undefined_flag="$no_undefined_flag" + +# Commands used to finish a libtool library installation in a directory. +finish_cmds="$finish_cmds" + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval="$finish_eval" + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe="$global_symbol_pipe" + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec="$hardcode_libdir_flag_spec" + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator="$hardcode_libdir_separator" + +# Set to yes if using DIR/libNAME.so during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$hardcode_direct + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$hardcode_minus_L + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var + +EOF + +case "$host_os" in +aix3*) + cat <<\EOF >> $ofile +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "${COLLECT_NAMES+set}" != set; then + COLLECT_NAMES= + export COLLECT_NAMES +fi + +EOF + ;; +esac + +# Append the ltmain.sh script. +cat "$ltmain" >> $ofile || (rm -f $ofile; exit 1) + +chmod +x $ofile +exit 0 + +# Local Variables: +# mode:shell-script +# sh-indentation:2 +# End: diff --git a/mk4/modimage/jpeg-6b/ltmain.sh b/mk4/modimage/jpeg-6b/ltmain.sh new file mode 100644 index 0000000..e9350b3 --- /dev/null +++ b/mk4/modimage/jpeg-6b/ltmain.sh @@ -0,0 +1,2453 @@ +# ltmain.sh - Provide generalized library-building support services. +# NOTE: Changing this file will not affect anything until you rerun ltconfig. +# +# Copyright (C) 1996-1998 Free Software Foundation, Inc. +# Gordon Matzigkeit , 1996 +# +# 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. +# +# 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. + +# The name of this program. +progname=`$echo "$0" | sed 's%^.*/%%'` +modename="$progname" + +# Constants. +PROGRAM=ltmain.sh +PACKAGE=libtool +VERSION=1.2 + +default_mode= +help="Try \`$progname --help' for more information." +magic="%%%MAGIC variable%%%" +mkdir="mkdir" +mv="mv -f" +rm="rm -f" + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='sed -e s/^X//' +sed_quote_subst='s/\([\\`\\"$\\\\]\)/\\\1/g' + +# NLS nuisances. +# Only set LANG and LC_ALL to C if already set. +# These must not be set unconditionally because not all systems understand +# e.g. LANG=C (notably SCO). +if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi +if test "${LANG+set}" = set; then LANG=C; export LANG; fi + +if test "$LTCONFIG_VERSION" != "$VERSION"; then + echo "$modename: ltconfig version \`$LTCONFIG_VERSION' does not match $PROGRAM version \`$VERSION'" 1>&2 + echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit 1 +fi + +if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then + echo "$modename: not configured to build any kind of library" 1>&2 + echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit 1 +fi + +# Global variables. +mode=$default_mode +nonopt= +prev= +prevopt= +run= +show="$echo" +show_help= +execute_dlfiles= + +# Parse our command line options once, thoroughly. +while test $# -gt 0 +do + arg="$1" + shift + + case "$arg" in + -*=*) optarg=`$echo "X$arg" | $Xsed -e 's/[-_a-zA-Z0-9]*=//'` ;; + *) optarg= ;; + esac + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case "$prev" in + execute_dlfiles) + eval "$prev=\"\$$prev \$arg\"" + ;; + *) + eval "$prev=\$arg" + ;; + esac + + prev= + prevopt= + continue + fi + + # Have we seen a non-optional argument yet? + case "$arg" in + --help) + show_help=yes + ;; + + --version) + echo "$PROGRAM (GNU $PACKAGE) $VERSION" + exit 0 + ;; + + --dry-run | -n) + run=: + ;; + + --features) + echo "host: $host" + if test "$build_libtool_libs" = yes; then + echo "enable shared libraries" + else + echo "disable shared libraries" + fi + if test "$build_old_libs" = yes; then + echo "enable static libraries" + else + echo "disable static libraries" + fi + exit 0 + ;; + + --finish) mode="finish" ;; + + --mode) prevopt="--mode" prev=mode ;; + --mode=*) mode="$optarg" ;; + + --quiet | --silent) + show=: + ;; + + -dlopen) + prevopt="-dlopen" + prev=execute_dlfiles + ;; + + -*) + $echo "$modename: unrecognized option \`$arg'" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; + + *) + nonopt="$arg" + break + ;; + esac +done + +if test -n "$prevopt"; then + $echo "$modename: option \`$prevopt' requires an argument" 1>&2 + $echo "$help" 1>&2 + exit 1 +fi + +if test -z "$show_help"; then + + # Infer the operation mode. + if test -z "$mode"; then + case "$nonopt" in + *cc | *++ | gcc* | *-gcc*) + mode=link + for arg + do + case "$arg" in + -c) + mode=compile + break + ;; + esac + done + ;; + *db | *dbx) + mode=execute + ;; + *install*|cp|mv) + mode=install + ;; + *rm) + mode=uninstall + ;; + *) + # If we have no mode, but dlfiles were specified, then do execute mode. + test -n "$execute_dlfiles" && mode=execute + + # Just use the default operation mode. + if test -z "$mode"; then + if test -n "$nonopt"; then + $echo "$modename: warning: cannot infer operation mode from \`$nonopt'" 1>&2 + else + $echo "$modename: warning: cannot infer operation mode without MODE-ARGS" 1>&2 + fi + fi + ;; + esac + fi + + # Only execute mode is allowed to have -dlopen flags. + if test -n "$execute_dlfiles" && test "$mode" != execute; then + $echo "$modename: unrecognized option \`-dlopen'" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + # Change the help message to a mode-specific one. + generic_help="$help" + help="Try \`$modename --help --mode=$mode' for more information." + + # These modes are in order of execution frequency so that they run quickly. + case "$mode" in + # libtool compile mode + compile) + modename="$modename: compile" + # Get the compilation command and the source file. + base_compile= + lastarg= + srcfile="$nonopt" + suppress_output= + + for arg + do + # Accept any command-line options. + case "$arg" in + -o) + $echo "$modename: you cannot specify the output filename with \`-o'" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; + + -static) + build_libtool_libs=no + build_old_libs=yes + continue + ;; + esac + + # Accept the current argument as the source file. + lastarg="$srcfile" + srcfile="$arg" + + # Aesthetically quote the previous argument. + + # Backslashify any backslashes, double quotes, and dollar signs. + # These are the only characters that are still specially + # interpreted inside of double-quoted scrings. + lastarg=`$echo "X$lastarg" | $Xsed -e "$sed_quote_subst"` + + # Double-quote args containing other shell metacharacters. + # Many Bourne shells cannot handle close brackets correctly in scan + # sets, so we specify it separately. + case "$lastarg" in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + lastarg="\"$lastarg\"" + ;; + esac + + # Add the previous argument to base_compile. + if test -z "$base_compile"; then + base_compile="$lastarg" + else + base_compile="$base_compile $lastarg" + fi + done + + # Get the name of the library object. + libobj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%'` + + # Recognize several different file suffixes. + xform='[cCFSfms]' + case "$libobj" in + *.ada) xform=ada ;; + *.adb) xform=adb ;; + *.ads) xform=ads ;; + *.asm) xform=asm ;; + *.c++) xform=c++ ;; + *.cc) xform=cc ;; + *.cpp) xform=cpp ;; + *.cxx) xform=cxx ;; + *.f90) xform=f90 ;; + *.for) xform=for ;; + esac + + libobj=`$echo "X$libobj" | $Xsed -e "s/\.$xform$/.lo/"` + + case "$libobj" in + *.lo) obj=`$echo "X$libobj" | $Xsed -e 's/\.lo$/.o/'` ;; + *) + $echo "$modename: cannot determine name of library object from \`$srcfile'" 1>&2 + exit 1 + ;; + esac + + if test -z "$base_compile"; then + $echo "$modename: you must specify a compilation command" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + # Delete any leftover library objects. + if test "$build_old_libs" = yes; then + $run $rm $obj $libobj + trap "$run $rm $obj $libobj; exit 1" 1 2 15 + else + $run $rm $libobj + trap "$run $rm $libobj; exit 1" 1 2 15 + fi + + # Only build a PIC object if we are building libtool libraries. + if test "$build_libtool_libs" = yes; then + # Without this assignment, base_compile gets emptied. + fbsd_hideous_sh_bug=$base_compile + + # All platforms use -DPIC, to notify preprocessed assembler code. + $show "$base_compile$pic_flag -DPIC $srcfile" + if $run eval "$base_compile\$pic_flag -DPIC \$srcfile"; then : + else + test -n "$obj" && $run $rm $obj + exit 1 + fi + + # If we have no pic_flag, then copy the object into place and finish. + if test -z "$pic_flag"; then + $show "$LN_S $obj $libobj" + $run $LN_S $obj $libobj + exit $? + fi + + # Just move the object, then go on to compile the next one + $show "$mv $obj $libobj" + $run $mv $obj $libobj || exit 1 + + # Allow error messages only from the first compilation. + suppress_output=' >/dev/null 2>&1' + fi + + # Only build a position-dependent object if we build old libraries. + if test "$build_old_libs" = yes; then + # Suppress compiler output if we already did a PIC compilation. + $show "$base_compile $srcfile$suppress_output" + if $run eval "$base_compile \$srcfile$suppress_output"; then : + else + $run $rm $obj $libobj + exit 1 + fi + fi + + # Create an invalid libtool object if no PIC, so that we do not + # accidentally link it into a program. + if test "$build_libtool_libs" != yes; then + $show "echo timestamp > $libobj" + $run eval "echo timestamp > \$libobj" || exit $? + fi + + exit 0 + ;; + + # libtool link mode + link) + modename="$modename: link" + CC="$nonopt" + allow_undefined=yes + compile_command="$CC" + finalize_command="$CC" + + compile_shlibpath= + finalize_shlibpath= + deplibs= + dlfiles= + dlprefiles= + export_dynamic=no + hardcode_libdirs= + libobjs= + link_against_libtool_libs= + ltlibs= + objs= + prev= + prevarg= + release= + rpath= + perm_rpath= + temp_rpath= + vinfo= + + # We need to know -static, to get the right output filenames. + for arg + do + case "$arg" in + -all-static | -static) + if test "X$arg" = "X-all-static" && test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then + $echo "$modename: warning: complete static linking is impossible in this configuration" 1>&2 + fi + build_libtool_libs=no + build_old_libs=yes + break + ;; + esac + done + + # See if our shared archives depend on static archives. + test -n "$old_archive_from_new_cmds" && build_old_libs=yes + + # Go through the arguments, transforming them on the way. + for arg + do + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case "$prev" in + output) + compile_command="$compile_command @OUTPUT@" + finalize_command="$finalize_command @OUTPUT@" + ;; + esac + + case "$prev" in + dlfiles|dlprefiles) + case "$arg" in + *.la | *.lo) ;; # We handle these cases below. + *) + dlprefiles="$dlprefiles $arg" + test "$prev" = dlfiles && dlfiles="$dlfiles $arg" + prev= + ;; + esac + ;; + release) + release="-$arg" + prev= + continue + ;; + rpath) + rpath="$rpath $arg" + prev= + continue + ;; + *) + eval "$prev=\"\$arg\"" + prev= + continue + ;; + esac + fi + + prevarg="$arg" + + case "$arg" in + -all-static) + if test -n "$link_static_flag"; then + compile_command="$compile_command $link_static_flag" + finalize_command="$finalize_command $link_static_flag" + fi + continue + ;; + + -allow-undefined) + # FIXME: remove this flag sometime in the future. + $echo "$modename: \`-allow-undefined' is deprecated because it is the default" 1>&2 + continue + ;; + + -dlopen) + prev=dlfiles + continue + ;; + + -dlpreopen) + prev=dlprefiles + continue + ;; + + -export-dynamic) + if test "$export_dynamic" != yes; then + export_dynamic=yes + if test -n "$export_dynamic_flag_spec"; then + eval arg=\"$export_dynamic_flag_spec\" + else + arg= + fi + + # Add the symbol object into the linking commands. + compile_command="$compile_command @SYMFILE@" + finalize_command="$finalize_command @SYMFILE@" + fi + ;; + + -L*) + dir=`$echo "X$arg" | $Xsed -e 's%^-L\(.*\)$%\1%'` + case "$dir" in + /* | [A-Za-z]:\\*) + # Add the corresponding hardcode_libdir_flag, if it is not identical. + ;; + *) + $echo "$modename: \`-L$dir' cannot specify a relative directory" 1>&2 + exit 1 + ;; + esac + deplibs="$deplibs $arg" + ;; + + -l*) deplibs="$deplibs $arg" ;; + + -no-undefined) + allow_undefined=no + continue + ;; + + -o) prev=output ;; + + -release) + prev=release + continue + ;; + + -rpath) + prev=rpath + continue + ;; + + -static) + # If we have no pic_flag, then this is the same as -all-static. + if test -z "$pic_flag" && test -n "$link_static_flag"; then + compile_command="$compile_command $link_static_flag" + finalize_command="$finalize_command $link_static_flag" + fi + continue + ;; + + -version-info) + prev=vinfo + continue + ;; + + # Some other compiler flag. + -* | +*) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case "$arg" in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + ;; + + *.o | *.a) + # A standard object. + objs="$objs $arg" + ;; + + *.lo) + # A library object. + if test "$prev" = dlfiles; then + dlfiles="$dlfiles $arg" + if test "$build_libtool_libs" = yes; then + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + if test "$prev" = dlprefiles; then + # Preload the old-style object. + dlprefiles="$dlprefiles "`$echo "X$arg" | $Xsed -e 's/\.lo$/\.o/'` + prev= + fi + libobjs="$libobjs $arg" + ;; + + *.la) + # A libtool-controlled library. + + dlname= + libdir= + library_names= + old_library= + + # Check to see that this really is a libtool archive. + if (sed -e '2q' $arg | egrep '^# Generated by ltmain\.sh') >/dev/null 2>&1; then : + else + $echo "$modename: \`$arg' is not a valid libtool archive" 1>&2 + exit 1 + fi + + # If there is no directory component, then add one. + case "$arg" in + */* | *\\*) . $arg ;; + *) . ./$arg ;; + esac + + if test -z "$libdir"; then + $echo "$modename: \`$arg' contains no -rpath information" 1>&2 + exit 1 + fi + + # Get the name of the library we link against. + linklib= + for l in $old_library $library_names; do + linklib="$l" + done + + if test -z "$linklib"; then + $echo "$modename: cannot find name of link library for \`$arg'" 1>&2 + exit 1 + fi + + # Find the relevant object directory and library name. + name=`$echo "X$arg" | $Xsed -e 's%^.*/%%' -e 's/\.la$//' -e 's/^lib//'` + dir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` + if test "X$dir" = "X$arg"; then + dir="$objdir" + else + dir="$dir/$objdir" + fi + + # This library was specified with -dlopen. + if test "$prev" = dlfiles; then + dlfiles="$dlfiles $arg" + if test -z "$dlname"; then + # If there is no dlname, we need to preload. + prev=dlprefiles + else + # We should not create a dependency on this library, but we + # may need any libraries it requires. + compile_command="$compile_command$dependency_libs" + finalize_command="$finalize_command$dependency_libs" + prev= + continue + fi + fi + + # The library was specified with -dlpreopen. + if test "$prev" = dlprefiles; then + # Prefer using a static library (so that no silly _DYNAMIC symbols + # are required to link). + if test -n "$old_library"; then + dlprefiles="$dlprefiles $dir/$old_library" + else + dlprefiles="$dlprefiles $dir/$linklib" + fi + prev= + fi + + if test "$build_libtool_libs" = yes && test -n "$library_names"; then + link_against_libtool_libs="$link_against_libtool_libs $arg" + if test -n "$shlibpath_var"; then + # Make sure the rpath contains only unique directories. + case "$temp_rpath " in + *" $dir "*) ;; + *) temp_rpath="$temp_rpath $dir" ;; + esac + fi + + # This is the magic to use -rpath. + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + # Put the magic libdir with the hardcode flag. + hardcode_libdirs="$libdir" + libdir="@HARDCODE_LIBDIRS@" + else + # Just accumulate the unique libdirs. + case "$hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator" in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + libdir= + fi + fi + + if test -n "$libdir"; then + eval flag=\"$hardcode_libdir_flag_spec\" + + compile_command="$compile_command $flag" + finalize_command="$finalize_command $flag" + fi + elif test -n "$runpath_var"; then + # Do the same for the permanent run path. + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + + + case "$hardcode_action" in + immediate) + if test "$hardcode_direct" = no; then + compile_command="$compile_command $dir/$linklib" + elif test "$hardcode_minus_L" = no; then + compile_command="$compile_command -L$dir -l$name" + elif test "$hardcode_shlibpath_var" = no; then + compile_shlibpath="$compile_shlibpath$dir:" + compile_command="$compile_command -l$name" + fi + ;; + + relink) + # We need an absolute path. + case "$dir" in + /* | [A-Za-z]:\\*) ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + $echo "$modename: cannot determine absolute directory name of \`$dir'" 1>&2 + exit 1 + fi + dir="$absdir" + ;; + esac + + if test "$hardcode_direct" = yes; then + compile_command="$compile_command $dir/$linklib" + elif test "$hardcode_minus_L" = yes; then + compile_command="$compile_command -L$dir -l$name" + elif test "$hardcode_shlibpath_var" = yes; then + compile_shlibpath="$compile_shlibpath$dir:" + compile_command="$compile_command -l$name" + fi + ;; + + *) + $echo "$modename: \`$hardcode_action' is an unknown hardcode action" 1>&2 + exit 1 + ;; + esac + + # Finalize command for both is simple: just hardcode it. + if test "$hardcode_direct" = yes; then + finalize_command="$finalize_command $libdir/$linklib" + elif test "$hardcode_minus_L" = yes; then + finalize_command="$finalize_command -L$libdir -l$name" + elif test "$hardcode_shlibpath_var" = yes; then + finalize_shlibpath="$finalize_shlibpath$libdir:" + finalize_command="$finalize_command -l$name" + else + # We cannot seem to hardcode it, guess we'll fake it. + finalize_command="$finalize_command -L$libdir -l$name" + fi + else + # Transform directly to old archives if we don't build new libraries. + if test -n "$pic_flag" && test -z "$old_library"; then + $echo "$modename: cannot find static library for \`$arg'" 1>&2 + exit 1 + fi + + # Here we assume that one of hardcode_direct or hardcode_minus_L + # is not unsupported. This is valid on all known static and + # shared platforms. + if test "$hardcode_direct" != unsupported; then + test -n "$old_library" && linklib="$old_library" + compile_command="$compile_command $dir/$linklib" + finalize_command="$finalize_command $dir/$linklib" + else + compile_command="$compile_command -L$dir -l$name" + finalize_command="$finalize_command -L$dir -l$name" + fi + fi + + # Add in any libraries that this one depends upon. + compile_command="$compile_command$dependency_libs" + finalize_command="$finalize_command$dependency_libs" + continue + ;; + + # Some other compiler argument. + *) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case "$arg" in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + ;; + esac + + # Now actually substitute the argument into the commands. + if test -n "$arg"; then + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + fi + done + + if test -n "$prev"; then + $echo "$modename: the \`$prevarg' option requires an argument" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + if test -n "$vinfo" && test -n "$release"; then + $echo "$modename: you cannot specify both \`-version-info' and \`-release'" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + oldlib= + oldobjs= + case "$output" in + "") + $echo "$modename: you must specify an output file" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; + + */* | *\\*) + $echo "$modename: output file \`$output' must have no directory components" 1>&2 + exit 1 + ;; + + *.a) + # Now set the variables for building old libraries. + build_libtool_libs=no + build_old_libs=yes + oldlib="$output" + $show "$rm $oldlib" + $run $rm $oldlib + ;; + + *.la) + # Make sure we only generate libraries of the form `libNAME.la'. + case "$output" in + lib*) ;; + *) + $echo "$modename: libtool library \`$arg' must begin with \`lib'" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; + esac + + name=`$echo "X$output" | $Xsed -e 's/\.la$//' -e 's/^lib//'` + eval libname=\"$libname_spec\" + + # All the library-specific variables (install_libdir is set above). + library_names= + old_library= + dlname= + current=0 + revision=0 + age=0 + + if test -n "$objs"; then + $echo "$modename: cannot build libtool library \`$output' from non-libtool objects:$objs" 2>&1 + exit 1 + fi + + # How the heck are we supposed to write a wrapper for a shared library? + if test -n "$link_against_libtool_libs"; then + $echo "$modename: libtool library \`$output' may not depend on uninstalled libraries:$link_against_libtool_libs" 1>&2 + exit 1 + fi + + if test -n "$dlfiles$dlprefiles"; then + $echo "$modename: warning: \`-dlopen' is ignored while creating libtool libraries" 1>&2 + # Nullify the symbol file. + compile_command=`$echo "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"` + finalize_command=`$echo "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"` + fi + + if test -z "$rpath"; then + $echo "$modename: you must specify an installation directory with \`-rpath'" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + set dummy $rpath + if test $# -gt 2; then + $echo "$modename: warning: ignoring multiple \`-rpath's for a libtool library" 1>&2 + fi + install_libdir="$2" + + # Parse the version information argument. + IFS="${IFS= }"; save_ifs="$IFS"; IFS=':' + set dummy $vinfo + IFS="$save_ifs" + + if test -n "$5"; then + $echo "$modename: too many parameters to \`-version-info'" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + test -n "$2" && current="$2" + test -n "$3" && revision="$3" + test -n "$4" && age="$4" + + # Check that each of the things are valid numbers. + case "$current" in + 0 | [1-9] | [1-9][0-9]*) ;; + *) + $echo "$modename: CURRENT \`$current' is not a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit 1 + ;; + esac + + case "$revision" in + 0 | [1-9] | [1-9][0-9]*) ;; + *) + $echo "$modename: REVISION \`$revision' is not a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit 1 + ;; + esac + + case "$age" in + 0 | [1-9] | [1-9][0-9]*) ;; + *) + $echo "$modename: AGE \`$age' is not a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit 1 + ;; + esac + + if test $age -gt $current; then + $echo "$modename: AGE \`$age' is greater than the current interface number \`$current'" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit 1 + fi + + # Calculate the version variables. + version_vars="version_type current age revision" + case "$version_type" in + none) ;; + + linux) + version_vars="$version_vars major versuffix" + major=`expr $current - $age` + versuffix="$major.$age.$revision" + ;; + + osf) + version_vars="$version_vars versuffix verstring" + major=`expr $current - $age` + versuffix="$current.$age.$revision" + verstring="$versuffix" + + # Add in all the interfaces that we are compatible with. + loop=$age + while test $loop != 0; do + iface=`expr $current - $loop` + loop=`expr $loop - 1` + verstring="$verstring:${iface}.0" + done + + # Make executables depend on our current version. + verstring="$verstring:${current}.0" + ;; + + sunos) + version_vars="$version_vars major versuffix" + major="$current" + versuffix="$current.$revision" + ;; + + *) + $echo "$modename: unknown library version type \`$version_type'" 1>&2 + echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit 1 + ;; + esac + + # Create the output directory, or remove our outputs if we need to. + if test -d $objdir; then + $show "$rm $objdir/$output $objdir/$libname.* $objdir/${libname}${release}.*" + $run $rm $objdir/$output $objdir/$libname.* $objdir/${libname}${release}.* + else + $show "$mkdir $objdir" + $run $mkdir $objdir + status=$? + if test $status -eq 0 || test -d $objdir; then : + else + exit $status + fi + fi + + # Check to see if the archive will have undefined symbols. + if test "$allow_undefined" = yes; then + if test "$allow_undefined_flag" = unsupported; then + $echo "$modename: warning: undefined symbols not allowed in $host shared libraries" 1>&2 + build_libtool_libs=no + build_old_libs=yes + fi + else + # Don't allow undefined symbols. + allow_undefined_flag="$no_undefined_flag" + fi + + # Add libc to deplibs on all systems. + dependency_libs="$deplibs" + deplibs="$deplibs -lc" + + if test "$build_libtool_libs" = yes; then + # Get the real and link names of the library. + eval library_names=\"$library_names_spec\" + set dummy $library_names + realname="$2" + shift; shift + + if test -n "$soname_spec"; then + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + + lib="$objdir/$realname" + for link + do + linknames="$linknames $link" + done + + # Use standard objects if they are PIC. + test -z "$pic_flag" && libobjs=`$echo "X$libobjs " | $Xsed -e 's/\.lo /.o /g' -e 's/ $//g'` + + # Do each of the archive commands. + eval cmds=\"$archive_cmds\" + IFS="${IFS= }"; save_ifs="$IFS"; IFS=';' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + + # Create links to the real library. + for linkname in $linknames; do + $show "(cd $objdir && $LN_S $realname $linkname)" + $run eval '(cd $objdir && $LN_S $realname $linkname)' || exit $? + done + + # If -export-dynamic was specified, set the dlname. + if test "$export_dynamic" = yes; then + # On all known operating systems, these are identical. + dlname="$soname" + fi + fi + + # Now set the variables for building old libraries. + oldlib="$objdir/$libname.a" + ;; + + *.lo | *.o) + if test -n "$link_against_libtool_libs"; then + $echo "$modename: error: cannot link libtool libraries into reloadable objects" 1>&2 + exit 1 + fi + + if test -n "$deplibs"; then + $echo "$modename: warning: \`-l' and \`-L' are ignored while creating objects" 1>&2 + fi + + if test -n "$dlfiles$dlprefiles"; then + $echo "$modename: warning: \`-dlopen' is ignored while creating objects" 1>&2 + # Nullify the symbol file. + compile_command=`$echo "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"` + finalize_command=`$echo "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"` + fi + + if test -n "$rpath"; then + $echo "$modename: warning: \`-rpath' is ignored while creating objects" 1>&2 + fi + + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info' is ignored while creating objects" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored while creating objects" 1>&2 + fi + + case "$output" in + *.lo) + if test -n "$objs"; then + $echo "$modename: cannot build library object \`$output' from non-libtool objects" 1>&2 + exit 1 + fi + libobj="$output" + obj=`$echo "X$output" | $Xsed -e 's/\.lo$/.o/'` + ;; + *) + libobj= + obj="$output" + ;; + esac + + # Delete the old objects. + $run $rm $obj $libobj + + # Create the old-style object. + reload_objs="$objs"`$echo "X$libobjs " | $Xsed -e 's/[^ ]*\.a //g' -e 's/\.lo /.o /g' -e 's/ $//g'` + + output="$obj" + eval cmds=\"$reload_cmds\" + IFS="${IFS= }"; save_ifs="$IFS"; IFS=';' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + + # Exit if we aren't doing a library object file. + test -z "$libobj" && exit 0 + + if test "$build_libtool_libs" != yes; then + # Create an invalid libtool object if no PIC, so that we don't + # accidentally link it into a program. + $show "echo timestamp > $libobj" + $run eval "echo timestamp > $libobj" || exit $? + exit 0 + fi + + if test -n "$pic_flag"; then + # Only do commands if we really have different PIC objects. + reload_objs="$libobjs" + output="$libobj" + eval cmds=\"$reload_cmds\" + IFS="${IFS= }"; save_ifs="$IFS"; IFS=';' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + else + # Just create a symlink. + $show "$LN_S $obj $libobj" + $run $LN_S $obj $libobj || exit 1 + fi + + exit 0 + ;; + + *) + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info' is ignored while linking programs" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored while creating objects" 1>&2 + fi + + if test -n "$rpath"; then + # If the user specified any rpath flags, then add them. + for libdir in $rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + # Put the magic libdir with the hardcode flag. + hardcode_libdirs="$libdir" + libdir="@HARDCODE_LIBDIRS@" + else + # Just accumulate the unique libdirs. + case "$hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator" in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + libdir= + fi + fi + + if test -n "$libdir"; then + eval flag=\"$hardcode_libdir_flag_spec\" + + compile_command="$compile_command $flag" + finalize_command="$finalize_command $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + done + fi + + # Substitute the hardcoded libdirs into the compile commands. + if test -n "$hardcode_libdir_separator"; then + compile_command=`$echo "X$compile_command" | $Xsed -e "s%@HARDCODE_LIBDIRS@%$hardcode_libdirs%g"` + finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@HARDCODE_LIBDIRS@%$hardcode_libdirs%g"` + fi + + if test -n "$libobjs" && test "$build_old_libs" = yes; then + # Transform all the library objects into standard objects. + compile_command=`$echo "X$compile_command " | $Xsed -e 's/\.lo /.o /g' -e 's/ $//'` + finalize_command=`$echo "X$finalize_command " | $Xsed -e 's/\.lo /.o /g' -e 's/ $//'` + fi + + if test "$export_dynamic" = yes && test -n "$NM" && test -n "$global_symbol_pipe"; then + dlsyms="${output}S.c" + else + dlsyms= + fi + + if test -n "$dlsyms"; then + # Add our own program objects to the preloaded list. + dlprefiles=`$echo "X$objs$dlprefiles " | $Xsed -e 's/\.lo /.o /g' -e 's/ $//'` + + # Discover the nlist of each of the dlfiles. + nlist="$objdir/${output}.nm" + + if test -d $objdir; then + $show "$rm $nlist ${nlist}T" + $run $rm "$nlist" "${nlist}T" + else + $show "$mkdir $objdir" + $run $mkdir $objdir + status=$? + if test $status -eq 0 || test -d $objdir; then : + else + exit $status + fi + fi + + for arg in $dlprefiles; do + $show "extracting global C symbols from \`$arg'" + $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" + done + + # Parse the name list into a source file. + $show "creating $objdir/$dlsyms" + if test -z "$run"; then + # Make sure we at least have an empty file. + test -f "$nlist" || : > "$nlist" + + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + wcout=`wc "$nlist" 2>/dev/null` + count=`echo "X$wcout" | $Xsed -e 's/^[ ]*\([0-9][0-9]*\).*$/\1/'` + (test "$count" -ge 0) 2>/dev/null || count=-1 + else + $rm "$nlist"T + count=-1 + fi + + case "$dlsyms" in + "") ;; + *.c) + $echo > "$objdir/$dlsyms" "\ +/* $dlsyms - symbol resolution table for \`$output' dlsym emulation. */ +/* Generated by $PROGRAM - GNU $PACKAGE $VERSION */ + +#ifdef __cplusplus +extern \"C\" { +#endif + +/* Prevent the only kind of declaration conflicts we can make. */ +#define dld_preloaded_symbol_count some_other_symbol +#define dld_preloaded_symbols some_other_symbol + +/* External symbol declarations for the compiler. */\ +" + + if test -f "$nlist"; then + sed -e 's/^.* \(.*\)$/extern char \1;/' < "$nlist" >> "$objdir/$dlsyms" + else + echo '/* NONE */' >> "$objdir/$dlsyms" + fi + + $echo >> "$objdir/$dlsyms" "\ + +#undef dld_preloaded_symbol_count +#undef dld_preloaded_symbols + +#if defined (__STDC__) && __STDC__ +# define __ptr_t void * +#else +# define __ptr_t char * +#endif + +/* The number of symbols in dld_preloaded_symbols, -1 if unsorted. */ +int dld_preloaded_symbol_count = $count; + +/* The mapping between symbol names and symbols. */ +struct { + char *name; + __ptr_t address; +} +dld_preloaded_symbols[] = +{\ +" + + if test -f "$nlist"; then + sed 's/^\(.*\) \(.*\)$/ {"\1", (__ptr_t) \&\2},/' < "$nlist" >> "$objdir/$dlsyms" + fi + + $echo >> "$objdir/$dlsyms" "\ + {0, (__ptr_t) 0} +}; + +#ifdef __cplusplus +} +#endif\ +" + ;; + + *) + $echo "$modename: unknown suffix for \`$dlsyms'" 1>&2 + exit 1 + ;; + esac + fi + + # Now compile the dynamic symbol file. + $show "(cd $objdir && $CC -c$no_builtin_flag \"$dlsyms\")" + $run eval '(cd $objdir && $CC -c$no_builtin_flag "$dlsyms")' || exit $? + + # Transform the symbol file into the correct name. + compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$objdir/${output}S.o%"` + finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$objdir/${output}S.o%"` + elif test "$export_dynamic" != yes; then + test -n "$dlfiles$dlprefiles" && $echo "$modename: warning: \`-dlopen' and \`-dlpreopen' are ignored without \`-export-dynamic'" 1>&2 + else + # We keep going just in case the user didn't refer to + # dld_preloaded_symbols. The linker will fail if global_symbol_pipe + # really was required. + $echo "$modename: not configured to extract global symbols from dlpreopened files" 1>&2 + + # Nullify the symbol file. + compile_command=`$echo "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"` + finalize_command=`$echo "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"` + fi + + if test -z "$link_against_libtool_libs" || test "$build_libtool_libs" != yes; then + # Replace the output file specification. + compile_command=`$echo "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` + finalize_command=`$echo "X$finalize_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` + + # We have no uninstalled library dependencies, so finalize right now. + $show "$compile_command" + $run eval "$compile_command" + exit $? + fi + + # Replace the output file specification. + compile_command=`$echo "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$objdir/$output"'%g'` + finalize_command=`$echo "X$finalize_command" | $Xsed -e 's%@OUTPUT@%'"$objdir/$output"'T%g'` + + # Create the binary in the object directory, then wrap it. + if test -d $objdir; then : + else + $show "$mkdir $objdir" + $run $mkdir $objdir + status=$? + if test $status -eq 0 || test -d $objdir; then : + else + exit $status + fi + fi + + if test -n "$shlibpath_var"; then + # We should set the shlibpath_var + rpath= + for dir in $temp_rpath; do + case "$dir" in + /* | [A-Za-z]:\\*) + # Absolute path. + rpath="$rpath$dir:" + ;; + *) + # Relative path: add a thisdir entry. + rpath="$rpath\$thisdir/$dir:" + ;; + esac + done + temp_rpath="$rpath" + fi + + # Delete the old output file. + $run $rm $output + + if test -n "$compile_shlibpath"; then + compile_command="$shlibpath_var=\"$compile_shlibpath\$$shlibpath_var\" $compile_command" + fi + if test -n "$finalize_shlibpath"; then + finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" + fi + + if test -n "$runpath_var" && test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + compile_command="$runpath_var=\"$rpath\$$runpath_var\" $compile_command" + finalize_command="$runpath_var=\"$rpath\$$runpath_var\" $finalize_command" + fi + + case "$hardcode_action" in + relink) + # AGH! Flame the AIX and HP-UX people for me, will ya? + $echo "$modename: warning: using a buggy system linker" 1>&2 + $echo "$modename: relinking will be required before \`$output' can be installed" 1>&2 + ;; + esac + + $show "$compile_command" + $run eval "$compile_command" || exit $? + + # Now create the wrapper script. + $show "creating $output" + + # Quote the finalize command for shipping. + finalize_command=`$echo "X$finalize_command" | $Xsed -e "$sed_quote_subst"` + + # Quote $echo for shipping. + qecho=`$echo "X$echo" | $Xsed -e "$sed_quote_subst"` + + # Only actually do things if our run command is non-null. + if test -z "$run"; then + $rm $output + trap "$rm $output; exit 1" 1 2 15 + + $echo > $output "\ +#! /bin/sh + +# $output - temporary wrapper script for $objdir/$output +# Generated by ltmain.sh - GNU $PACKAGE $VERSION +# +# The $output program cannot be directly executed until all the libtool +# libraries that it depends on are installed. +# +# This wrapper script should never be moved out of \``pwd`'. +# If it is, it will not operate correctly. + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='sed -e s/^X//' +sed_quote_subst='$sed_quote_subst' + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +if test \"\${CDPATH+set}\" = set; then CDPATH=; export CDPATH; fi + +# This environment variable determines our operation mode. +if test \"\$libtool_install_magic\" = \"$magic\"; then + # install mode needs the following variables: + link_against_libtool_libs='$link_against_libtool_libs' + finalize_command=\"$finalize_command\" +else + # When we are sourced in execute mode, \$file and \$echo are already set. + if test \"\$libtool_execute_magic\" = \"$magic\"; then : + else + echo=\"$qecho\" + file=\"\$0\" + fi\ +" + $echo >> $output "\ + + # Find the directory that this script lives in. + thisdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\` + test \"x\$thisdir\" = \"x\$file\" && thisdir=. + + # Follow symbolic links until we get to the real thisdir. + file=\`ls -ld \"\$file\" | sed -n 's/.*-> //p'\` + while test -n \"\$file\"; do + destdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\` + + # If there was a directory component, then change thisdir. + if test \"x\$destdir\" != \"x\$file\"; then + case \"\$destdir\" in + /* | [A-Za-z]:\\*) thisdir=\"\$destdir\" ;; + *) thisdir=\"\$thisdir/\$destdir\" ;; + esac + fi + + file=\`\$echo \"X\$file\" | \$Xsed -e 's%^.*/%%'\` + file=\`ls -ld \"\$thisdir/\$file\" | sed -n 's/.*-> //p'\` + done + + # Try to get the absolute directory name. + absdir=\`cd \"\$thisdir\" && pwd\` + test -n \"\$absdir\" && thisdir=\"\$absdir\" + + progdir=\"\$thisdir/$objdir\" + program='$output' + + if test -f \"\$progdir/\$program\"; then" + + # Export our shlibpath_var if we have one. + if test -n "$shlibpath_var" && test -n "$temp_rpath"; then + $echo >> $output "\ + # Add our own library path to $shlibpath_var + $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" + + # Some systems cannot cope with colon-terminated $shlibpath_var + $shlibpath_var=\`\$echo \"X\$$shlibpath_var\" | \$Xsed -e 's/:*\$//'\` + + export $shlibpath_var +" + fi + + $echo >> $output "\ + if test \"\$libtool_execute_magic\" != \"$magic\"; then + # Run the actual program with our arguments. + + # Export the path to the program. + PATH=\"\$progdir:\$PATH\" + export PATH + + exec \$program \${1+\"\$@\"} + + \$echo \"\$0: cannot exec \$program \${1+\"\$@\"}\" + exit 1 + fi + else + # The program doesn't exist. + \$echo \"\$0: error: \$progdir/\$program does not exist\" 1>&2 + \$echo \"This script is just a wrapper for \$program.\" 1>&2 + echo \"See the $PACKAGE documentation for more information.\" 1>&2 + exit 1 + fi +fi\ +" + chmod +x $output + fi + exit 0 + ;; + esac + + # See if we need to build an old-fashioned archive. + if test "$build_old_libs" = "yes"; then + # Transform .lo files to .o files. + oldobjs="$objs"`$echo "X$libobjs " | $Xsed -e 's/[^ ]*\.a //g' -e 's/\.lo /.o /g' -e 's/ $//g'` + + # Do each command in the archive commands. + if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then + eval cmds=\"$old_archive_from_new_cmds\" + else + eval cmds=\"$old_archive_cmds\" + fi + IFS="${IFS= }"; save_ifs="$IFS"; IFS=';' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + + # Now create the libtool archive. + case "$output" in + *.la) + old_library= + test "$build_old_libs" = yes && old_library="$libname.a" + + $show "creating $output" + + # Only create the output if not a dry run. + if test -z "$run"; then + $echo > $output "\ +# $output - a libtool library file +# Generated by ltmain.sh - GNU $PACKAGE $VERSION + +# The name that we can dlopen(3). +dlname='$dlname' + +# Names of this library. +library_names='$library_names' + +# The name of the static archive. +old_library='$old_library' + +# Libraries that this one depends upon. +dependency_libs='$dependency_libs' + +# Version information for $libname. +current=$current +age=$age +revision=$revision + +# Directory that this library needs to be installed in: +libdir='$install_libdir'\ +" + fi + + # Do a symbolic link so that the libtool archive can be found in + # LD_LIBRARY_PATH before the program is installed. + $show "(cd $objdir && $LN_S ../$output $output)" + $run eval "(cd $objdir && $LN_S ../$output $output)" || exit 1 + ;; + esac + exit 0 + ;; + + # libtool install mode + install) + modename="$modename: install" + + # There may be an optional /bin/sh argument at the beginning of + # install_prog (especially on Windows NT). + if test "$nonopt" = "$SHELL"; then + # Aesthetically quote it. + arg=`$echo "X$nonopt" | $Xsed -e "$sed_quote_subst"` + case "$arg" in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + install_prog="$arg " + arg="$1" + shift + else + install_prog= + arg="$nonopt" + fi + + # The real first argument should be the name of the installation program. + # Aesthetically quote it. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case "$arg" in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + install_prog="$install_prog$arg" + + # We need to accept at least all the BSD install flags. + dest= + files= + opts= + prev= + install_type= + isdir= + stripme= + for arg + do + if test -n "$dest"; then + files="$files $dest" + dest="$arg" + continue + fi + + case "$arg" in + -d) isdir=yes ;; + -f) prev="-f" ;; + -g) prev="-g" ;; + -m) prev="-m" ;; + -o) prev="-o" ;; + -s) + stripme=" -s" + continue + ;; + -*) ;; + + *) + # If the previous option needed an argument, then skip it. + if test -n "$prev"; then + prev= + else + dest="$arg" + continue + fi + ;; + esac + + # Aesthetically quote the argument. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case "$arg" in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + install_prog="$install_prog $arg" + done + + if test -z "$install_prog"; then + $echo "$modename: you must specify an install program" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + if test -n "$prev"; then + $echo "$modename: the \`$prev' option requires an argument" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + if test -z "$files"; then + if test -z "$dest"; then + $echo "$modename: no file or destination specified" 1>&2 + else + $echo "$modename: you must specify a destination" 1>&2 + fi + $echo "$help" 1>&2 + exit 1 + fi + + # Strip any trailing slash from the destination. + dest=`$echo "X$dest" | $Xsed -e 's%/$%%'` + + # Check to see that the destination is a directory. + test -d "$dest" && isdir=yes + if test -n "$isdir"; then + destdir="$dest" + destname= + else + destdir=`$echo "X$dest" | $Xsed -e 's%/[^/]*$%%'` + test "X$destdir" = "X$dest" && destdir=. + destname=`$echo "X$dest" | $Xsed -e 's%^.*/%%'` + + # Not a directory, so check to see that there is only one file specified. + set dummy $files + if test $# -gt 2; then + $echo "$modename: \`$dest' is not a directory" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + fi + case "$destdir" in + /* | [A-Za-z]:\\*) ;; + *) + for file in $files; do + case "$file" in + *.lo) ;; + *) + $echo "$modename: \`$destdir' must be an absolute directory name" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; + esac + done + ;; + esac + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + staticlibs= + future_libdirs= + current_libdirs= + for file in $files; do + + # Do each installation. + case "$file" in + *.a) + # Do the static libraries later. + staticlibs="$staticlibs $file" + ;; + + *.la) + # Check to see that this really is a libtool archive. + if (sed -e '2q' $file | egrep '^# Generated by ltmain\.sh') >/dev/null 2>&1; then : + else + $echo "$modename: \`$file' is not a valid libtool archive" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + library_names= + old_library= + # If there is no directory component, then add one. + case "$file" in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Add the libdir to current_libdirs if it is the destination. + if test "X$destdir" = "X$libdir"; then + case "$current_libdirs " in + *" $libdir "*) ;; + *) current_libdirs="$current_libdirs $libdir" ;; + esac + else + # Note the libdir as a future libdir. + case "$future_libdirs " in + *" $libdir "*) ;; + *) future_libdirs="$future_libdirs $libdir" ;; + esac + fi + + dir="`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`/" + test "X$dir" = "X$file/" && dir= + dir="$dir$objdir" + + # See the names of the shared library. + set dummy $library_names + if test -n "$2"; then + realname="$2" + shift + shift + + # Install the shared library and build the symlinks. + $show "$install_prog $dir/$realname $destdir/$realname" + $run eval "$install_prog $dir/$realname $destdir/$realname" || exit $? + test "X$dlname" = "X$realname" && dlname= + + if test $# -gt 0; then + # Delete the old symlinks. + rmcmd="$rm" + for linkname + do + rmcmd="$rmcmd $destdir/$linkname" + done + $show "$rmcmd" + $run $rmcmd + + # ... and create new ones. + for linkname + do + test "X$dlname" = "X$linkname" && dlname= + $show "(cd $destdir && $LN_S $realname $linkname)" + $run eval "(cd $destdir && $LN_S $realname $linkname)" + done + fi + + if test -n "$dlname"; then + # Install the dynamically-loadable library. + $show "$install_prog $dir/$dlname $destdir/$dlname" + $run eval "$install_prog $dir/$dlname $destdir/$dlname" || exit $? + fi + + # Do each command in the postinstall commands. + lib="$destdir/$realname" + eval cmds=\"$postinstall_cmds\" + IFS="${IFS= }"; save_ifs="$IFS"; IFS=';' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + + # Install the pseudo-library for information purposes. + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + $show "$install_prog $file $destdir/$name" + $run eval "$install_prog $file $destdir/$name" || exit $? + + # Maybe install the static library, too. + test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library" + ;; + + *.lo) + # Install (i.e. copy) a libtool object. + + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + destfile="$destdir/$destfile" + fi + + # Deduce the name of the destination old-style object file. + case "$destfile" in + *.lo) + staticdest=`$echo "X$destfile" | $Xsed -e 's/\.lo$/\.o/'` + ;; + *.o) + staticdest="$destfile" + destfile= + ;; + *) + $echo "$modename: cannot copy a libtool object to \`$destfile'" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; + esac + + # Install the libtool object if requested. + if test -n "$destfile"; then + $show "$install_prog $file $destfile" + $run eval "$install_prog $file $destfile" || exit $? + fi + + # Install the old object if enabled. + if test "$build_old_libs" = yes; then + # Deduce the name of the old-style object file. + staticobj=`$echo "X$file" | $Xsed -e 's/\.lo$/\.o/'` + + $show "$install_prog $staticobj $staticdest" + $run eval "$install_prog \$staticobj \$staticdest" || exit $? + fi + exit 0 + ;; + + *) + # Do a test to see if this is really a libtool program. + if (sed -e '4q' $file | egrep '^# Generated by ltmain\.sh') >/dev/null 2>&1; then + link_against_libtool_libs= + finalize_command= + + # If there is no directory component, then add one. + case "$file" in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Check the variables that should have been set. + if test -z "$link_against_libtool_libs" || test -z "$finalize_command"; then + $echo "$modename: invalid libtool wrapper script \`$file'" 1>&2 + exit 1 + fi + + finalize=yes + for lib in $link_against_libtool_libs; do + # Check to see that each library is installed. + libdir= + if test -f "$lib"; then + # If there is no directory component, then add one. + case "$lib" in + */* | *\\*) . $lib ;; + *) . ./$lib ;; + esac + fi + libfile="$libdir/`$echo "X$lib" | $Xsed -e 's%^.*/%%g'`" + if test -z "$libdir"; then + $echo "$modename: warning: \`$lib' contains no -rpath information" 1>&2 + elif test -f "$libfile"; then : + else + $echo "$modename: warning: \`$lib' has not been installed in \`$libdir'" 1>&2 + finalize=no + fi + done + + if test "$hardcode_action" = relink; then + if test "$finalize" = yes; then + $echo "$modename: warning: relinking \`$file' on behalf of your buggy system linker" 1>&2 + $show "$finalize_command" + if $run eval "$finalize_command"; then : + else + $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2 + continue + fi + file="$objdir/$file"T + else + $echo "$modename: warning: cannot relink \`$file' on behalf of your buggy system linker" 1>&2 + fi + else + # Install the binary that we compiled earlier. + file=`$echo "X$file" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"` + fi + fi + + $show "$install_prog$stripme $file $dest" + $run eval "$install_prog\$stripme \$file \$dest" || exit $? + ;; + esac + done + + for file in $staticlibs; do + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + + # Set up the ranlib parameters. + oldlib="$destdir/$name" + + $show "$install_prog $file $oldlib" + $run eval "$install_prog \$file \$oldlib" || exit $? + + # Do each command in the postinstall commands. + eval cmds=\"$old_postinstall_cmds\" + IFS="${IFS= }"; save_ifs="$IFS"; IFS=';' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + done + + if test -n "$future_libdirs"; then + $echo "$modename: warning: remember to run \`$progname --finish$future_libdirs'" 1>&2 + fi + + if test -n "$current_libdirs"; then + # Maybe just do a dry run. + test -n "$run" && current_libdirs=" -n$current_libdirs" + exec $SHELL $0 --finish$current_libdirs + exit 1 + fi + + exit 0 + ;; + + # libtool finish mode + finish) + modename="$modename: finish" + libdirs="$nonopt" + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + for dir + do + libdirs="$libdirs $dir" + done + + for libdir in $libdirs; do + if test -n "$finish_cmds"; then + # Do each command in the finish commands. + eval cmds=\"$finish_cmds\" + IFS="${IFS= }"; save_ifs="$IFS"; IFS=';' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" + done + IFS="$save_ifs" + fi + if test -n "$finish_eval"; then + # Do the single finish_eval. + eval cmds=\"$finish_eval\" + $run eval "$cmds" + fi + done + fi + + echo "------------------------------------------------------------------------------" + echo "Libraries have been installed in:" + for libdir in $libdirs; do + echo " $libdir" + done + echo + echo "To link against installed libraries in a given directory, LIBDIR," + echo "you must use the \`-LLIBDIR' flag during linking." + echo + echo " You will also need to do one of the following:" + if test -n "$shlibpath_var"; then + echo " - add LIBDIR to the \`$shlibpath_var' environment variable" + echo " during execution" + fi + if test -n "$runpath_var"; then + echo " - add LIBDIR to the \`$runpath_var' environment variable" + echo " during linking" + fi + if test -n "$hardcode_libdir_flag_spec"; then + libdir=LIBDIR + eval flag=\"$hardcode_libdir_flag_spec\" + + echo " - use the \`$flag' linker flag" + fi + if test -f /etc/ld.so.conf; then + echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" + fi + echo + echo "See any operating system documentation about shared libraries for" + echo "more information, such as the ld(1) and ld.so(8) manual pages." + echo "------------------------------------------------------------------------------" + exit 0 + ;; + + # libtool execute mode + execute) + modename="$modename: execute" + + # The first argument is the command name. + cmd="$nonopt" + if test -z "$cmd"; then + $echo "$modename: you must specify a COMMAND" 1>&2 + $echo "$help" + exit 1 + fi + + # Handle -dlopen flags immediately. + for file in $execute_dlfiles; do + if test -f "$file"; then : + else + $echo "$modename: \`$file' is not a file" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + dir= + case "$file" in + *.la) + # Check to see that this really is a libtool archive. + if (sed -e '2q' $file | egrep '^# Generated by ltmain\.sh') >/dev/null 2>&1; then : + else + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + # Read the libtool library. + dlname= + library_names= + + # If there is no directory component, then add one. + case "$file" in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Skip this library if it cannot be dlopened. + if test -z "$dlname"; then + # Warn if it was a shared library. + test -n "$library_names" && $echo "$modename: warning: \`$file' was not linked with \`-export-dynamic'" + continue + fi + + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$file" && dir=. + + if test -f "$dir/$objdir/$dlname"; then + dir="$dir/$objdir" + else + $echo "$modename: cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" 1>&2 + exit 1 + fi + ;; + + *.lo) + # Just add the directory containing the .lo file. + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$file" && dir=. + ;; + + *) + $echo "$modename: warning \`-dlopen' is ignored for non-libtool libraries and objects" 1>&2 + continue + ;; + esac + + # Get the absolute pathname. + absdir=`cd "$dir" && pwd` + test -n "$absdir" && dir="$absdir" + + # Now add the directory to shlibpath_var. + if eval "test -z \"\$$shlibpath_var\""; then + eval "$shlibpath_var=\"\$dir\"" + else + eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" + fi + done + + # This variable tells wrapper scripts just to set shlibpath_var + # rather than running their programs. + libtool_execute_magic="$magic" + + # Check if any of the arguments is a wrapper script. + args= + for file + do + case "$file" in + -*) ;; + *) + # Do a test to see if this is really a libtool program. + if (sed -e '4q' $file | egrep '^# Generated by ltmain\.sh') >/dev/null 2>&1; then + # If there is no directory component, then add one. + case "$file" in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Transform arg to wrapped name. + file="$progdir/$program" + fi + ;; + esac + # Quote arguments (to preserve shell metacharacters). + file=`$echo "X$file" | $Xsed -e "$sed_quote_subst"` + args="$args \"$file\"" + done + + if test -z "$run"; then + # Export the shlibpath_var. + eval "export $shlibpath_var" + + # Now actually exec the command. + eval "exec \$cmd$args" + + $echo "$modename: cannot exec \$cmd$args" + exit 1 + else + # Display what would be done. + eval "\$echo \"\$shlibpath_var=\$$shlibpath_var\"" + $echo "export $shlibpath_var" + $echo "$cmd$args" + exit 0 + fi + ;; + + # libtool uninstall mode + uninstall) + modename="$modename: uninstall" + rm="$nonopt" + files= + + for arg + do + case "$arg" in + -*) rm="$rm $arg" ;; + *) files="$files $arg" ;; + esac + done + + if test -z "$rm"; then + $echo "$modename: you must specify an RM program" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + for file in $files; do + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$file" && dir=. + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + + rmfiles="$file" + + case "$name" in + *.la) + # Possibly a libtool archive, so verify it. + if (sed -e '2q' $file | egrep '^# Generated by ltmain\.sh') >/dev/null 2>&1; then + . $dir/$name + + # Delete the libtool libraries and symlinks. + for n in $library_names; do + rmfiles="$rmfiles $dir/$n" + test "X$n" = "X$dlname" && dlname= + done + test -n "$dlname" && rmfiles="$rmfiles $dir/$dlname" + test -n "$old_library" && rmfiles="$rmfiles $dir/$old_library" + + $show "$rm $rmfiles" + $run $rm $rmfiles + + if test -n "$library_names"; then + # Do each command in the postuninstall commands. + eval cmds=\"$postuninstall_cmds\" + IFS="${IFS= }"; save_ifs="$IFS"; IFS=';' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" + done + IFS="$save_ifs" + fi + + if test -n "$old_library"; then + # Do each command in the old_postuninstall commands. + eval cmds=\"$old_postuninstall_cmds\" + IFS="${IFS= }"; save_ifs="$IFS"; IFS=';' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" + done + IFS="$save_ifs" + fi + + # FIXME: should reinstall the best remaining shared library. + fi + ;; + + *.lo) + if test "$build_old_libs" = yes; then + oldobj=`$echo "X$name" | $Xsed -e 's/\.lo$/\.o/'` + rmfiles="$rmfiles $dir/$oldobj" + fi + $show "$rm $rmfiles" + $run $rm $rmfiles + ;; + + *) + $show "$rm $rmfiles" + $run $rm $rmfiles + ;; + esac + done + exit 0 + ;; + + "") + $echo "$modename: you must specify a MODE" 1>&2 + $echo "$generic_help" 1>&2 + exit 1 + ;; + esac + + $echo "$modename: invalid operation mode \`$mode'" 1>&2 + $echo "$generic_help" 1>&2 + exit 1 +fi # test -z "$show_help" + +# We need to display help for each of the modes. +case "$mode" in +"") $echo \ +"Usage: $modename [OPTION]... [MODE-ARG]... + +Provide generalized library-building support services. + +-n, --dry-run display commands without modifying any files + --features display configuration information and exit + --finish same as \`--mode=finish' + --help display this help message and exit + --mode=MODE use operation mode MODE [default=inferred from MODE-ARGS] + --quiet same as \`--silent' + --silent don't print informational messages + --version print version information + +MODE must be one of the following: + + compile compile a source file into a libtool object + execute automatically set library path, then run a program + finish complete the installation of libtool libraries + install install libraries or executables + link create a library or an executable + uninstall remove libraries from an installed directory + +MODE-ARGS vary depending on the MODE. Try \`$modename --help --mode=MODE' for +a more detailed description of MODE." + exit 0 + ;; + +compile) + $echo \ +"Usage: $modename [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE + +Compile a source file into a libtool library object. + +COMPILE-COMMAND is a command to be used in creating a \`standard' object file +from the given SOURCEFILE. + +The output file name is determined by removing the directory component from +SOURCEFILE, then substituting the C source code suffix \`.c' with the +library object suffix, \`.lo'." + ;; + +execute) + $echo \ +"Usage: $modename [OPTION]... --mode=execute COMMAND [ARGS]... + +Automatically set library path, then run a program. + +This mode accepts the following additional options: + + -dlopen FILE add the directory containing FILE to the library path + +This mode sets the library path environment variable according to \`-dlopen' +flags. + +If any of the ARGS are libtool executable wrappers, then they are translated +into their corresponding uninstalled binary, and any of their required library +directories are added to the library path. + +Then, COMMAND is executed, with ARGS as arguments." + ;; + +finish) + $echo \ +"Usage: $modename [OPTION]... --mode=finish [LIBDIR]... + +Complete the installation of libtool libraries. + +Each LIBDIR is a directory that contains libtool libraries. + +The commands that this mode executes may require superuser privileges. Use +the \`--dry-run' option if you just want to see what would be executed." + ;; + +install) + $echo \ +"Usage: $modename [OPTION]... --mode=install INSTALL-COMMAND... + +Install executables or libraries. + +INSTALL-COMMAND is the installation command. The first component should be +either the \`install' or \`cp' program. + +The rest of the components are interpreted as arguments to that command (only +BSD-compatible install options are recognized)." + ;; + +link) + $echo \ +"Usage: $modename [OPTION]... --mode=link LINK-COMMAND... + +Link object files or libraries together to form another library, or to +create an executable program. + +LINK-COMMAND is a command using the C compiler that you would use to create +a program from several object files. + +The following components of LINK-COMMAND are treated specially: + + -all-static do not do any dynamic linking at all + -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime + -dlpreopen FILE link in FILE and add its symbols to dld_preloaded_symbols + -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) + -LLIBDIR search LIBDIR for required installed libraries + -lNAME OUTPUT-FILE requires the installed library libNAME + -no-undefined declare that a library does not refer to external symbols + -o OUTPUT-FILE create OUTPUT-FILE from the specified objects + -release RELEASE specify package release information + -rpath LIBDIR the created library will eventually be installed in LIBDIR + -static do not do any dynamic linking of libtool libraries + -version-info CURRENT[:REVISION[:AGE]] + specify library version info [each variable defaults to 0] + +All other options (arguments beginning with \`-') are ignored. + +Every other argument is treated as a filename. Files ending in \`.la' are +treated as uninstalled libtool libraries, other files are standard or library +object files. + +If the OUTPUT-FILE ends in \`.la', then a libtool library is created, only +library objects (\`.lo' files) may be specified, and \`-rpath' is required. + +If OUTPUT-FILE ends in \`.a', then a standard library is created using \`ar' +and \`ranlib'. + +If OUTPUT-FILE ends in \`.lo' or \`.o', then a reloadable object file is +created, otherwise an executable program is created." + ;; + +uninstall) + $echo +"Usage: $modename [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... + +Remove libraries from an installation directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, all the files associated with it are deleted. +Otherwise, only FILE itself is deleted using RM." + ;; + +*) + $echo "$modename: invalid operation mode \`$mode'" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; +esac + +echo +$echo "Try \`$modename --help' for more information about other modes." + +exit 0 + +# Local Variables: +# mode:shell-script +# sh-indentation:2 +# End: diff --git a/mk4/modimage/jpeg-6b/makcjpeg.st b/mk4/modimage/jpeg-6b/makcjpeg.st new file mode 100644 index 0000000..fc72c89 --- /dev/null +++ b/mk4/modimage/jpeg-6b/makcjpeg.st @@ -0,0 +1,38 @@ +; Project file for Independent JPEG Group's software +; +; This project file is for Atari ST/STE/TT systems using Pure C or Turbo C. +; Thanks to Frank Moehle (Frank.Moehle@arbi.informatik.uni-oldenburg.de), +; Dr. B. Setzepfandt (bernd@gina.uni-muenster.de), +; and Guido Vollbeding (guivol@esc.de). +; +; To use this file, rename it to cjpeg.prj. +; If you are using Turbo C, change filenames beginning with "pc..." to "tc..." +; Read installation instructions before trying to make the program! +; +; +; * * * Output file * * * +cjpeg.ttp +; +; * * * COMPILER OPTIONS * * * +.C[-P] ; absolute calls +.C[-M] ; and no string merging, folks +.C[-w-cln] ; no "constant is long" warnings +.C[-w-par] ; no "parameter xxxx unused" +.C[-w-rch] ; no "unreachable code" +.C[-wsig] ; warn if significant digits may be lost += +; * * * * List of modules * * * * +pcstart.o +cjpeg.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h,jversion.h) +cdjpeg.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h) +rdswitch.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h) +rdppm.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h) +rdgif.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h) +rdtarga.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h) +rdbmp.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h) +rdrle.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h) +libjpeg.lib ; built by libjpeg.prj +pcfltlib.lib ; floating point library +; the float library can be omitted if you've turned off DCT_FLOAT_SUPPORTED +pcstdlib.lib ; standard library +pcextlib.lib ; extended library diff --git a/mk4/modimage/jpeg-6b/makdjpeg.st b/mk4/modimage/jpeg-6b/makdjpeg.st new file mode 100644 index 0000000..3226726 --- /dev/null +++ b/mk4/modimage/jpeg-6b/makdjpeg.st @@ -0,0 +1,38 @@ +; Project file for Independent JPEG Group's software +; +; This project file is for Atari ST/STE/TT systems using Pure C or Turbo C. +; Thanks to Frank Moehle (Frank.Moehle@arbi.informatik.uni-oldenburg.de), +; Dr. B. Setzepfandt (bernd@gina.uni-muenster.de), +; and Guido Vollbeding (guivol@esc.de). +; +; To use this file, rename it to djpeg.prj. +; If you are using Turbo C, change filenames beginning with "pc..." to "tc..." +; Read installation instructions before trying to make the program! +; +; +; * * * Output file * * * +djpeg.ttp +; +; * * * COMPILER OPTIONS * * * +.C[-P] ; absolute calls +.C[-M] ; and no string merging, folks +.C[-w-cln] ; no "constant is long" warnings +.C[-w-par] ; no "parameter xxxx unused" +.C[-w-rch] ; no "unreachable code" +.C[-wsig] ; warn if significant digits may be lost += +; * * * * List of modules * * * * +pcstart.o +djpeg.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h,jversion.h) +cdjpeg.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h) +rdcolmap.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h) +wrppm.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h) +wrgif.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h) +wrtarga.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h) +wrbmp.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h) +wrrle.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h) +libjpeg.lib ; built by libjpeg.prj +pcfltlib.lib ; floating point library +; the float library can be omitted if you've turned off DCT_FLOAT_SUPPORTED +pcstdlib.lib ; standard library +pcextlib.lib ; extended library diff --git a/mk4/modimage/jpeg-6b/makeapps.ds b/mk4/modimage/jpeg-6b/makeapps.ds new file mode 100644 index 0000000..bedd038 --- /dev/null +++ b/mk4/modimage/jpeg-6b/makeapps.ds @@ -0,0 +1,828 @@ +# Microsoft Developer Studio Generated NMAKE File, Format Version 4.20 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +!IF "$(CFG)" == "" +CFG=cjpeg - Win32 +!MESSAGE No configuration specified. Defaulting to cjpeg - Win32. +!ENDIF + +!IF "$(CFG)" != "cjpeg - Win32" && "$(CFG)" != "djpeg - Win32" &&\ + "$(CFG)" != "jpegtran - Win32" && "$(CFG)" != "rdjpgcom - Win32" &&\ + "$(CFG)" != "wrjpgcom - Win32" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE on this makefile +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "apps.mak" CFG="cjpeg - Win32" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "cjpeg - Win32" (based on "Win32 (x86) Console Application") +!MESSAGE "djpeg - Win32" (based on "Win32 (x86) Console Application") +!MESSAGE "jpegtran - Win32" (based on "Win32 (x86) Console Application") +!MESSAGE "rdjpgcom - Win32" (based on "Win32 (x86) Console Application") +!MESSAGE "wrjpgcom - Win32" (based on "Win32 (x86) Console Application") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF +################################################################################ +# Begin Project +# PROP Target_Last_Scanned "cjpeg - Win32" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "cjpeg - Win32" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "cjpeg\Release" +# PROP BASE Intermediate_Dir "cjpeg\Release" +# PROP BASE Target_Dir "cjpeg" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "cjpeg\Release" +# PROP Intermediate_Dir "cjpeg\Release" +# PROP Target_Dir "cjpeg" +OUTDIR=.\cjpeg\Release +INTDIR=.\cjpeg\Release + +ALL : "$(OUTDIR)\cjpeg.exe" + +CLEAN : + -@erase "$(INTDIR)\cjpeg.obj" + -@erase "$(INTDIR)\rdppm.obj" + -@erase "$(INTDIR)\rdgif.obj" + -@erase "$(INTDIR)\rdtarga.obj" + -@erase "$(INTDIR)\rdrle.obj" + -@erase "$(INTDIR)\rdbmp.obj" + -@erase "$(INTDIR)\rdswitch.obj" + -@erase "$(INTDIR)\cdjpeg.obj" + -@erase "$(OUTDIR)\cjpeg.exe" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c +CPP_PROJ=/nologo /ML /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE"\ + /Fp"$(INTDIR)/cjpeg.pch" /YX /Fo"$(INTDIR)/" /c +CPP_OBJS=.\cjpeg\Release/ +CPP_SBRS=.\. +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o"$(OUTDIR)/cjpeg.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release\jpeg.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +LINK32_FLAGS=Release\jpeg.lib kernel32.lib user32.lib gdi32.lib winspool.lib\ + comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib\ + odbc32.lib odbccp32.lib /nologo /subsystem:console /incremental:no\ + /pdb:"$(OUTDIR)/cjpeg.pdb" /machine:I386 /out:"$(OUTDIR)/cjpeg.exe" +LINK32_OBJS= \ + "$(INTDIR)\cjpeg.obj" \ + "$(INTDIR)\rdppm.obj" \ + "$(INTDIR)\rdgif.obj" \ + "$(INTDIR)\rdtarga.obj" \ + "$(INTDIR)\rdrle.obj" \ + "$(INTDIR)\rdbmp.obj" \ + "$(INTDIR)\rdswitch.obj" \ + "$(INTDIR)\cdjpeg.obj" \ + + +"$(OUTDIR)\cjpeg.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "djpeg - Win32" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "djpeg\Release" +# PROP BASE Intermediate_Dir "djpeg\Release" +# PROP BASE Target_Dir "djpeg" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "djpeg\Release" +# PROP Intermediate_Dir "djpeg\Release" +# PROP Target_Dir "djpeg" +OUTDIR=.\djpeg\Release +INTDIR=.\djpeg\Release + +ALL : "$(OUTDIR)\djpeg.exe" + +CLEAN : + -@erase "$(INTDIR)\djpeg.obj" + -@erase "$(INTDIR)\wrppm.obj" + -@erase "$(INTDIR)\wrgif.obj" + -@erase "$(INTDIR)\wrtarga.obj" + -@erase "$(INTDIR)\wrrle.obj" + -@erase "$(INTDIR)\wrbmp.obj" + -@erase "$(INTDIR)\rdcolmap.obj" + -@erase "$(INTDIR)\cdjpeg.obj" + -@erase "$(OUTDIR)\djpeg.exe" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c +CPP_PROJ=/nologo /ML /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE"\ + /Fp"$(INTDIR)/djpeg.pch" /YX /Fo"$(INTDIR)/" /c +CPP_OBJS=.\djpeg\Release/ +CPP_SBRS=.\. +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o"$(OUTDIR)/djpeg.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release\jpeg.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +LINK32_FLAGS=Release\jpeg.lib kernel32.lib user32.lib gdi32.lib winspool.lib\ + comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib\ + odbc32.lib odbccp32.lib /nologo /subsystem:console /incremental:no\ + /pdb:"$(OUTDIR)/djpeg.pdb" /machine:I386 /out:"$(OUTDIR)/djpeg.exe" +LINK32_OBJS= \ + "$(INTDIR)\djpeg.obj" \ + "$(INTDIR)\wrppm.obj" \ + "$(INTDIR)\wrgif.obj" \ + "$(INTDIR)\wrtarga.obj" \ + "$(INTDIR)\wrrle.obj" \ + "$(INTDIR)\wrbmp.obj" \ + "$(INTDIR)\rdcolmap.obj" \ + "$(INTDIR)\cdjpeg.obj" \ + + +"$(OUTDIR)\djpeg.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "jpegtran - Win32" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "jpegtran\Release" +# PROP BASE Intermediate_Dir "jpegtran\Release" +# PROP BASE Target_Dir "jpegtran" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "jpegtran\Release" +# PROP Intermediate_Dir "jpegtran\Release" +# PROP Target_Dir "jpegtran" +OUTDIR=.\jpegtran\Release +INTDIR=.\jpegtran\Release + +ALL : "$(OUTDIR)\jpegtran.exe" + +CLEAN : + -@erase "$(INTDIR)\jpegtran.obj" + -@erase "$(INTDIR)\rdswitch.obj" + -@erase "$(INTDIR)\cdjpeg.obj" + -@erase "$(INTDIR)\transupp.obj" + -@erase "$(OUTDIR)\jpegtran.exe" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c +CPP_PROJ=/nologo /ML /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE"\ + /Fp"$(INTDIR)/jpegtran.pch" /YX /Fo"$(INTDIR)/" /c +CPP_OBJS=.\jpegtran\Release/ +CPP_SBRS=.\. +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o"$(OUTDIR)/jpegtran.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release\jpeg.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +LINK32_FLAGS=Release\jpeg.lib kernel32.lib user32.lib gdi32.lib winspool.lib\ + comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib\ + odbc32.lib odbccp32.lib /nologo /subsystem:console /incremental:no\ + /pdb:"$(OUTDIR)/jpegtran.pdb" /machine:I386 /out:"$(OUTDIR)/jpegtran.exe" +LINK32_OBJS= \ + "$(INTDIR)\jpegtran.obj" \ + "$(INTDIR)\rdswitch.obj" \ + "$(INTDIR)\cdjpeg.obj" \ + "$(INTDIR)\transupp.obj" \ + + +"$(OUTDIR)\jpegtran.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "rdjpgcom - Win32" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "rdjpgcom\Release" +# PROP BASE Intermediate_Dir "rdjpgcom\Release" +# PROP BASE Target_Dir "rdjpgcom" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "rdjpgcom\Release" +# PROP Intermediate_Dir "rdjpgcom\Release" +# PROP Target_Dir "rdjpgcom" +OUTDIR=.\rdjpgcom\Release +INTDIR=.\rdjpgcom\Release + +ALL : "$(OUTDIR)\rdjpgcom.exe" + +CLEAN : + -@erase "$(INTDIR)\rdjpgcom.obj" + -@erase "$(OUTDIR)\rdjpgcom.exe" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c +CPP_PROJ=/nologo /ML /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE"\ + /Fp"$(INTDIR)/rdjpgcom.pch" /YX /Fo"$(INTDIR)/" /c +CPP_OBJS=.\rdjpgcom\Release/ +CPP_SBRS=.\. +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o"$(OUTDIR)/rdjpgcom.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release\jpeg.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +LINK32_FLAGS=Release\jpeg.lib kernel32.lib user32.lib gdi32.lib winspool.lib\ + comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib\ + odbc32.lib odbccp32.lib /nologo /subsystem:console /incremental:no\ + /pdb:"$(OUTDIR)/rdjpgcom.pdb" /machine:I386 /out:"$(OUTDIR)/rdjpgcom.exe" +LINK32_OBJS= \ + "$(INTDIR)\rdjpgcom.obj" + +"$(OUTDIR)\rdjpgcom.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "wrjpgcom - Win32" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "wrjpgcom\Release" +# PROP BASE Intermediate_Dir "wrjpgcom\Release" +# PROP BASE Target_Dir "wrjpgcom" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "wrjpgcom\Release" +# PROP Intermediate_Dir "wrjpgcom\Release" +# PROP Target_Dir "wrjpgcom" +OUTDIR=.\wrjpgcom\Release +INTDIR=.\wrjpgcom\Release + +ALL : "$(OUTDIR)\wrjpgcom.exe" + +CLEAN : + -@erase "$(INTDIR)\wrjpgcom.obj" + -@erase "$(OUTDIR)\wrjpgcom.exe" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c +CPP_PROJ=/nologo /ML /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE"\ + /Fp"$(INTDIR)/wrjpgcom.pch" /YX /Fo"$(INTDIR)/" /c +CPP_OBJS=.\wrjpgcom\Release/ +CPP_SBRS=.\. +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o"$(OUTDIR)/wrjpgcom.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release\jpeg.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +LINK32_FLAGS=Release\jpeg.lib kernel32.lib user32.lib gdi32.lib winspool.lib\ + comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib\ + odbc32.lib odbccp32.lib /nologo /subsystem:console /incremental:no\ + /pdb:"$(OUTDIR)/wrjpgcom.pdb" /machine:I386 /out:"$(OUTDIR)/wrjpgcom.exe" +LINK32_OBJS= \ + "$(INTDIR)\wrjpgcom.obj" + +"$(OUTDIR)\wrjpgcom.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + +.c{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.c{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +################################################################################ +# Begin Target + +# Name "cjpeg - Win32" + +!IF "$(CFG)" == "cjpeg - Win32" + +!ENDIF + +################################################################################ +# Begin Source File + +SOURCE="cjpeg.c" +DEP_CPP_CJPEG=\ + "cdjpeg.h"\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jerror.h"\ + "cderror.h"\ + "jversion.h"\ + + +"$(INTDIR)\cjpeg.obj" : $(SOURCE) $(DEP_CPP_CJPEG) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="cdjpeg.c" +DEP_CPP_CDJPE=\ + "cdjpeg.h"\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jerror.h"\ + "cderror.h"\ + + +"$(INTDIR)\cdjpeg.obj" : $(SOURCE) $(DEP_CPP_CDJPE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="rdswitch.c" +DEP_CPP_RDSWI=\ + "cdjpeg.h"\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jerror.h"\ + "cderror.h"\ + + +"$(INTDIR)\rdswitch.obj" : $(SOURCE) $(DEP_CPP_RDSWI) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="rdppm.c" +DEP_CPP_RDPPM=\ + "cdjpeg.h"\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jerror.h"\ + "cderror.h"\ + + +"$(INTDIR)\rdppm.obj" : $(SOURCE) $(DEP_CPP_RDPPM) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="rdgif.c" +DEP_CPP_RDGIF=\ + "cdjpeg.h"\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jerror.h"\ + "cderror.h"\ + + +"$(INTDIR)\rdgif.obj" : $(SOURCE) $(DEP_CPP_RDGIF) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="rdtarga.c" +DEP_CPP_RDTAR=\ + "cdjpeg.h"\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jerror.h"\ + "cderror.h"\ + + +"$(INTDIR)\rdtarga.obj" : $(SOURCE) $(DEP_CPP_RDTAR) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="rdbmp.c" +DEP_CPP_RDBMP=\ + "cdjpeg.h"\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jerror.h"\ + "cderror.h"\ + + +"$(INTDIR)\rdbmp.obj" : $(SOURCE) $(DEP_CPP_RDBMP) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="rdrle.c" +DEP_CPP_RDRLE=\ + "cdjpeg.h"\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jerror.h"\ + "cderror.h"\ + + +"$(INTDIR)\rdrle.obj" : $(SOURCE) $(DEP_CPP_RDRLE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +# End Target +################################################################################ +# Begin Target + +# Name "djpeg - Win32" + +!IF "$(CFG)" == "djpeg - Win32" + +!ENDIF + +################################################################################ +# Begin Source File + +SOURCE="djpeg.c" +DEP_CPP_DJPEG=\ + "cdjpeg.h"\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jerror.h"\ + "cderror.h"\ + "jversion.h"\ + + +"$(INTDIR)\djpeg.obj" : $(SOURCE) $(DEP_CPP_DJPEG) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="cdjpeg.c" +DEP_CPP_CDJPE=\ + "cdjpeg.h"\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jerror.h"\ + "cderror.h"\ + + +"$(INTDIR)\cdjpeg.obj" : $(SOURCE) $(DEP_CPP_CDJPE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="rdcolmap.c" +DEP_CPP_RDCOL=\ + "cdjpeg.h"\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jerror.h"\ + "cderror.h"\ + + +"$(INTDIR)\rdcolmap.obj" : $(SOURCE) $(DEP_CPP_RDCOL) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="wrppm.c" +DEP_CPP_WRPPM=\ + "cdjpeg.h"\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jerror.h"\ + "cderror.h"\ + + +"$(INTDIR)\wrppm.obj" : $(SOURCE) $(DEP_CPP_WRPPM) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="wrgif.c" +DEP_CPP_WRGIF=\ + "cdjpeg.h"\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jerror.h"\ + "cderror.h"\ + + +"$(INTDIR)\wrgif.obj" : $(SOURCE) $(DEP_CPP_WRGIF) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="wrtarga.c" +DEP_CPP_WRTAR=\ + "cdjpeg.h"\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jerror.h"\ + "cderror.h"\ + + +"$(INTDIR)\wrtarga.obj" : $(SOURCE) $(DEP_CPP_WRTAR) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="wrbmp.c" +DEP_CPP_WRBMP=\ + "cdjpeg.h"\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jerror.h"\ + "cderror.h"\ + + +"$(INTDIR)\wrbmp.obj" : $(SOURCE) $(DEP_CPP_WRBMP) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="wrrle.c" +DEP_CPP_WRRLE=\ + "cdjpeg.h"\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jerror.h"\ + "cderror.h"\ + + +"$(INTDIR)\wrrle.obj" : $(SOURCE) $(DEP_CPP_WRRLE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +# End Target +################################################################################ +# Begin Target + +# Name "jpegtran - Win32" + +!IF "$(CFG)" == "jpegtran - Win32" + +!ENDIF + +################################################################################ +# Begin Source File + +SOURCE="jpegtran.c" +DEP_CPP_JPEGT=\ + "cdjpeg.h"\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jerror.h"\ + "cderror.h"\ + "transupp.h"\ + "jversion.h"\ + + +"$(INTDIR)\jpegtran.obj" : $(SOURCE) $(DEP_CPP_JPEGT) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="cdjpeg.c" +DEP_CPP_CDJPE=\ + "cdjpeg.h"\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jerror.h"\ + "cderror.h"\ + + +"$(INTDIR)\cdjpeg.obj" : $(SOURCE) $(DEP_CPP_CDJPE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="rdswitch.c" +DEP_CPP_RDSWI=\ + "cdjpeg.h"\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jerror.h"\ + "cderror.h"\ + + +"$(INTDIR)\rdswitch.obj" : $(SOURCE) $(DEP_CPP_RDSWI) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="transupp.c" +DEP_CPP_TRANS=\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jpegint.h"\ + "jerror.h"\ + "transupp.h"\ + + +"$(INTDIR)\transupp.obj" : $(SOURCE) $(DEP_CPP_TRANS) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +# End Target +################################################################################ +# Begin Target + +# Name "rdjpgcom - Win32" + +!IF "$(CFG)" == "rdjpgcom - Win32" + +!ENDIF + +################################################################################ +# Begin Source File + +SOURCE="rdjpgcom.c" +DEP_CPP_RDJPG=\ + "jinclude.h"\ + "jconfig.h"\ + + +"$(INTDIR)\rdjpgcom.obj" : $(SOURCE) $(DEP_CPP_RDJPG) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +# End Target +################################################################################ +# Begin Target + +# Name "wrjpgcom - Win32" + +!IF "$(CFG)" == "wrjpgcom - Win32" + +!ENDIF + +################################################################################ +# Begin Source File + +SOURCE="wrjpgcom.c" +DEP_CPP_WRJPG=\ + "jinclude.h"\ + "jconfig.h"\ + + +"$(INTDIR)\wrjpgcom.obj" : $(SOURCE) $(DEP_CPP_WRJPG) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +# End Target +# End Project +################################################################################ + diff --git a/mk4/modimage/jpeg-6b/makefile.ansi b/mk4/modimage/jpeg-6b/makefile.ansi new file mode 100644 index 0000000..be835d8 --- /dev/null +++ b/mk4/modimage/jpeg-6b/makefile.ansi @@ -0,0 +1,214 @@ +# Makefile for Independent JPEG Group's software + +# This makefile is suitable for Unix-like systems with ANSI-capable compilers. +# If you have a non-ANSI compiler, makefile.unix is a better starting point. + +# Read installation instructions before saying "make" !! + +# The name of your C compiler: +CC= cc + +# You may need to adjust these cc options: +CFLAGS= -O -xarch=v9a +# Generally, we recommend defining any configuration symbols in jconfig.h, +# NOT via -D switches here. + +# Link-time cc options: +LDFLAGS= + +# To link any special libraries, add the necessary -l commands here. +LDLIBS= + +# Put here the object file name for the correct system-dependent memory +# manager file. For Unix this is usually jmemnobs.o, but you may want +# to use jmemansi.o or jmemname.o if you have limited swap space. +SYSDEPMEM= jmemnobs.o + +# miscellaneous OS-dependent stuff +# linker +LN= $(CC) +# file deletion command +RM= rm -f +# library (.a) file creation command +AR= ar rc +# second step in .a creation (use "touch" if not needed) +AR2= ranlib + +# End of configurable options. + + +# source files: JPEG library proper +LIBSOURCES= jcapimin.c jcapistd.c jccoefct.c jccolor.c jcdctmgr.c jchuff.c \ + jcinit.c jcmainct.c jcmarker.c jcmaster.c jcomapi.c jcparam.c \ + jcphuff.c jcprepct.c jcsample.c jctrans.c jdapimin.c jdapistd.c \ + jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c jddctmgr.c jdhuff.c \ + jdinput.c jdmainct.c jdmarker.c jdmaster.c jdmerge.c jdphuff.c \ + jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c jfdctfst.c \ + jfdctint.c jidctflt.c jidctfst.c jidctint.c jidctred.c jquant1.c \ + jquant2.c jutils.c jmemmgr.c +# memmgr back ends: compile only one of these into a working library +SYSDEPSOURCES= jmemansi.c jmemname.c jmemnobs.c jmemdos.c jmemmac.c +# source files: cjpeg/djpeg/jpegtran applications, also rdjpgcom/wrjpgcom +APPSOURCES= cjpeg.c djpeg.c jpegtran.c rdjpgcom.c wrjpgcom.c cdjpeg.c \ + rdcolmap.c rdswitch.c transupp.c rdppm.c wrppm.c rdgif.c wrgif.c \ + rdtarga.c wrtarga.c rdbmp.c wrbmp.c rdrle.c wrrle.c +SOURCES= $(LIBSOURCES) $(SYSDEPSOURCES) $(APPSOURCES) +# files included by source files +INCLUDES= jchuff.h jdhuff.h jdct.h jerror.h jinclude.h jmemsys.h jmorecfg.h \ + jpegint.h jpeglib.h jversion.h cdjpeg.h cderror.h transupp.h +# documentation, test, and support files +DOCS= README install.doc usage.doc cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 \ + wrjpgcom.1 wizard.doc example.c libjpeg.doc structure.doc \ + coderules.doc filelist.doc change.log +MKFILES= configure makefile.cfg makefile.ansi makefile.unix makefile.bcc \ + makefile.mc6 makefile.dj makefile.wat makefile.vc makelib.ds \ + makeapps.ds makeproj.mac makcjpeg.st makdjpeg.st makljpeg.st \ + maktjpeg.st makefile.manx makefile.sas makefile.mms makefile.vms \ + makvms.opt +CONFIGFILES= jconfig.cfg jconfig.bcc jconfig.mc6 jconfig.dj jconfig.wat \ + jconfig.vc jconfig.mac jconfig.st jconfig.manx jconfig.sas \ + jconfig.vms +CONFIGUREFILES= config.guess config.sub install-sh ltconfig ltmain.sh +OTHERFILES= jconfig.doc ckconfig.c ansi2knr.c ansi2knr.1 jmemdosa.asm +TESTFILES= testorig.jpg testimg.ppm testimg.bmp testimg.jpg testprog.jpg \ + testimgp.jpg +DISTFILES= $(DOCS) $(MKFILES) $(CONFIGFILES) $(SOURCES) $(INCLUDES) \ + $(CONFIGUREFILES) $(OTHERFILES) $(TESTFILES) +# library object files common to compression and decompression +COMOBJECTS= jcomapi.o jutils.o jerror.o jmemmgr.o $(SYSDEPMEM) +# compression library object files +CLIBOBJECTS= jcapimin.o jcapistd.o jctrans.o jcparam.o jdatadst.o jcinit.o \ + jcmaster.o jcmarker.o jcmainct.o jcprepct.o jccoefct.o jccolor.o \ + jcsample.o jchuff.o jcphuff.o jcdctmgr.o jfdctfst.o jfdctflt.o \ + jfdctint.o +# decompression library object files +DLIBOBJECTS= jdapimin.o jdapistd.o jdtrans.o jdatasrc.o jdmaster.o \ + jdinput.o jdmarker.o jdhuff.o jdphuff.o jdmainct.o jdcoefct.o \ + jdpostct.o jddctmgr.o jidctfst.o jidctflt.o jidctint.o jidctred.o \ + jdsample.o jdcolor.o jquant1.o jquant2.o jdmerge.o +# These objectfiles are included in libjpeg.a +LIBOBJECTS= $(CLIBOBJECTS) $(DLIBOBJECTS) $(COMOBJECTS) +# object files for sample applications (excluding library files) +COBJECTS= cjpeg.o rdppm.o rdgif.o rdtarga.o rdrle.o rdbmp.o rdswitch.o \ + cdjpeg.o +DOBJECTS= djpeg.o wrppm.o wrgif.o wrtarga.o wrrle.o wrbmp.o rdcolmap.o \ + cdjpeg.o +TROBJECTS= jpegtran.o rdswitch.o cdjpeg.o transupp.o + + +all: libjpeg.a cjpeg djpeg jpegtran rdjpgcom wrjpgcom + +libjpeg.a: $(LIBOBJECTS) + $(RM) libjpeg.a + $(AR) libjpeg.a $(LIBOBJECTS) + $(AR2) libjpeg.a + +cjpeg: $(COBJECTS) libjpeg.a + $(LN) $(LDFLAGS) -o cjpeg $(COBJECTS) libjpeg.a $(LDLIBS) + +djpeg: $(DOBJECTS) libjpeg.a + $(LN) $(LDFLAGS) -o djpeg $(DOBJECTS) libjpeg.a $(LDLIBS) + +jpegtran: $(TROBJECTS) libjpeg.a + $(LN) $(LDFLAGS) -o jpegtran $(TROBJECTS) libjpeg.a $(LDLIBS) + +rdjpgcom: rdjpgcom.o + $(LN) $(LDFLAGS) -o rdjpgcom rdjpgcom.o $(LDLIBS) + +wrjpgcom: wrjpgcom.o + $(LN) $(LDFLAGS) -o wrjpgcom wrjpgcom.o $(LDLIBS) + +jconfig.h: jconfig.doc + echo You must prepare a system-dependent jconfig.h file. + echo Please read the installation directions in install.doc. + exit 1 + +clean: + $(RM) *.o cjpeg djpeg jpegtran libjpeg.a rdjpgcom wrjpgcom + $(RM) core testout* + +test: cjpeg djpeg jpegtran + $(RM) testout* + ./djpeg -dct int -ppm -outfile testout.ppm testorig.jpg + ./djpeg -dct int -bmp -colors 256 -outfile testout.bmp testorig.jpg + ./cjpeg -dct int -outfile testout.jpg testimg.ppm + ./djpeg -dct int -ppm -outfile testoutp.ppm testprog.jpg + ./cjpeg -dct int -progressive -opt -outfile testoutp.jpg testimg.ppm + ./jpegtran -outfile testoutt.jpg testprog.jpg + cmp testimg.ppm testout.ppm + cmp testimg.bmp testout.bmp + cmp testimg.jpg testout.jpg + cmp testimg.ppm testoutp.ppm + cmp testimgp.jpg testoutp.jpg + cmp testorig.jpg testoutt.jpg + + +jcapimin.o: jcapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcapistd.o: jcapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jccoefct.o: jccoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jccolor.o: jccolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcdctmgr.o: jcdctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jchuff.o: jchuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jchuff.h +jcinit.o: jcinit.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcmainct.o: jcmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcmarker.o: jcmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcmaster.o: jcmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcomapi.o: jcomapi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcparam.o: jcparam.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcphuff.o: jcphuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jchuff.h +jcprepct.o: jcprepct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcsample.o: jcsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jctrans.o: jctrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdapimin.o: jdapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdapistd.o: jdapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdatadst.o: jdatadst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h +jdatasrc.o: jdatasrc.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h +jdcoefct.o: jdcoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdcolor.o: jdcolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jddctmgr.o: jddctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jdhuff.o: jdhuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdhuff.h +jdinput.o: jdinput.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdmainct.o: jdmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdmarker.o: jdmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdmaster.o: jdmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdmerge.o: jdmerge.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdphuff.o: jdphuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdhuff.h +jdpostct.o: jdpostct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdsample.o: jdsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdtrans.o: jdtrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jerror.o: jerror.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jversion.h jerror.h +jfdctflt.o: jfdctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jfdctfst.o: jfdctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jfdctint.o: jfdctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jidctflt.o: jidctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jidctfst.o: jidctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jidctint.o: jidctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jidctred.o: jidctred.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jquant1.o: jquant1.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jquant2.o: jquant2.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jutils.o: jutils.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jmemmgr.o: jmemmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +jmemansi.o: jmemansi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +jmemname.o: jmemname.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +jmemnobs.o: jmemnobs.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +jmemdos.o: jmemdos.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +jmemmac.o: jmemmac.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +cjpeg.o: cjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h +djpeg.o: djpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h +jpegtran.o: jpegtran.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h transupp.h jversion.h +rdjpgcom.o: rdjpgcom.c jinclude.h jconfig.h +wrjpgcom.o: wrjpgcom.c jinclude.h jconfig.h +cdjpeg.o: cdjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdcolmap.o: rdcolmap.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdswitch.o: rdswitch.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +transupp.o: transupp.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h transupp.h +rdppm.o: rdppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +wrppm.o: wrppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdgif.o: rdgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +wrgif.o: wrgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdtarga.o: rdtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +wrtarga.o: wrtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdbmp.o: rdbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +wrbmp.o: wrbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdrle.o: rdrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +wrrle.o: wrrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h diff --git a/mk4/modimage/jpeg-6b/makefile.bcc b/mk4/modimage/jpeg-6b/makefile.bcc new file mode 100644 index 0000000..a1cfcde --- /dev/null +++ b/mk4/modimage/jpeg-6b/makefile.bcc @@ -0,0 +1,285 @@ +# Makefile for Independent JPEG Group's software + +# This makefile is suitable for Borland C on MS-DOS or OS/2. +# It works with Borland C++ for DOS, revision 3.0 or later, +# and has been tested with Borland C++ for OS/2. +# Watch out for optimization bugs in the OS/2 compilers --- see notes below! +# Thanks to Tom Wright and Ge' Weijers (original DOS) and +# Ken Porter (OS/2) for this file. + +# Read installation instructions before saying "make" !! + +# Are we under DOS or OS/2? +!if !$d(DOS) && !$d(OS2) +!if $d(__OS2__) +OS2=1 +!else +DOS=1 +!endif +!endif + +# The name of your C compiler: +CC= bcc + +# You may need to adjust these cc options: +!if $d(DOS) +CFLAGS= -O2 -mm -w-par -w-stu -w-ccc -w-rch +!else +CFLAGS= -O1 -w-par -w-stu -w-ccc -w-rch +!endif +# -O2 enables full code optimization (for pre-3.0 Borland C++, use -O -G -Z). +# -O2 is buggy in Borland OS/2 C++ revision 2.0, so use -O1 there for now. +# If you have Borland OS/2 C++ revision 1.0, use -O or no optimization at all. +# -mm selects medium memory model (near data, far code pointers; DOS only!) +# -w-par suppresses warnings about unused function parameters +# -w-stu suppresses warnings about incomplete structures +# -w-ccc suppresses warnings about compile-time-constant conditions +# -w-rch suppresses warnings about unreachable code +# Generally, we recommend defining any configuration symbols in jconfig.h, +# NOT via -D switches here. + +# Link-time cc options: +!if $d(DOS) +LDFLAGS= -mm +# memory model option here must match CFLAGS! +!else +LDFLAGS= +# -lai full-screen app +# -lc case-significant link +!endif + +# Put here the object file name for the correct system-dependent memory +# manager file. +# For DOS, we recommend jmemdos.c and jmemdosa.asm. +# For OS/2, we recommend jmemnobs.c (flat memory!) +# SYSDEPMEMLIB must list the same files with "+" signs for the librarian. +!if $d(DOS) +SYSDEPMEM= jmemdos.obj jmemdosa.obj +SYSDEPMEMLIB= +jmemdos.obj +jmemdosa.obj +!else +SYSDEPMEM= jmemnobs.obj +SYSDEPMEMLIB= +jmemnobs.obj +!endif + +# End of configurable options. + + +# source files: JPEG library proper +LIBSOURCES= jcapimin.c jcapistd.c jccoefct.c jccolor.c jcdctmgr.c jchuff.c \ + jcinit.c jcmainct.c jcmarker.c jcmaster.c jcomapi.c jcparam.c \ + jcphuff.c jcprepct.c jcsample.c jctrans.c jdapimin.c jdapistd.c \ + jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c jddctmgr.c jdhuff.c \ + jdinput.c jdmainct.c jdmarker.c jdmaster.c jdmerge.c jdphuff.c \ + jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c jfdctfst.c \ + jfdctint.c jidctflt.c jidctfst.c jidctint.c jidctred.c jquant1.c \ + jquant2.c jutils.c jmemmgr.c +# memmgr back ends: compile only one of these into a working library +SYSDEPSOURCES= jmemansi.c jmemname.c jmemnobs.c jmemdos.c jmemmac.c +# source files: cjpeg/djpeg/jpegtran applications, also rdjpgcom/wrjpgcom +APPSOURCES= cjpeg.c djpeg.c jpegtran.c rdjpgcom.c wrjpgcom.c cdjpeg.c \ + rdcolmap.c rdswitch.c transupp.c rdppm.c wrppm.c rdgif.c wrgif.c \ + rdtarga.c wrtarga.c rdbmp.c wrbmp.c rdrle.c wrrle.c +SOURCES= $(LIBSOURCES) $(SYSDEPSOURCES) $(APPSOURCES) +# files included by source files +INCLUDES= jchuff.h jdhuff.h jdct.h jerror.h jinclude.h jmemsys.h jmorecfg.h \ + jpegint.h jpeglib.h jversion.h cdjpeg.h cderror.h transupp.h +# documentation, test, and support files +DOCS= README install.doc usage.doc cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 \ + wrjpgcom.1 wizard.doc example.c libjpeg.doc structure.doc \ + coderules.doc filelist.doc change.log +MKFILES= configure makefile.cfg makefile.ansi makefile.unix makefile.bcc \ + makefile.mc6 makefile.dj makefile.wat makefile.vc makelib.ds \ + makeapps.ds makeproj.mac makcjpeg.st makdjpeg.st makljpeg.st \ + maktjpeg.st makefile.manx makefile.sas makefile.mms makefile.vms \ + makvms.opt +CONFIGFILES= jconfig.cfg jconfig.bcc jconfig.mc6 jconfig.dj jconfig.wat \ + jconfig.vc jconfig.mac jconfig.st jconfig.manx jconfig.sas \ + jconfig.vms +CONFIGUREFILES= config.guess config.sub install-sh ltconfig ltmain.sh +OTHERFILES= jconfig.doc ckconfig.c ansi2knr.c ansi2knr.1 jmemdosa.asm +TESTFILES= testorig.jpg testimg.ppm testimg.bmp testimg.jpg testprog.jpg \ + testimgp.jpg +DISTFILES= $(DOCS) $(MKFILES) $(CONFIGFILES) $(SOURCES) $(INCLUDES) \ + $(CONFIGUREFILES) $(OTHERFILES) $(TESTFILES) +# library object files common to compression and decompression +COMOBJECTS= jcomapi.obj jutils.obj jerror.obj jmemmgr.obj $(SYSDEPMEM) +# compression library object files +CLIBOBJECTS= jcapimin.obj jcapistd.obj jctrans.obj jcparam.obj jdatadst.obj \ + jcinit.obj jcmaster.obj jcmarker.obj jcmainct.obj jcprepct.obj \ + jccoefct.obj jccolor.obj jcsample.obj jchuff.obj jcphuff.obj \ + jcdctmgr.obj jfdctfst.obj jfdctflt.obj jfdctint.obj +# decompression library object files +DLIBOBJECTS= jdapimin.obj jdapistd.obj jdtrans.obj jdatasrc.obj \ + jdmaster.obj jdinput.obj jdmarker.obj jdhuff.obj jdphuff.obj \ + jdmainct.obj jdcoefct.obj jdpostct.obj jddctmgr.obj jidctfst.obj \ + jidctflt.obj jidctint.obj jidctred.obj jdsample.obj jdcolor.obj \ + jquant1.obj jquant2.obj jdmerge.obj +# These objectfiles are included in libjpeg.lib +LIBOBJECTS= $(CLIBOBJECTS) $(DLIBOBJECTS) $(COMOBJECTS) +# object files for sample applications (excluding library files) +COBJECTS= cjpeg.obj rdppm.obj rdgif.obj rdtarga.obj rdrle.obj rdbmp.obj \ + rdswitch.obj cdjpeg.obj +DOBJECTS= djpeg.obj wrppm.obj wrgif.obj wrtarga.obj wrrle.obj wrbmp.obj \ + rdcolmap.obj cdjpeg.obj +TROBJECTS= jpegtran.obj rdswitch.obj cdjpeg.obj transupp.obj + + +all: libjpeg.lib cjpeg.exe djpeg.exe jpegtran.exe rdjpgcom.exe wrjpgcom.exe + +libjpeg.lib: $(LIBOBJECTS) + - del libjpeg.lib + tlib libjpeg.lib /E /C @&&| ++jcapimin.obj +jcapistd.obj +jctrans.obj +jcparam.obj +jdatadst.obj & ++jcinit.obj +jcmaster.obj +jcmarker.obj +jcmainct.obj +jcprepct.obj & ++jccoefct.obj +jccolor.obj +jcsample.obj +jchuff.obj +jcphuff.obj & ++jcdctmgr.obj +jfdctfst.obj +jfdctflt.obj +jfdctint.obj +jdapimin.obj & ++jdapistd.obj +jdtrans.obj +jdatasrc.obj +jdmaster.obj +jdinput.obj & ++jdmarker.obj +jdhuff.obj +jdphuff.obj +jdmainct.obj +jdcoefct.obj & ++jdpostct.obj +jddctmgr.obj +jidctfst.obj +jidctflt.obj +jidctint.obj & ++jidctred.obj +jdsample.obj +jdcolor.obj +jquant1.obj +jquant2.obj & ++jdmerge.obj +jcomapi.obj +jutils.obj +jerror.obj +jmemmgr.obj & +$(SYSDEPMEMLIB) +| + +cjpeg.exe: $(COBJECTS) libjpeg.lib + $(CC) $(LDFLAGS) -ecjpeg.exe $(COBJECTS) libjpeg.lib + +djpeg.exe: $(DOBJECTS) libjpeg.lib + $(CC) $(LDFLAGS) -edjpeg.exe $(DOBJECTS) libjpeg.lib + +jpegtran.exe: $(TROBJECTS) libjpeg.lib + $(CC) $(LDFLAGS) -ejpegtran.exe $(TROBJECTS) libjpeg.lib + +rdjpgcom.exe: rdjpgcom.c +!if $d(DOS) + $(CC) -ms -O rdjpgcom.c +!else + $(CC) $(CFLAGS) rdjpgcom.c +!endif + +# On DOS, wrjpgcom needs large model so it can malloc a 64K chunk +wrjpgcom.exe: wrjpgcom.c +!if $d(DOS) + $(CC) -ml -O wrjpgcom.c +!else + $(CC) $(CFLAGS) wrjpgcom.c +!endif + +# This "{}" syntax allows Borland Make to "batch" source files. +# In this way, each run of the compiler can build many modules. +.c.obj: + $(CC) $(CFLAGS) -c{ $<} + +jconfig.h: jconfig.doc + echo You must prepare a system-dependent jconfig.h file. + echo Please read the installation directions in install.doc. + exit 1 + +clean: + - del *.obj + - del libjpeg.lib + - del cjpeg.exe + - del djpeg.exe + - del jpegtran.exe + - del rdjpgcom.exe + - del wrjpgcom.exe + - del testout*.* + +test: cjpeg.exe djpeg.exe jpegtran.exe + - del testout*.* + djpeg -dct int -ppm -outfile testout.ppm testorig.jpg + djpeg -dct int -bmp -colors 256 -outfile testout.bmp testorig.jpg + cjpeg -dct int -outfile testout.jpg testimg.ppm + djpeg -dct int -ppm -outfile testoutp.ppm testprog.jpg + cjpeg -dct int -progressive -opt -outfile testoutp.jpg testimg.ppm + jpegtran -outfile testoutt.jpg testprog.jpg +!if $d(DOS) + fc /b testimg.ppm testout.ppm + fc /b testimg.bmp testout.bmp + fc /b testimg.jpg testout.jpg + fc /b testimg.ppm testoutp.ppm + fc /b testimgp.jpg testoutp.jpg + fc /b testorig.jpg testoutt.jpg +!else + echo n > n.tmp + comp testimg.ppm testout.ppm < n.tmp + comp testimg.bmp testout.bmp < n.tmp + comp testimg.jpg testout.jpg < n.tmp + comp testimg.ppm testoutp.ppm < n.tmp + comp testimgp.jpg testoutp.jpg < n.tmp + comp testorig.jpg testoutt.jpg < n.tmp + del n.tmp +!endif + + +jcapimin.obj: jcapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcapistd.obj: jcapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jccoefct.obj: jccoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jccolor.obj: jccolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcdctmgr.obj: jcdctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jchuff.obj: jchuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jchuff.h +jcinit.obj: jcinit.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcmainct.obj: jcmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcmarker.obj: jcmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcmaster.obj: jcmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcomapi.obj: jcomapi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcparam.obj: jcparam.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcphuff.obj: jcphuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jchuff.h +jcprepct.obj: jcprepct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcsample.obj: jcsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jctrans.obj: jctrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdapimin.obj: jdapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdapistd.obj: jdapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdatadst.obj: jdatadst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h +jdatasrc.obj: jdatasrc.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h +jdcoefct.obj: jdcoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdcolor.obj: jdcolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jddctmgr.obj: jddctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jdhuff.obj: jdhuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdhuff.h +jdinput.obj: jdinput.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdmainct.obj: jdmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdmarker.obj: jdmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdmaster.obj: jdmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdmerge.obj: jdmerge.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdphuff.obj: jdphuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdhuff.h +jdpostct.obj: jdpostct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdsample.obj: jdsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdtrans.obj: jdtrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jerror.obj: jerror.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jversion.h jerror.h +jfdctflt.obj: jfdctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jfdctfst.obj: jfdctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jfdctint.obj: jfdctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jidctflt.obj: jidctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jidctfst.obj: jidctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jidctint.obj: jidctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jidctred.obj: jidctred.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jquant1.obj: jquant1.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jquant2.obj: jquant2.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jutils.obj: jutils.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jmemmgr.obj: jmemmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +jmemansi.obj: jmemansi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +jmemname.obj: jmemname.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +jmemnobs.obj: jmemnobs.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +jmemdos.obj: jmemdos.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +jmemmac.obj: jmemmac.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +cjpeg.obj: cjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h +djpeg.obj: djpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h +jpegtran.obj: jpegtran.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h transupp.h jversion.h +rdjpgcom.obj: rdjpgcom.c jinclude.h jconfig.h +wrjpgcom.obj: wrjpgcom.c jinclude.h jconfig.h +cdjpeg.obj: cdjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdcolmap.obj: rdcolmap.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdswitch.obj: rdswitch.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +transupp.obj: transupp.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h transupp.h +rdppm.obj: rdppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +wrppm.obj: wrppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdgif.obj: rdgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +wrgif.obj: wrgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdtarga.obj: rdtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +wrtarga.obj: wrtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdbmp.obj: rdbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +wrbmp.obj: wrbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdrle.obj: rdrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +wrrle.obj: wrrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +jmemdosa.obj: jmemdosa.asm + tasm /mx jmemdosa.asm diff --git a/mk4/modimage/jpeg-6b/makefile.cfg b/mk4/modimage/jpeg-6b/makefile.cfg new file mode 100644 index 0000000..f25e42e --- /dev/null +++ b/mk4/modimage/jpeg-6b/makefile.cfg @@ -0,0 +1,319 @@ +# Makefile for Independent JPEG Group's software + +# makefile.cfg is edited by configure to produce a custom Makefile. + +# Read installation instructions before saying "make" !! + +# For compiling with source and object files in different directories. +srcdir = @srcdir@ +VPATH = @srcdir@ + +# Where to install the programs and man pages. +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = $(exec_prefix)/bin +libdir = $(exec_prefix)/lib +includedir = $(prefix)/include +binprefix = +manprefix = +manext = 1 +mandir = $(prefix)/man/man$(manext) + +# The name of your C compiler: +CC= @CC@ + +# You may need to adjust these cc options: +CFLAGS= @CFLAGS@ @CPPFLAGS@ @INCLUDEFLAGS@ +# Generally, we recommend defining any configuration symbols in jconfig.h, +# NOT via -D switches here. +# However, any special defines for ansi2knr.c may be included here: +ANSI2KNRFLAGS= @ANSI2KNRFLAGS@ + +# Link-time cc options: +LDFLAGS= @LDFLAGS@ + +# To link any special libraries, add the necessary -l commands here. +LDLIBS= @LIBS@ + +# If using GNU libtool, LIBTOOL references it; if not, LIBTOOL is empty. +LIBTOOL = @LIBTOOL@ +# $(O) expands to "lo" if using libtool, plain "o" if not. +# Similarly, $(A) expands to "la" or "a". +O = @O@ +A = @A@ + +# Library version ID; libtool uses this for the shared library version number. +# Note: we suggest this match the macro of the same name in jpeglib.h. +JPEG_LIB_VERSION = @JPEG_LIB_VERSION@ + +# Put here the object file name for the correct system-dependent memory +# manager file. For Unix this is usually jmemnobs.o, but you may want +# to use jmemansi.o or jmemname.o if you have limited swap space. +SYSDEPMEM= @MEMORYMGR@ + +# miscellaneous OS-dependent stuff +SHELL= /bin/sh +# linker +LN= @LN@ +# file deletion command +RM= rm -f +# directory creation command +MKDIR= mkdir +# library (.a) file creation command +AR= ar rc +# second step in .a creation (use "touch" if not needed) +AR2= @RANLIB@ +# installation program +INSTALL= @INSTALL@ +INSTALL_PROGRAM= @INSTALL_PROGRAM@ +INSTALL_LIB= @INSTALL_LIB@ +INSTALL_DATA= @INSTALL_DATA@ + +# End of configurable options. + + +# source files: JPEG library proper +LIBSOURCES= jcapimin.c jcapistd.c jccoefct.c jccolor.c jcdctmgr.c jchuff.c \ + jcinit.c jcmainct.c jcmarker.c jcmaster.c jcomapi.c jcparam.c \ + jcphuff.c jcprepct.c jcsample.c jctrans.c jdapimin.c jdapistd.c \ + jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c jddctmgr.c jdhuff.c \ + jdinput.c jdmainct.c jdmarker.c jdmaster.c jdmerge.c jdphuff.c \ + jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c jfdctfst.c \ + jfdctint.c jidctflt.c jidctfst.c jidctint.c jidctred.c jquant1.c \ + jquant2.c jutils.c jmemmgr.c +# memmgr back ends: compile only one of these into a working library +SYSDEPSOURCES= jmemansi.c jmemname.c jmemnobs.c jmemdos.c jmemmac.c +# source files: cjpeg/djpeg/jpegtran applications, also rdjpgcom/wrjpgcom +APPSOURCES= cjpeg.c djpeg.c jpegtran.c rdjpgcom.c wrjpgcom.c cdjpeg.c \ + rdcolmap.c rdswitch.c transupp.c rdppm.c wrppm.c rdgif.c wrgif.c \ + rdtarga.c wrtarga.c rdbmp.c wrbmp.c rdrle.c wrrle.c +SOURCES= $(LIBSOURCES) $(SYSDEPSOURCES) $(APPSOURCES) +# files included by source files +INCLUDES= jchuff.h jdhuff.h jdct.h jerror.h jinclude.h jmemsys.h jmorecfg.h \ + jpegint.h jpeglib.h jversion.h cdjpeg.h cderror.h transupp.h +# documentation, test, and support files +DOCS= README install.doc usage.doc cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 \ + wrjpgcom.1 wizard.doc example.c libjpeg.doc structure.doc \ + coderules.doc filelist.doc change.log +MKFILES= configure makefile.cfg makefile.ansi makefile.unix makefile.bcc \ + makefile.mc6 makefile.dj makefile.wat makefile.vc makelib.ds \ + makeapps.ds makeproj.mac makcjpeg.st makdjpeg.st makljpeg.st \ + maktjpeg.st makefile.manx makefile.sas makefile.mms makefile.vms \ + makvms.opt +CONFIGFILES= jconfig.cfg jconfig.bcc jconfig.mc6 jconfig.dj jconfig.wat \ + jconfig.vc jconfig.mac jconfig.st jconfig.manx jconfig.sas \ + jconfig.vms +CONFIGUREFILES= config.guess config.sub install-sh ltconfig ltmain.sh +OTHERFILES= jconfig.doc ckconfig.c ansi2knr.c ansi2knr.1 jmemdosa.asm +TESTFILES= testorig.jpg testimg.ppm testimg.bmp testimg.jpg testprog.jpg \ + testimgp.jpg +DISTFILES= $(DOCS) $(MKFILES) $(CONFIGFILES) $(SOURCES) $(INCLUDES) \ + $(CONFIGUREFILES) $(OTHERFILES) $(TESTFILES) +# library object files common to compression and decompression +COMOBJECTS= jcomapi.$(O) jutils.$(O) jerror.$(O) jmemmgr.$(O) $(SYSDEPMEM) +# compression library object files +CLIBOBJECTS= jcapimin.$(O) jcapistd.$(O) jctrans.$(O) jcparam.$(O) \ + jdatadst.$(O) jcinit.$(O) jcmaster.$(O) jcmarker.$(O) jcmainct.$(O) \ + jcprepct.$(O) jccoefct.$(O) jccolor.$(O) jcsample.$(O) jchuff.$(O) \ + jcphuff.$(O) jcdctmgr.$(O) jfdctfst.$(O) jfdctflt.$(O) \ + jfdctint.$(O) +# decompression library object files +DLIBOBJECTS= jdapimin.$(O) jdapistd.$(O) jdtrans.$(O) jdatasrc.$(O) \ + jdmaster.$(O) jdinput.$(O) jdmarker.$(O) jdhuff.$(O) jdphuff.$(O) \ + jdmainct.$(O) jdcoefct.$(O) jdpostct.$(O) jddctmgr.$(O) \ + jidctfst.$(O) jidctflt.$(O) jidctint.$(O) jidctred.$(O) \ + jdsample.$(O) jdcolor.$(O) jquant1.$(O) jquant2.$(O) jdmerge.$(O) +# These objectfiles are included in libjpeg.a +LIBOBJECTS= $(CLIBOBJECTS) $(DLIBOBJECTS) $(COMOBJECTS) +# object files for sample applications (excluding library files) +COBJECTS= cjpeg.$(O) rdppm.$(O) rdgif.$(O) rdtarga.$(O) rdrle.$(O) \ + rdbmp.$(O) rdswitch.$(O) cdjpeg.$(O) +DOBJECTS= djpeg.$(O) wrppm.$(O) wrgif.$(O) wrtarga.$(O) wrrle.$(O) \ + wrbmp.$(O) rdcolmap.$(O) cdjpeg.$(O) +TROBJECTS= jpegtran.$(O) rdswitch.$(O) cdjpeg.$(O) transupp.$(O) + + +all: @A2K_DEPS@ libjpeg.$(A) cjpeg djpeg jpegtran rdjpgcom wrjpgcom + +# Special compilation rules to support ansi2knr and libtool. +.SUFFIXES: .lo .la + +# How to compile with libtool. +@COM_LT@.c.lo: +@COM_LT@ $(LIBTOOL) --mode=compile $(CC) $(CFLAGS) -c $(srcdir)/$*.c + +# How to use ansi2knr, when not using libtool. +@COM_A2K@.c.o: +@COM_A2K@ ./ansi2knr $(srcdir)/$*.c knr/$*.c +@COM_A2K@ $(CC) $(CFLAGS) -c knr/$*.c +@COM_A2K@ $(RM) knr/$*.c + +# How to use ansi2knr AND libtool. +@COM_A2K@.c.lo: +@COM_A2K@ ./ansi2knr $(srcdir)/$*.c knr/$*.c +@COM_A2K@ $(LIBTOOL) --mode=compile $(CC) $(CFLAGS) -c knr/$*.c +@COM_A2K@ $(RM) knr/$*.c + +ansi2knr: ansi2knr.c + $(CC) $(CFLAGS) $(ANSI2KNRFLAGS) -o ansi2knr $(srcdir)/ansi2knr.c + $(MKDIR) knr + +# the library: + +# without libtool: +libjpeg.a: @A2K_DEPS@ $(LIBOBJECTS) + $(RM) libjpeg.a + $(AR) libjpeg.a $(LIBOBJECTS) + $(AR2) libjpeg.a + +# with libtool: +libjpeg.la: @A2K_DEPS@ $(LIBOBJECTS) + $(LIBTOOL) --mode=link $(CC) -o libjpeg.la $(LIBOBJECTS) \ + -rpath $(libdir) -version-info $(JPEG_LIB_VERSION) + +# sample programs: + +cjpeg: $(COBJECTS) libjpeg.$(A) + $(LN) $(LDFLAGS) -o cjpeg $(COBJECTS) libjpeg.$(A) $(LDLIBS) + +djpeg: $(DOBJECTS) libjpeg.$(A) + $(LN) $(LDFLAGS) -o djpeg $(DOBJECTS) libjpeg.$(A) $(LDLIBS) + +jpegtran: $(TROBJECTS) libjpeg.$(A) + $(LN) $(LDFLAGS) -o jpegtran $(TROBJECTS) libjpeg.$(A) $(LDLIBS) + +rdjpgcom: rdjpgcom.$(O) + $(LN) $(LDFLAGS) -o rdjpgcom rdjpgcom.$(O) $(LDLIBS) + +wrjpgcom: wrjpgcom.$(O) + $(LN) $(LDFLAGS) -o wrjpgcom wrjpgcom.$(O) $(LDLIBS) + +# Installation rules: + +install: cjpeg djpeg jpegtran rdjpgcom wrjpgcom @FORCE_INSTALL_LIB@ + $(INSTALL_PROGRAM) cjpeg $(bindir)/$(binprefix)cjpeg + $(INSTALL_PROGRAM) djpeg $(bindir)/$(binprefix)djpeg + $(INSTALL_PROGRAM) jpegtran $(bindir)/$(binprefix)jpegtran + $(INSTALL_PROGRAM) rdjpgcom $(bindir)/$(binprefix)rdjpgcom + $(INSTALL_PROGRAM) wrjpgcom $(bindir)/$(binprefix)wrjpgcom + $(INSTALL_DATA) $(srcdir)/cjpeg.1 $(mandir)/$(manprefix)cjpeg.$(manext) + $(INSTALL_DATA) $(srcdir)/djpeg.1 $(mandir)/$(manprefix)djpeg.$(manext) + $(INSTALL_DATA) $(srcdir)/jpegtran.1 $(mandir)/$(manprefix)jpegtran.$(manext) + $(INSTALL_DATA) $(srcdir)/rdjpgcom.1 $(mandir)/$(manprefix)rdjpgcom.$(manext) + $(INSTALL_DATA) $(srcdir)/wrjpgcom.1 $(mandir)/$(manprefix)wrjpgcom.$(manext) + +install-lib: libjpeg.$(A) install-headers + $(INSTALL_LIB) libjpeg.$(A) $(libdir)/$(binprefix)libjpeg.$(A) + +install-headers: jconfig.h + $(INSTALL_DATA) jconfig.h $(includedir)/jconfig.h + $(INSTALL_DATA) $(srcdir)/jpeglib.h $(includedir)/jpeglib.h + $(INSTALL_DATA) $(srcdir)/jmorecfg.h $(includedir)/jmorecfg.h + $(INSTALL_DATA) $(srcdir)/jerror.h $(includedir)/jerror.h + +clean: + $(RM) *.o *.lo libjpeg.a libjpeg.la + $(RM) cjpeg djpeg jpegtran rdjpgcom wrjpgcom + $(RM) ansi2knr core testout* config.log config.status + $(RM) -r knr .libs _libs + +distclean: clean + $(RM) Makefile jconfig.h libtool config.cache + +test: cjpeg djpeg jpegtran + $(RM) testout* + ./djpeg -dct int -ppm -outfile testout.ppm $(srcdir)/testorig.jpg + ./djpeg -dct int -bmp -colors 256 -outfile testout.bmp $(srcdir)/testorig.jpg + ./cjpeg -dct int -outfile testout.jpg $(srcdir)/testimg.ppm + ./djpeg -dct int -ppm -outfile testoutp.ppm $(srcdir)/testprog.jpg + ./cjpeg -dct int -progressive -opt -outfile testoutp.jpg $(srcdir)/testimg.ppm + ./jpegtran -outfile testoutt.jpg $(srcdir)/testprog.jpg + cmp $(srcdir)/testimg.ppm testout.ppm + cmp $(srcdir)/testimg.bmp testout.bmp + cmp $(srcdir)/testimg.jpg testout.jpg + cmp $(srcdir)/testimg.ppm testoutp.ppm + cmp $(srcdir)/testimgp.jpg testoutp.jpg + cmp $(srcdir)/testorig.jpg testoutt.jpg + +check: test + +# Mistake catcher: + +jconfig.h: jconfig.doc + echo You must prepare a system-dependent jconfig.h file. + echo Please read the installation directions in install.doc. + exit 1 + +# GNU Make likes to know which target names are not really files to be made: +.PHONY: all install install-lib install-headers clean distclean test check + + +jcapimin.$(O): jcapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcapistd.$(O): jcapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jccoefct.$(O): jccoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jccolor.$(O): jccolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcdctmgr.$(O): jcdctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jchuff.$(O): jchuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jchuff.h +jcinit.$(O): jcinit.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcmainct.$(O): jcmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcmarker.$(O): jcmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcmaster.$(O): jcmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcomapi.$(O): jcomapi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcparam.$(O): jcparam.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcphuff.$(O): jcphuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jchuff.h +jcprepct.$(O): jcprepct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcsample.$(O): jcsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jctrans.$(O): jctrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdapimin.$(O): jdapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdapistd.$(O): jdapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdatadst.$(O): jdatadst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h +jdatasrc.$(O): jdatasrc.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h +jdcoefct.$(O): jdcoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdcolor.$(O): jdcolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jddctmgr.$(O): jddctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jdhuff.$(O): jdhuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdhuff.h +jdinput.$(O): jdinput.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdmainct.$(O): jdmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdmarker.$(O): jdmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdmaster.$(O): jdmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdmerge.$(O): jdmerge.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdphuff.$(O): jdphuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdhuff.h +jdpostct.$(O): jdpostct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdsample.$(O): jdsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdtrans.$(O): jdtrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jerror.$(O): jerror.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jversion.h jerror.h +jfdctflt.$(O): jfdctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jfdctfst.$(O): jfdctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jfdctint.$(O): jfdctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jidctflt.$(O): jidctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jidctfst.$(O): jidctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jidctint.$(O): jidctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jidctred.$(O): jidctred.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jquant1.$(O): jquant1.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jquant2.$(O): jquant2.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jutils.$(O): jutils.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jmemmgr.$(O): jmemmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +jmemansi.$(O): jmemansi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +jmemname.$(O): jmemname.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +jmemnobs.$(O): jmemnobs.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +jmemdos.$(O): jmemdos.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +jmemmac.$(O): jmemmac.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +cjpeg.$(O): cjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h +djpeg.$(O): djpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h +jpegtran.$(O): jpegtran.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h transupp.h jversion.h +rdjpgcom.$(O): rdjpgcom.c jinclude.h jconfig.h +wrjpgcom.$(O): wrjpgcom.c jinclude.h jconfig.h +cdjpeg.$(O): cdjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdcolmap.$(O): rdcolmap.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdswitch.$(O): rdswitch.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +transupp.$(O): transupp.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h transupp.h +rdppm.$(O): rdppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +wrppm.$(O): wrppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdgif.$(O): rdgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +wrgif.$(O): wrgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdtarga.$(O): rdtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +wrtarga.$(O): wrtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdbmp.$(O): rdbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +wrbmp.$(O): wrbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdrle.$(O): rdrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +wrrle.$(O): wrrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h diff --git a/mk4/modimage/jpeg-6b/makefile.dj b/mk4/modimage/jpeg-6b/makefile.dj new file mode 100644 index 0000000..f766d25 --- /dev/null +++ b/mk4/modimage/jpeg-6b/makefile.dj @@ -0,0 +1,220 @@ +# Makefile for Independent JPEG Group's software + +# This makefile is for DJGPP (Delorie's GNU C port on MS-DOS), v2.0 or later. +# Thanks to Frank J. Donahoe for this version. + +# Read installation instructions before saying "make" !! + +# The name of your C compiler: +CC= gcc + +# You may need to adjust these cc options: +CFLAGS= -O2 -Wall -I. +# Generally, we recommend defining any configuration symbols in jconfig.h, +# NOT via -D switches here. + +# Link-time cc options: +LDFLAGS= -s + +# To link any special libraries, add the necessary -l commands here. +LDLIBS= + +# Put here the object file name for the correct system-dependent memory +# manager file. For DJGPP this is usually jmemnobs.o, but you could +# use jmemname.o if you want to use named temp files instead of swap space. +SYSDEPMEM= jmemnobs.o + +# miscellaneous OS-dependent stuff +# linker +LN= $(CC) +# file deletion command +RM= del +# library (.a) file creation command +AR= ar rc +# second step in .a creation (use "touch" if not needed) +AR2= ranlib + +# End of configurable options. + + +# source files: JPEG library proper +LIBSOURCES= jcapimin.c jcapistd.c jccoefct.c jccolor.c jcdctmgr.c jchuff.c \ + jcinit.c jcmainct.c jcmarker.c jcmaster.c jcomapi.c jcparam.c \ + jcphuff.c jcprepct.c jcsample.c jctrans.c jdapimin.c jdapistd.c \ + jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c jddctmgr.c jdhuff.c \ + jdinput.c jdmainct.c jdmarker.c jdmaster.c jdmerge.c jdphuff.c \ + jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c jfdctfst.c \ + jfdctint.c jidctflt.c jidctfst.c jidctint.c jidctred.c jquant1.c \ + jquant2.c jutils.c jmemmgr.c +# memmgr back ends: compile only one of these into a working library +SYSDEPSOURCES= jmemansi.c jmemname.c jmemnobs.c jmemdos.c jmemmac.c +# source files: cjpeg/djpeg/jpegtran applications, also rdjpgcom/wrjpgcom +APPSOURCES= cjpeg.c djpeg.c jpegtran.c rdjpgcom.c wrjpgcom.c cdjpeg.c \ + rdcolmap.c rdswitch.c transupp.c rdppm.c wrppm.c rdgif.c wrgif.c \ + rdtarga.c wrtarga.c rdbmp.c wrbmp.c rdrle.c wrrle.c +SOURCES= $(LIBSOURCES) $(SYSDEPSOURCES) $(APPSOURCES) +# files included by source files +INCLUDES= jchuff.h jdhuff.h jdct.h jerror.h jinclude.h jmemsys.h jmorecfg.h \ + jpegint.h jpeglib.h jversion.h cdjpeg.h cderror.h transupp.h +# documentation, test, and support files +DOCS= README install.doc usage.doc cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 \ + wrjpgcom.1 wizard.doc example.c libjpeg.doc structure.doc \ + coderules.doc filelist.doc change.log +MKFILES= configure makefile.cfg makefile.ansi makefile.unix makefile.bcc \ + makefile.mc6 makefile.dj makefile.wat makefile.vc makelib.ds \ + makeapps.ds makeproj.mac makcjpeg.st makdjpeg.st makljpeg.st \ + maktjpeg.st makefile.manx makefile.sas makefile.mms makefile.vms \ + makvms.opt +CONFIGFILES= jconfig.cfg jconfig.bcc jconfig.mc6 jconfig.dj jconfig.wat \ + jconfig.vc jconfig.mac jconfig.st jconfig.manx jconfig.sas \ + jconfig.vms +CONFIGUREFILES= config.guess config.sub install-sh ltconfig ltmain.sh +OTHERFILES= jconfig.doc ckconfig.c ansi2knr.c ansi2knr.1 jmemdosa.asm +TESTFILES= testorig.jpg testimg.ppm testimg.bmp testimg.jpg testprog.jpg \ + testimgp.jpg +DISTFILES= $(DOCS) $(MKFILES) $(CONFIGFILES) $(SOURCES) $(INCLUDES) \ + $(CONFIGUREFILES) $(OTHERFILES) $(TESTFILES) +# library object files common to compression and decompression +COMOBJECTS= jcomapi.o jutils.o jerror.o jmemmgr.o $(SYSDEPMEM) +# compression library object files +CLIBOBJECTS= jcapimin.o jcapistd.o jctrans.o jcparam.o jdatadst.o jcinit.o \ + jcmaster.o jcmarker.o jcmainct.o jcprepct.o jccoefct.o jccolor.o \ + jcsample.o jchuff.o jcphuff.o jcdctmgr.o jfdctfst.o jfdctflt.o \ + jfdctint.o +# decompression library object files +DLIBOBJECTS= jdapimin.o jdapistd.o jdtrans.o jdatasrc.o jdmaster.o \ + jdinput.o jdmarker.o jdhuff.o jdphuff.o jdmainct.o jdcoefct.o \ + jdpostct.o jddctmgr.o jidctfst.o jidctflt.o jidctint.o jidctred.o \ + jdsample.o jdcolor.o jquant1.o jquant2.o jdmerge.o +# These objectfiles are included in libjpeg.a +LIBOBJECTS= $(CLIBOBJECTS) $(DLIBOBJECTS) $(COMOBJECTS) +# object files for sample applications (excluding library files) +COBJECTS= cjpeg.o rdppm.o rdgif.o rdtarga.o rdrle.o rdbmp.o rdswitch.o \ + cdjpeg.o +DOBJECTS= djpeg.o wrppm.o wrgif.o wrtarga.o wrrle.o wrbmp.o rdcolmap.o \ + cdjpeg.o +TROBJECTS= jpegtran.o rdswitch.o cdjpeg.o transupp.o + + +all: libjpeg.a cjpeg.exe djpeg.exe jpegtran.exe rdjpgcom.exe wrjpgcom.exe + +libjpeg.a: $(LIBOBJECTS) + $(RM) libjpeg.a + $(AR) libjpeg.a $(LIBOBJECTS) + $(AR2) libjpeg.a + +cjpeg.exe: $(COBJECTS) libjpeg.a + $(LN) $(LDFLAGS) -o cjpeg.exe $(COBJECTS) libjpeg.a $(LDLIBS) + +djpeg.exe: $(DOBJECTS) libjpeg.a + $(LN) $(LDFLAGS) -o djpeg.exe $(DOBJECTS) libjpeg.a $(LDLIBS) + +jpegtran.exe: $(TROBJECTS) libjpeg.a + $(LN) $(LDFLAGS) -o jpegtran.exe $(TROBJECTS) libjpeg.a $(LDLIBS) + +rdjpgcom.exe: rdjpgcom.o + $(LN) $(LDFLAGS) -o rdjpgcom.exe rdjpgcom.o $(LDLIBS) + +wrjpgcom.exe: wrjpgcom.o + $(LN) $(LDFLAGS) -o wrjpgcom.exe wrjpgcom.o $(LDLIBS) + +jconfig.h: jconfig.doc + echo You must prepare a system-dependent jconfig.h file. + echo Please read the installation directions in install.doc. + exit 1 + +clean: + $(RM) *.o + $(RM) cjpeg.exe + $(RM) djpeg.exe + $(RM) jpegtran.exe + $(RM) rdjpgcom.exe + $(RM) wrjpgcom.exe + $(RM) libjpeg.a + $(RM) testout*.* + +test: cjpeg.exe djpeg.exe jpegtran.exe + $(RM) testout*.* + ./djpeg -dct int -ppm -outfile testout.ppm testorig.jpg + ./djpeg -dct int -bmp -colors 256 -outfile testout.bmp testorig.jpg + ./cjpeg -dct int -outfile testout.jpg testimg.ppm + ./djpeg -dct int -ppm -outfile testoutp.ppm testprog.jpg + ./cjpeg -dct int -progressive -opt -outfile testoutp.jpg testimg.ppm + ./jpegtran -outfile testoutt.jpg testprog.jpg + fc /b testimg.ppm testout.ppm + fc /b testimg.bmp testout.bmp + fc /b testimg.jpg testout.jpg + fc /b testimg.ppm testoutp.ppm + fc /b testimgp.jpg testoutp.jpg + fc /b testorig.jpg testoutt.jpg + + +jcapimin.o: jcapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcapistd.o: jcapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jccoefct.o: jccoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jccolor.o: jccolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcdctmgr.o: jcdctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jchuff.o: jchuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jchuff.h +jcinit.o: jcinit.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcmainct.o: jcmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcmarker.o: jcmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcmaster.o: jcmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcomapi.o: jcomapi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcparam.o: jcparam.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcphuff.o: jcphuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jchuff.h +jcprepct.o: jcprepct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcsample.o: jcsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jctrans.o: jctrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdapimin.o: jdapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdapistd.o: jdapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdatadst.o: jdatadst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h +jdatasrc.o: jdatasrc.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h +jdcoefct.o: jdcoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdcolor.o: jdcolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jddctmgr.o: jddctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jdhuff.o: jdhuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdhuff.h +jdinput.o: jdinput.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdmainct.o: jdmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdmarker.o: jdmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdmaster.o: jdmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdmerge.o: jdmerge.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdphuff.o: jdphuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdhuff.h +jdpostct.o: jdpostct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdsample.o: jdsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdtrans.o: jdtrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jerror.o: jerror.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jversion.h jerror.h +jfdctflt.o: jfdctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jfdctfst.o: jfdctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jfdctint.o: jfdctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jidctflt.o: jidctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jidctfst.o: jidctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jidctint.o: jidctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jidctred.o: jidctred.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jquant1.o: jquant1.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jquant2.o: jquant2.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jutils.o: jutils.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jmemmgr.o: jmemmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +jmemansi.o: jmemansi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +jmemname.o: jmemname.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +jmemnobs.o: jmemnobs.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +jmemdos.o: jmemdos.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +jmemmac.o: jmemmac.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +cjpeg.o: cjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h +djpeg.o: djpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h +jpegtran.o: jpegtran.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h transupp.h jversion.h +rdjpgcom.o: rdjpgcom.c jinclude.h jconfig.h +wrjpgcom.o: wrjpgcom.c jinclude.h jconfig.h +cdjpeg.o: cdjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdcolmap.o: rdcolmap.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdswitch.o: rdswitch.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +transupp.o: transupp.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h transupp.h +rdppm.o: rdppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +wrppm.o: wrppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdgif.o: rdgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +wrgif.o: wrgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdtarga.o: rdtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +wrtarga.o: wrtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdbmp.o: rdbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +wrbmp.o: wrbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdrle.o: rdrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +wrrle.o: wrrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h diff --git a/mk4/modimage/jpeg-6b/makefile.manx b/mk4/modimage/jpeg-6b/makefile.manx new file mode 100644 index 0000000..4cb42d1 --- /dev/null +++ b/mk4/modimage/jpeg-6b/makefile.manx @@ -0,0 +1,214 @@ +# Makefile for Independent JPEG Group's software + +# This makefile is for Amiga systems using Manx Aztec C ver 5.x. +# Thanks to D.J. James (djjames@cup.portal.com) for this version. + +# Read installation instructions before saying "make" !! + +# The name of your C compiler: +CC= cc + +# You may need to adjust these cc options: +# Uncomment for generic 68000 code (will work on any Amiga) +ARCHFLAGS= -sn + +# Uncomment for 68020/68030 code (faster, but won't run on 68000 CPU) +#ARCHFLAGS= -c2 + +CFLAGS= -MC -MD $(ARCHFLAGS) -spfam -r4 + +# Link-time cc options: +LDFLAGS= -g + +# To link any special libraries, add the necessary -l commands here. +LDLIBS= -lml -lcl + +# Put here the object file name for the correct system-dependent memory +# manager file. For Amiga we recommend jmemname.o. +SYSDEPMEM= jmemname.o + +# miscellaneous OS-dependent stuff +# linker +LN= ln +# file deletion command +RM= delete quiet +# library (.lib) file creation command +AR= lb + +# End of configurable options. + + +# source files: JPEG library proper +LIBSOURCES= jcapimin.c jcapistd.c jccoefct.c jccolor.c jcdctmgr.c jchuff.c \ + jcinit.c jcmainct.c jcmarker.c jcmaster.c jcomapi.c jcparam.c \ + jcphuff.c jcprepct.c jcsample.c jctrans.c jdapimin.c jdapistd.c \ + jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c jddctmgr.c jdhuff.c \ + jdinput.c jdmainct.c jdmarker.c jdmaster.c jdmerge.c jdphuff.c \ + jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c jfdctfst.c \ + jfdctint.c jidctflt.c jidctfst.c jidctint.c jidctred.c jquant1.c \ + jquant2.c jutils.c jmemmgr.c +# memmgr back ends: compile only one of these into a working library +SYSDEPSOURCES= jmemansi.c jmemname.c jmemnobs.c jmemdos.c jmemmac.c +# source files: cjpeg/djpeg/jpegtran applications, also rdjpgcom/wrjpgcom +APPSOURCES= cjpeg.c djpeg.c jpegtran.c rdjpgcom.c wrjpgcom.c cdjpeg.c \ + rdcolmap.c rdswitch.c transupp.c rdppm.c wrppm.c rdgif.c wrgif.c \ + rdtarga.c wrtarga.c rdbmp.c wrbmp.c rdrle.c wrrle.c +SOURCES= $(LIBSOURCES) $(SYSDEPSOURCES) $(APPSOURCES) +# files included by source files +INCLUDES= jchuff.h jdhuff.h jdct.h jerror.h jinclude.h jmemsys.h jmorecfg.h \ + jpegint.h jpeglib.h jversion.h cdjpeg.h cderror.h transupp.h +# documentation, test, and support files +DOCS= README install.doc usage.doc cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 \ + wrjpgcom.1 wizard.doc example.c libjpeg.doc structure.doc \ + coderules.doc filelist.doc change.log +MKFILES= configure makefile.cfg makefile.ansi makefile.unix makefile.bcc \ + makefile.mc6 makefile.dj makefile.wat makefile.vc makelib.ds \ + makeapps.ds makeproj.mac makcjpeg.st makdjpeg.st makljpeg.st \ + maktjpeg.st makefile.manx makefile.sas makefile.mms makefile.vms \ + makvms.opt +CONFIGFILES= jconfig.cfg jconfig.bcc jconfig.mc6 jconfig.dj jconfig.wat \ + jconfig.vc jconfig.mac jconfig.st jconfig.manx jconfig.sas \ + jconfig.vms +CONFIGUREFILES= config.guess config.sub install-sh ltconfig ltmain.sh +OTHERFILES= jconfig.doc ckconfig.c ansi2knr.c ansi2knr.1 jmemdosa.asm +TESTFILES= testorig.jpg testimg.ppm testimg.bmp testimg.jpg testprog.jpg \ + testimgp.jpg +DISTFILES= $(DOCS) $(MKFILES) $(CONFIGFILES) $(SOURCES) $(INCLUDES) \ + $(CONFIGUREFILES) $(OTHERFILES) $(TESTFILES) +# library object files common to compression and decompression +COMOBJECTS= jcomapi.o jutils.o jerror.o jmemmgr.o $(SYSDEPMEM) +# compression library object files +CLIBOBJECTS= jcapimin.o jcapistd.o jctrans.o jcparam.o jdatadst.o jcinit.o \ + jcmaster.o jcmarker.o jcmainct.o jcprepct.o jccoefct.o jccolor.o \ + jcsample.o jchuff.o jcphuff.o jcdctmgr.o jfdctfst.o jfdctflt.o \ + jfdctint.o +# decompression library object files +DLIBOBJECTS= jdapimin.o jdapistd.o jdtrans.o jdatasrc.o jdmaster.o \ + jdinput.o jdmarker.o jdhuff.o jdphuff.o jdmainct.o jdcoefct.o \ + jdpostct.o jddctmgr.o jidctfst.o jidctflt.o jidctint.o jidctred.o \ + jdsample.o jdcolor.o jquant1.o jquant2.o jdmerge.o +# These objectfiles are included in libjpeg.lib +LIBOBJECTS= $(CLIBOBJECTS) $(DLIBOBJECTS) $(COMOBJECTS) +# object files for sample applications (excluding library files) +COBJECTS= cjpeg.o rdppm.o rdgif.o rdtarga.o rdrle.o rdbmp.o rdswitch.o \ + cdjpeg.o +DOBJECTS= djpeg.o wrppm.o wrgif.o wrtarga.o wrrle.o wrbmp.o rdcolmap.o \ + cdjpeg.o +TROBJECTS= jpegtran.o rdswitch.o cdjpeg.o transupp.o + + +all: libjpeg.lib cjpeg djpeg jpegtran rdjpgcom wrjpgcom + +libjpeg.lib: $(LIBOBJECTS) + -$(RM) libjpeg.lib + $(AR) libjpeg.lib $(LIBOBJECTS) + +cjpeg: $(COBJECTS) libjpeg.lib + $(LN) $(LDFLAGS) -o cjpeg $(COBJECTS) libjpeg.lib $(LDLIBS) + +djpeg: $(DOBJECTS) libjpeg.lib + $(LN) $(LDFLAGS) -o djpeg $(DOBJECTS) libjpeg.lib $(LDLIBS) + +jpegtran: $(TROBJECTS) libjpeg.lib + $(LN) $(LDFLAGS) -o jpegtran $(TROBJECTS) libjpeg.lib $(LDLIBS) + +rdjpgcom: rdjpgcom.o + $(LN) $(LDFLAGS) -o rdjpgcom rdjpgcom.o $(LDLIBS) + +wrjpgcom: wrjpgcom.o + $(LN) $(LDFLAGS) -o wrjpgcom wrjpgcom.o $(LDLIBS) + +jconfig.h: jconfig.doc + echo You must prepare a system-dependent jconfig.h file. + echo Please read the installation directions in install.doc. + exit 1 + +clean: + -$(RM) *.o cjpeg djpeg jpegtran libjpeg.lib rdjpgcom wrjpgcom + -$(RM) core testout*.* + +test: cjpeg djpeg jpegtran + -$(RM) testout*.* + djpeg -dct int -ppm -outfile testout.ppm testorig.jpg + djpeg -dct int -bmp -colors 256 -outfile testout.bmp testorig.jpg + cjpeg -dct int -outfile testout.jpg testimg.ppm + djpeg -dct int -ppm -outfile testoutp.ppm testprog.jpg + cjpeg -dct int -progressive -opt -outfile testoutp.jpg testimg.ppm + jpegtran -outfile testoutt.jpg testprog.jpg + cmp testimg.ppm testout.ppm + cmp testimg.bmp testout.bmp + cmp testimg.jpg testout.jpg + cmp testimg.ppm testoutp.ppm + cmp testimgp.jpg testoutp.jpg + cmp testorig.jpg testoutt.jpg + + +jcapimin.o: jcapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcapistd.o: jcapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jccoefct.o: jccoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jccolor.o: jccolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcdctmgr.o: jcdctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jchuff.o: jchuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jchuff.h +jcinit.o: jcinit.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcmainct.o: jcmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcmarker.o: jcmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcmaster.o: jcmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcomapi.o: jcomapi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcparam.o: jcparam.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcphuff.o: jcphuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jchuff.h +jcprepct.o: jcprepct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcsample.o: jcsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jctrans.o: jctrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdapimin.o: jdapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdapistd.o: jdapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdatadst.o: jdatadst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h +jdatasrc.o: jdatasrc.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h +jdcoefct.o: jdcoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdcolor.o: jdcolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jddctmgr.o: jddctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jdhuff.o: jdhuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdhuff.h +jdinput.o: jdinput.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdmainct.o: jdmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdmarker.o: jdmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdmaster.o: jdmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdmerge.o: jdmerge.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdphuff.o: jdphuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdhuff.h +jdpostct.o: jdpostct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdsample.o: jdsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdtrans.o: jdtrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jerror.o: jerror.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jversion.h jerror.h +jfdctflt.o: jfdctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jfdctfst.o: jfdctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jfdctint.o: jfdctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jidctflt.o: jidctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jidctfst.o: jidctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jidctint.o: jidctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jidctred.o: jidctred.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jquant1.o: jquant1.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jquant2.o: jquant2.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jutils.o: jutils.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jmemmgr.o: jmemmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +jmemansi.o: jmemansi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +jmemname.o: jmemname.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +jmemnobs.o: jmemnobs.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +jmemdos.o: jmemdos.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +jmemmac.o: jmemmac.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +cjpeg.o: cjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h +djpeg.o: djpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h +jpegtran.o: jpegtran.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h transupp.h jversion.h +rdjpgcom.o: rdjpgcom.c jinclude.h jconfig.h +wrjpgcom.o: wrjpgcom.c jinclude.h jconfig.h +cdjpeg.o: cdjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdcolmap.o: rdcolmap.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdswitch.o: rdswitch.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +transupp.o: transupp.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h transupp.h +rdppm.o: rdppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +wrppm.o: wrppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdgif.o: rdgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +wrgif.o: wrgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdtarga.o: rdtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +wrtarga.o: wrtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdbmp.o: rdbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +wrbmp.o: wrbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdrle.o: rdrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +wrrle.o: wrrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h diff --git a/mk4/modimage/jpeg-6b/makefile.mc6 b/mk4/modimage/jpeg-6b/makefile.mc6 new file mode 100644 index 0000000..6aff054 --- /dev/null +++ b/mk4/modimage/jpeg-6b/makefile.mc6 @@ -0,0 +1,249 @@ +# Makefile for Independent JPEG Group's software + +# This makefile is for Microsoft C for MS-DOS, version 6.00A and up. +# Use NMAKE, not Microsoft's brain-damaged MAKE. +# Thanks to Alan Wright and Chris Turner of Olivetti Research Ltd. + +# Read installation instructions before saying "nmake" !! + +# You may need to adjust these compiler options: +CFLAGS = -AM -Oecigt -Gs -W3 +# -AM medium memory model (or use -AS for small model, if you remove features) +# -Oecigt -Gs maximum safe optimisation (-Ol has bugs in MSC 6.00A) +# -W3 warning level 3 +# You might also want to add -G2 if you have an 80286, etc. +# Generally, we recommend defining any configuration symbols in jconfig.h, +# NOT via -D switches here. + +# Jan-Herman Buining suggests the following switches for MS C 8.0 and a 486: +# CFLAGS = /AM /f- /FPi87 /G3 /Gs /Gy /Ob1 /Oc /Oe /Og /Oi /Ol /On /Oo /Ot \ +# /OV4 /W3 +# except for jquant1.c, which must be compiled with /Oo- to avoid a compiler +# crash. + +# Ingar Steinsland suggests the following switches when building +# a 16-bit Windows DLL: +# CFLAGS = -ALw -Gsw -Zpe -W3 -O2 -Zi -Zd + +# Put here the object file name for the correct system-dependent memory +# manager file. For DOS, we recommend jmemdos.c and jmemdosa.asm. +# (But not for Windows; see install.doc if you use this makefile for Windows.) +SYSDEPMEM= jmemdos.obj jmemdosa.obj +# SYSDEPMEMLIB must list the same files with "+" signs for the librarian. +SYSDEPMEMLIB= +jmemdos.obj +jmemdosa.obj + +# End of configurable options. + + +# source files: JPEG library proper +LIBSOURCES= jcapimin.c jcapistd.c jccoefct.c jccolor.c jcdctmgr.c jchuff.c \ + jcinit.c jcmainct.c jcmarker.c jcmaster.c jcomapi.c jcparam.c \ + jcphuff.c jcprepct.c jcsample.c jctrans.c jdapimin.c jdapistd.c \ + jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c jddctmgr.c jdhuff.c \ + jdinput.c jdmainct.c jdmarker.c jdmaster.c jdmerge.c jdphuff.c \ + jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c jfdctfst.c \ + jfdctint.c jidctflt.c jidctfst.c jidctint.c jidctred.c jquant1.c \ + jquant2.c jutils.c jmemmgr.c +# memmgr back ends: compile only one of these into a working library +SYSDEPSOURCES= jmemansi.c jmemname.c jmemnobs.c jmemdos.c jmemmac.c +# source files: cjpeg/djpeg/jpegtran applications, also rdjpgcom/wrjpgcom +APPSOURCES= cjpeg.c djpeg.c jpegtran.c rdjpgcom.c wrjpgcom.c cdjpeg.c \ + rdcolmap.c rdswitch.c transupp.c rdppm.c wrppm.c rdgif.c wrgif.c \ + rdtarga.c wrtarga.c rdbmp.c wrbmp.c rdrle.c wrrle.c +SOURCES= $(LIBSOURCES) $(SYSDEPSOURCES) $(APPSOURCES) +# files included by source files +INCLUDES= jchuff.h jdhuff.h jdct.h jerror.h jinclude.h jmemsys.h jmorecfg.h \ + jpegint.h jpeglib.h jversion.h cdjpeg.h cderror.h transupp.h +# documentation, test, and support files +DOCS= README install.doc usage.doc cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 \ + wrjpgcom.1 wizard.doc example.c libjpeg.doc structure.doc \ + coderules.doc filelist.doc change.log +MKFILES= configure makefile.cfg makefile.ansi makefile.unix makefile.bcc \ + makefile.mc6 makefile.dj makefile.wat makefile.vc makelib.ds \ + makeapps.ds makeproj.mac makcjpeg.st makdjpeg.st makljpeg.st \ + maktjpeg.st makefile.manx makefile.sas makefile.mms makefile.vms \ + makvms.opt +CONFIGFILES= jconfig.cfg jconfig.bcc jconfig.mc6 jconfig.dj jconfig.wat \ + jconfig.vc jconfig.mac jconfig.st jconfig.manx jconfig.sas \ + jconfig.vms +CONFIGUREFILES= config.guess config.sub install-sh ltconfig ltmain.sh +OTHERFILES= jconfig.doc ckconfig.c ansi2knr.c ansi2knr.1 jmemdosa.asm +TESTFILES= testorig.jpg testimg.ppm testimg.bmp testimg.jpg testprog.jpg \ + testimgp.jpg +DISTFILES= $(DOCS) $(MKFILES) $(CONFIGFILES) $(SOURCES) $(INCLUDES) \ + $(CONFIGUREFILES) $(OTHERFILES) $(TESTFILES) +# library object files common to compression and decompression +COMOBJECTS= jcomapi.obj jutils.obj jerror.obj jmemmgr.obj $(SYSDEPMEM) +# compression library object files +CLIBOBJECTS= jcapimin.obj jcapistd.obj jctrans.obj jcparam.obj jdatadst.obj \ + jcinit.obj jcmaster.obj jcmarker.obj jcmainct.obj jcprepct.obj \ + jccoefct.obj jccolor.obj jcsample.obj jchuff.obj jcphuff.obj \ + jcdctmgr.obj jfdctfst.obj jfdctflt.obj jfdctint.obj +# decompression library object files +DLIBOBJECTS= jdapimin.obj jdapistd.obj jdtrans.obj jdatasrc.obj \ + jdmaster.obj jdinput.obj jdmarker.obj jdhuff.obj jdphuff.obj \ + jdmainct.obj jdcoefct.obj jdpostct.obj jddctmgr.obj jidctfst.obj \ + jidctflt.obj jidctint.obj jidctred.obj jdsample.obj jdcolor.obj \ + jquant1.obj jquant2.obj jdmerge.obj +# These objectfiles are included in libjpeg.lib +LIBOBJECTS= $(CLIBOBJECTS) $(DLIBOBJECTS) $(COMOBJECTS) +# object files for sample applications (excluding library files) +COBJECTS= cjpeg.obj rdppm.obj rdgif.obj rdtarga.obj rdrle.obj rdbmp.obj \ + rdswitch.obj cdjpeg.obj +DOBJECTS= djpeg.obj wrppm.obj wrgif.obj wrtarga.obj wrrle.obj wrbmp.obj \ + rdcolmap.obj cdjpeg.obj +TROBJECTS= jpegtran.obj rdswitch.obj cdjpeg.obj transupp.obj + +# need linker response file because file list > 128 chars +RFILE = libjpeg.ans + + +all: libjpeg.lib cjpeg.exe djpeg.exe jpegtran.exe rdjpgcom.exe wrjpgcom.exe + +libjpeg.lib: $(LIBOBJECTS) $(RFILE) + del libjpeg.lib + lib @$(RFILE) + +# linker response file for building libjpeg.lib +$(RFILE) : makefile + del $(RFILE) + echo libjpeg.lib >$(RFILE) +# silly want-to-create-it prompt: + echo y >>$(RFILE) + echo +jcapimin.obj +jcapistd.obj +jctrans.obj +jcparam.obj & >>$(RFILE) + echo +jdatadst.obj +jcinit.obj +jcmaster.obj +jcmarker.obj & >>$(RFILE) + echo +jcmainct.obj +jcprepct.obj +jccoefct.obj & >>$(RFILE) + echo +jccolor.obj +jcsample.obj +jchuff.obj +jcphuff.obj & >>$(RFILE) + echo +jcdctmgr.obj +jfdctfst.obj +jfdctflt.obj & >>$(RFILE) + echo +jfdctint.obj +jdapimin.obj +jdapistd.obj & >>$(RFILE) + echo +jdtrans.obj +jdatasrc.obj +jdmaster.obj +jdinput.obj & >>$(RFILE) + echo +jdmarker.obj +jdhuff.obj +jdphuff.obj +jdmainct.obj & >>$(RFILE) + echo +jdcoefct.obj +jdpostct.obj +jddctmgr.obj & >>$(RFILE) + echo +jidctfst.obj +jidctflt.obj +jidctint.obj & >>$(RFILE) + echo +jidctred.obj +jdsample.obj +jdcolor.obj +jquant1.obj & >>$(RFILE) + echo +jquant2.obj +jdmerge.obj +jcomapi.obj +jutils.obj & >>$(RFILE) + echo +jerror.obj +jmemmgr.obj & >>$(RFILE) + echo $(SYSDEPMEMLIB) ; >>$(RFILE) + +cjpeg.exe: $(COBJECTS) libjpeg.lib + echo $(COBJECTS) >cjpeg.lst + link /STACK:4096 /EXEPACK @cjpeg.lst, cjpeg.exe, , libjpeg.lib, ; + del cjpeg.lst + +djpeg.exe: $(DOBJECTS) libjpeg.lib + echo $(DOBJECTS) >djpeg.lst + link /STACK:4096 /EXEPACK @djpeg.lst, djpeg.exe, , libjpeg.lib, ; + del djpeg.lst + +jpegtran.exe: $(TROBJECTS) libjpeg.lib + link /STACK:4096 /EXEPACK $(TROBJECTS), jpegtran.exe, , libjpeg.lib, ; + +rdjpgcom.exe: rdjpgcom.c + $(CC) -AS -O -W3 rdjpgcom.c + +# wrjpgcom needs large model so it can malloc a 64K chunk +wrjpgcom.exe: wrjpgcom.c + $(CC) -AL -O -W3 wrjpgcom.c + +jconfig.h: jconfig.doc + echo You must prepare a system-dependent jconfig.h file. + echo Please read the installation directions in install.doc. + exit 1 + +clean: + del *.obj + del libjpeg.lib + del cjpeg.exe + del djpeg.exe + del jpegtran.exe + del rdjpgcom.exe + del wrjpgcom.exe + del testout*.* + +test: cjpeg.exe djpeg.exe jpegtran.exe + del testout*.* + djpeg -dct int -ppm -outfile testout.ppm testorig.jpg + djpeg -dct int -bmp -colors 256 -outfile testout.bmp testorig.jpg + cjpeg -dct int -outfile testout.jpg testimg.ppm + djpeg -dct int -ppm -outfile testoutp.ppm testprog.jpg + cjpeg -dct int -progressive -opt -outfile testoutp.jpg testimg.ppm + jpegtran -outfile testoutt.jpg testprog.jpg + fc /b testimg.ppm testout.ppm + fc /b testimg.bmp testout.bmp + fc /b testimg.jpg testout.jpg + fc /b testimg.ppm testoutp.ppm + fc /b testimgp.jpg testoutp.jpg + fc /b testorig.jpg testoutt.jpg + + +jcapimin.obj: jcapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcapistd.obj: jcapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jccoefct.obj: jccoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jccolor.obj: jccolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcdctmgr.obj: jcdctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jchuff.obj: jchuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jchuff.h +jcinit.obj: jcinit.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcmainct.obj: jcmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcmarker.obj: jcmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcmaster.obj: jcmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcomapi.obj: jcomapi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcparam.obj: jcparam.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcphuff.obj: jcphuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jchuff.h +jcprepct.obj: jcprepct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcsample.obj: jcsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jctrans.obj: jctrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdapimin.obj: jdapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdapistd.obj: jdapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdatadst.obj: jdatadst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h +jdatasrc.obj: jdatasrc.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h +jdcoefct.obj: jdcoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdcolor.obj: jdcolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jddctmgr.obj: jddctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jdhuff.obj: jdhuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdhuff.h +jdinput.obj: jdinput.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdmainct.obj: jdmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdmarker.obj: jdmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdmaster.obj: jdmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdmerge.obj: jdmerge.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdphuff.obj: jdphuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdhuff.h +jdpostct.obj: jdpostct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdsample.obj: jdsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdtrans.obj: jdtrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jerror.obj: jerror.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jversion.h jerror.h +jfdctflt.obj: jfdctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jfdctfst.obj: jfdctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jfdctint.obj: jfdctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jidctflt.obj: jidctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jidctfst.obj: jidctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jidctint.obj: jidctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jidctred.obj: jidctred.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jquant1.obj: jquant1.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jquant2.obj: jquant2.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jutils.obj: jutils.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jmemmgr.obj: jmemmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +jmemansi.obj: jmemansi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +jmemname.obj: jmemname.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +jmemnobs.obj: jmemnobs.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +jmemdos.obj: jmemdos.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +jmemmac.obj: jmemmac.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +cjpeg.obj: cjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h +djpeg.obj: djpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h +jpegtran.obj: jpegtran.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h transupp.h jversion.h +rdjpgcom.obj: rdjpgcom.c jinclude.h jconfig.h +wrjpgcom.obj: wrjpgcom.c jinclude.h jconfig.h +cdjpeg.obj: cdjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdcolmap.obj: rdcolmap.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdswitch.obj: rdswitch.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +transupp.obj: transupp.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h transupp.h +rdppm.obj: rdppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +wrppm.obj: wrppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdgif.obj: rdgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +wrgif.obj: wrgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdtarga.obj: rdtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +wrtarga.obj: wrtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdbmp.obj: rdbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +wrbmp.obj: wrbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdrle.obj: rdrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +wrrle.obj: wrrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +jmemdosa.obj : jmemdosa.asm + masm /mx $*; diff --git a/mk4/modimage/jpeg-6b/makefile.mms b/mk4/modimage/jpeg-6b/makefile.mms new file mode 100644 index 0000000..cf130e5 --- /dev/null +++ b/mk4/modimage/jpeg-6b/makefile.mms @@ -0,0 +1,218 @@ +# Makefile for Independent JPEG Group's software + +# This makefile is for use with MMS on Digital VMS systems. +# Thanks to Rick Dyson (dyson@iowasp.physics.uiowa.edu) +# and Tim Bell (tbell@netcom.com) for their help. + +# Read installation instructions before saying "MMS" !! + +# You may need to adjust these cc options: +CFLAGS= $(CFLAGS) /NoDebug /Optimize +# Generally, we recommend defining any configuration symbols in jconfig.h, +# NOT via /Define switches here. +.ifdef ALPHA +OPT= +.else +OPT= ,Sys$Disk:[]MAKVMS.OPT/Option +.endif + +# Put here the object file name for the correct system-dependent memory +# manager file. For Unix this is usually jmemnobs.o, but you may want +# to use jmemansi.o or jmemname.o if you have limited swap space. +SYSDEPMEM= jmemnobs.obj + +# End of configurable options. + + +# source files: JPEG library proper +LIBSOURCES= jcapimin.c jcapistd.c jccoefct.c jccolor.c jcdctmgr.c jchuff.c \ + jcinit.c jcmainct.c jcmarker.c jcmaster.c jcomapi.c jcparam.c \ + jcphuff.c jcprepct.c jcsample.c jctrans.c jdapimin.c jdapistd.c \ + jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c jddctmgr.c jdhuff.c \ + jdinput.c jdmainct.c jdmarker.c jdmaster.c jdmerge.c jdphuff.c \ + jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c jfdctfst.c \ + jfdctint.c jidctflt.c jidctfst.c jidctint.c jidctred.c jquant1.c \ + jquant2.c jutils.c jmemmgr.c +# memmgr back ends: compile only one of these into a working library +SYSDEPSOURCES= jmemansi.c jmemname.c jmemnobs.c jmemdos.c jmemmac.c +# source files: cjpeg/djpeg/jpegtran applications, also rdjpgcom/wrjpgcom +APPSOURCES= cjpeg.c djpeg.c jpegtran.c rdjpgcom.c wrjpgcom.c cdjpeg.c \ + rdcolmap.c rdswitch.c transupp.c rdppm.c wrppm.c rdgif.c wrgif.c \ + rdtarga.c wrtarga.c rdbmp.c wrbmp.c rdrle.c wrrle.c +SOURCES= $(LIBSOURCES) $(SYSDEPSOURCES) $(APPSOURCES) +# files included by source files +INCLUDES= jchuff.h jdhuff.h jdct.h jerror.h jinclude.h jmemsys.h jmorecfg.h \ + jpegint.h jpeglib.h jversion.h cdjpeg.h cderror.h transupp.h +# documentation, test, and support files +DOCS= README install.doc usage.doc cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 \ + wrjpgcom.1 wizard.doc example.c libjpeg.doc structure.doc \ + coderules.doc filelist.doc change.log +MKFILES= configure makefile.cfg makefile.ansi makefile.unix makefile.bcc \ + makefile.mc6 makefile.dj makefile.wat makefile.vc makelib.ds \ + makeapps.ds makeproj.mac makcjpeg.st makdjpeg.st makljpeg.st \ + maktjpeg.st makefile.manx makefile.sas makefile.mms makefile.vms \ + makvms.opt +CONFIGFILES= jconfig.cfg jconfig.bcc jconfig.mc6 jconfig.dj jconfig.wat \ + jconfig.vc jconfig.mac jconfig.st jconfig.manx jconfig.sas \ + jconfig.vms +CONFIGUREFILES= config.guess config.sub install-sh ltconfig ltmain.sh +OTHERFILES= jconfig.doc ckconfig.c ansi2knr.c ansi2knr.1 jmemdosa.asm +TESTFILES= testorig.jpg testimg.ppm testimg.bmp testimg.jpg testprog.jpg \ + testimgp.jpg +DISTFILES= $(DOCS) $(MKFILES) $(CONFIGFILES) $(SOURCES) $(INCLUDES) \ + $(CONFIGUREFILES) $(OTHERFILES) $(TESTFILES) +# library object files common to compression and decompression +COMOBJECTS= jcomapi.obj jutils.obj jerror.obj jmemmgr.obj $(SYSDEPMEM) +# compression library object files +CLIBOBJECTS= jcapimin.obj jcapistd.obj jctrans.obj jcparam.obj jdatadst.obj \ + jcinit.obj jcmaster.obj jcmarker.obj jcmainct.obj jcprepct.obj \ + jccoefct.obj jccolor.obj jcsample.obj jchuff.obj jcphuff.obj \ + jcdctmgr.obj jfdctfst.obj jfdctflt.obj jfdctint.obj +# decompression library object files +DLIBOBJECTS= jdapimin.obj jdapistd.obj jdtrans.obj jdatasrc.obj \ + jdmaster.obj jdinput.obj jdmarker.obj jdhuff.obj jdphuff.obj \ + jdmainct.obj jdcoefct.obj jdpostct.obj jddctmgr.obj jidctfst.obj \ + jidctflt.obj jidctint.obj jidctred.obj jdsample.obj jdcolor.obj \ + jquant1.obj jquant2.obj jdmerge.obj +# These objectfiles are included in libjpeg.olb +LIBOBJECTS= $(CLIBOBJECTS) $(DLIBOBJECTS) $(COMOBJECTS) +# object files for sample applications (excluding library files) +COBJECTS= cjpeg.obj rdppm.obj rdgif.obj rdtarga.obj rdrle.obj rdbmp.obj \ + rdswitch.obj cdjpeg.obj +DOBJECTS= djpeg.obj wrppm.obj wrgif.obj wrtarga.obj wrrle.obj wrbmp.obj \ + rdcolmap.obj cdjpeg.obj +TROBJECTS= jpegtran.obj rdswitch.obj cdjpeg.obj transupp.obj +# objectfile lists with commas --- what a crock +COBJLIST= cjpeg.obj,rdppm.obj,rdgif.obj,rdtarga.obj,rdrle.obj,rdbmp.obj,\ + rdswitch.obj,cdjpeg.obj +DOBJLIST= djpeg.obj,wrppm.obj,wrgif.obj,wrtarga.obj,wrrle.obj,wrbmp.obj,\ + rdcolmap.obj,cdjpeg.obj +TROBJLIST= jpegtran.obj,rdswitch.obj,cdjpeg.obj,transupp.obj +LIBOBJLIST= jcapimin.obj,jcapistd.obj,jctrans.obj,jcparam.obj,jdatadst.obj,\ + jcinit.obj,jcmaster.obj,jcmarker.obj,jcmainct.obj,jcprepct.obj,\ + jccoefct.obj,jccolor.obj,jcsample.obj,jchuff.obj,jcphuff.obj,\ + jcdctmgr.obj,jfdctfst.obj,jfdctflt.obj,jfdctint.obj,jdapimin.obj,\ + jdapistd.obj,jdtrans.obj,jdatasrc.obj,jdmaster.obj,jdinput.obj,\ + jdmarker.obj,jdhuff.obj,jdphuff.obj,jdmainct.obj,jdcoefct.obj,\ + jdpostct.obj,jddctmgr.obj,jidctfst.obj,jidctflt.obj,jidctint.obj,\ + jidctred.obj,jdsample.obj,jdcolor.obj,jquant1.obj,jquant2.obj,\ + jdmerge.obj,jcomapi.obj,jutils.obj,jerror.obj,jmemmgr.obj,$(SYSDEPMEM) + + +.first + @- Define /NoLog Sys Sys$Library + +ALL : libjpeg.olb cjpeg.exe djpeg.exe jpegtran.exe rdjpgcom.exe wrjpgcom.exe + @ Continue + +libjpeg.olb : $(LIBOBJECTS) + Library /Create libjpeg.olb $(LIBOBJLIST) + +cjpeg.exe : $(COBJECTS) libjpeg.olb + $(LINK) $(LFLAGS) /Executable = cjpeg.exe $(COBJLIST),libjpeg.olb/Library$(OPT) + +djpeg.exe : $(DOBJECTS) libjpeg.olb + $(LINK) $(LFLAGS) /Executable = djpeg.exe $(DOBJLIST),libjpeg.olb/Library$(OPT) + +jpegtran.exe : $(TROBJECTS) libjpeg.olb + $(LINK) $(LFLAGS) /Executable = jpegtran.exe $(TROBJLIST),libjpeg.olb/Library$(OPT) + +rdjpgcom.exe : rdjpgcom.obj + $(LINK) $(LFLAGS) /Executable = rdjpgcom.exe rdjpgcom.obj$(OPT) + +wrjpgcom.exe : wrjpgcom.obj + $(LINK) $(LFLAGS) /Executable = wrjpgcom.exe wrjpgcom.obj$(OPT) + +jconfig.h : jconfig.vms + @- Copy jconfig.vms jconfig.h + +clean : + @- Set Protection = Owner:RWED *.*;-1 + @- Set Protection = Owner:RWED *.OBJ + - Purge /NoLog /NoConfirm *.* + - Delete /NoLog /NoConfirm *.OBJ; + +test : cjpeg.exe djpeg.exe jpegtran.exe + mcr sys$disk:[]djpeg -dct int -ppm -outfile testout.ppm testorig.jpg + mcr sys$disk:[]djpeg -dct int -bmp -colors 256 -outfile testout.bmp testorig.jpg + mcr sys$disk:[]cjpeg -dct int -outfile testout.jpg testimg.ppm + mcr sys$disk:[]djpeg -dct int -ppm -outfile testoutp.ppm testprog.jpg + mcr sys$disk:[]cjpeg -dct int -progressive -opt -outfile testoutp.jpg testimg.ppm + mcr sys$disk:[]jpegtran -outfile testoutt.jpg testprog.jpg + - Backup /Compare/Log testimg.ppm testout.ppm + - Backup /Compare/Log testimg.bmp testout.bmp + - Backup /Compare/Log testimg.jpg testout.jpg + - Backup /Compare/Log testimg.ppm testoutp.ppm + - Backup /Compare/Log testimgp.jpg testoutp.jpg + - Backup /Compare/Log testorig.jpg testoutt.jpg + + +jcapimin.obj : jcapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcapistd.obj : jcapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jccoefct.obj : jccoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jccolor.obj : jccolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcdctmgr.obj : jcdctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jchuff.obj : jchuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jchuff.h +jcinit.obj : jcinit.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcmainct.obj : jcmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcmarker.obj : jcmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcmaster.obj : jcmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcomapi.obj : jcomapi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcparam.obj : jcparam.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcphuff.obj : jcphuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jchuff.h +jcprepct.obj : jcprepct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcsample.obj : jcsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jctrans.obj : jctrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdapimin.obj : jdapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdapistd.obj : jdapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdatadst.obj : jdatadst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h +jdatasrc.obj : jdatasrc.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h +jdcoefct.obj : jdcoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdcolor.obj : jdcolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jddctmgr.obj : jddctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jdhuff.obj : jdhuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdhuff.h +jdinput.obj : jdinput.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdmainct.obj : jdmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdmarker.obj : jdmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdmaster.obj : jdmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdmerge.obj : jdmerge.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdphuff.obj : jdphuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdhuff.h +jdpostct.obj : jdpostct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdsample.obj : jdsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdtrans.obj : jdtrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jerror.obj : jerror.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jversion.h jerror.h +jfdctflt.obj : jfdctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jfdctfst.obj : jfdctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jfdctint.obj : jfdctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jidctflt.obj : jidctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jidctfst.obj : jidctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jidctint.obj : jidctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jidctred.obj : jidctred.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jquant1.obj : jquant1.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jquant2.obj : jquant2.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jutils.obj : jutils.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jmemmgr.obj : jmemmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +jmemansi.obj : jmemansi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +jmemname.obj : jmemname.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +jmemnobs.obj : jmemnobs.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +jmemdos.obj : jmemdos.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +jmemmac.obj : jmemmac.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +cjpeg.obj : cjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h +djpeg.obj : djpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h +jpegtran.obj : jpegtran.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h transupp.h jversion.h +rdjpgcom.obj : rdjpgcom.c jinclude.h jconfig.h +wrjpgcom.obj : wrjpgcom.c jinclude.h jconfig.h +cdjpeg.obj : cdjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdcolmap.obj : rdcolmap.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdswitch.obj : rdswitch.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +transupp.obj : transupp.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h transupp.h +rdppm.obj : rdppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +wrppm.obj : wrppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdgif.obj : rdgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +wrgif.obj : wrgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdtarga.obj : rdtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +wrtarga.obj : wrtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdbmp.obj : rdbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +wrbmp.obj : wrbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdrle.obj : rdrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +wrrle.obj : wrrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h diff --git a/mk4/modimage/jpeg-6b/makefile.sas b/mk4/modimage/jpeg-6b/makefile.sas new file mode 100644 index 0000000..f296faf --- /dev/null +++ b/mk4/modimage/jpeg-6b/makefile.sas @@ -0,0 +1,252 @@ +# Makefile for Independent JPEG Group's software + +# This makefile is for Amiga systems using SAS C 6.0 and up. +# Thanks to Ed Hanway, Mark Rinfret, and Jim Zepeda. + +# Read installation instructions before saying "make" !! + +# The name of your C compiler: +CC= sc + +# You may need to adjust these cc options: +# Uncomment the following lines for generic 680x0 version +ARCHFLAGS= cpu=any +SUFFIX= + +# Uncomment the following lines for 68030-only version +#ARCHFLAGS= cpu=68030 +#SUFFIX=.030 + +CFLAGS= nostackcheck data=near parms=register optimize $(ARCHFLAGS) \ + ignore=104 ignore=304 ignore=306 +# ignore=104 disables warnings for mismatched const qualifiers +# ignore=304 disables warnings for variables being optimized out +# ignore=306 disables warnings for the inlining of functions +# Generally, we recommend defining any configuration symbols in jconfig.h, +# NOT via define switches here. + +# Link-time cc options: +LDFLAGS= SC SD ND BATCH + +# To link any special libraries, add the necessary commands here. +LDLIBS= LIB:scm.lib LIB:sc.lib + +# Put here the object file name for the correct system-dependent memory +# manager file. For Amiga we recommend jmemname.o. +SYSDEPMEM= jmemname.o + +# miscellaneous OS-dependent stuff +# linker +LN= slink +# file deletion command +RM= delete quiet +# library (.lib) file creation command +AR= oml + +# End of configurable options. + + +# source files: JPEG library proper +LIBSOURCES= jcapimin.c jcapistd.c jccoefct.c jccolor.c jcdctmgr.c jchuff.c \ + jcinit.c jcmainct.c jcmarker.c jcmaster.c jcomapi.c jcparam.c \ + jcphuff.c jcprepct.c jcsample.c jctrans.c jdapimin.c jdapistd.c \ + jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c jddctmgr.c jdhuff.c \ + jdinput.c jdmainct.c jdmarker.c jdmaster.c jdmerge.c jdphuff.c \ + jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c jfdctfst.c \ + jfdctint.c jidctflt.c jidctfst.c jidctint.c jidctred.c jquant1.c \ + jquant2.c jutils.c jmemmgr.c +# memmgr back ends: compile only one of these into a working library +SYSDEPSOURCES= jmemansi.c jmemname.c jmemnobs.c jmemdos.c jmemmac.c +# source files: cjpeg/djpeg/jpegtran applications, also rdjpgcom/wrjpgcom +APPSOURCES= cjpeg.c djpeg.c jpegtran.c rdjpgcom.c wrjpgcom.c cdjpeg.c \ + rdcolmap.c rdswitch.c transupp.c rdppm.c wrppm.c rdgif.c wrgif.c \ + rdtarga.c wrtarga.c rdbmp.c wrbmp.c rdrle.c wrrle.c +SOURCES= $(LIBSOURCES) $(SYSDEPSOURCES) $(APPSOURCES) +# files included by source files +INCLUDES= jchuff.h jdhuff.h jdct.h jerror.h jinclude.h jmemsys.h jmorecfg.h \ + jpegint.h jpeglib.h jversion.h cdjpeg.h cderror.h transupp.h +# documentation, test, and support files +DOCS= README install.doc usage.doc cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 \ + wrjpgcom.1 wizard.doc example.c libjpeg.doc structure.doc \ + coderules.doc filelist.doc change.log +MKFILES= configure makefile.cfg makefile.ansi makefile.unix makefile.bcc \ + makefile.mc6 makefile.dj makefile.wat makefile.vc makelib.ds \ + makeapps.ds makeproj.mac makcjpeg.st makdjpeg.st makljpeg.st \ + maktjpeg.st makefile.manx makefile.sas makefile.mms makefile.vms \ + makvms.opt +CONFIGFILES= jconfig.cfg jconfig.bcc jconfig.mc6 jconfig.dj jconfig.wat \ + jconfig.vc jconfig.mac jconfig.st jconfig.manx jconfig.sas \ + jconfig.vms +CONFIGUREFILES= config.guess config.sub install-sh ltconfig ltmain.sh +OTHERFILES= jconfig.doc ckconfig.c ansi2knr.c ansi2knr.1 jmemdosa.asm +TESTFILES= testorig.jpg testimg.ppm testimg.bmp testimg.jpg testprog.jpg \ + testimgp.jpg +DISTFILES= $(DOCS) $(MKFILES) $(CONFIGFILES) $(SOURCES) $(INCLUDES) \ + $(CONFIGUREFILES) $(OTHERFILES) $(TESTFILES) +# library object files common to compression and decompression +COMOBJECTS= jcomapi.o jutils.o jerror.o jmemmgr.o $(SYSDEPMEM) +# compression library object files +CLIBOBJECTS= jcapimin.o jcapistd.o jctrans.o jcparam.o jdatadst.o jcinit.o \ + jcmaster.o jcmarker.o jcmainct.o jcprepct.o jccoefct.o jccolor.o \ + jcsample.o jchuff.o jcphuff.o jcdctmgr.o jfdctfst.o jfdctflt.o \ + jfdctint.o +# decompression library object files +DLIBOBJECTS= jdapimin.o jdapistd.o jdtrans.o jdatasrc.o jdmaster.o \ + jdinput.o jdmarker.o jdhuff.o jdphuff.o jdmainct.o jdcoefct.o \ + jdpostct.o jddctmgr.o jidctfst.o jidctflt.o jidctint.o jidctred.o \ + jdsample.o jdcolor.o jquant1.o jquant2.o jdmerge.o +# These objectfiles are included in libjpeg.lib +LIBOBJECTS= $(CLIBOBJECTS) $(DLIBOBJECTS) $(COMOBJECTS) +# object files for sample applications (excluding library files) +COBJECTS= cjpeg.o rdppm.o rdgif.o rdtarga.o rdrle.o rdbmp.o rdswitch.o \ + cdjpeg.o +DOBJECTS= djpeg.o wrppm.o wrgif.o wrtarga.o wrrle.o wrbmp.o rdcolmap.o \ + cdjpeg.o +TROBJECTS= jpegtran.o rdswitch.o cdjpeg.o transupp.o + + +all: libjpeg.lib cjpeg$(SUFFIX) djpeg$(SUFFIX) jpegtran$(SUFFIX) rdjpgcom$(SUFFIX) wrjpgcom$(SUFFIX) + +# note: do several AR steps to avoid command line length limitations + +libjpeg.lib: $(LIBOBJECTS) + -$(RM) libjpeg.lib + $(AR) libjpeg.lib r $(CLIBOBJECTS) + $(AR) libjpeg.lib r $(DLIBOBJECTS) + $(AR) libjpeg.lib r $(COMOBJECTS) + +cjpeg$(SUFFIX): $(COBJECTS) libjpeg.lib + $(LN) + +# You may want to adjust these compiler options: +CFLAGS= $(cflags) $(cdebug) $(cvars) -I. +# Generally, we recommend defining any configuration symbols in jconfig.h, +# NOT via -D switches here. + +# Link-time options: +LDFLAGS= $(ldebug) $(conlflags) + +# To link any special libraries, add the necessary commands here. +LDLIBS= $(conlibs) + +# Put here the object file name for the correct system-dependent memory +# manager file. For NT we suggest jmemnobs.obj, which expects the OS to +# provide adequate virtual memory. +SYSDEPMEM= jmemnobs.obj + +# miscellaneous OS-dependent stuff +# file deletion command +RM= del + +# End of configurable options. + + +# source files: JPEG library proper +LIBSOURCES= jcapimin.c jcapistd.c jccoefct.c jccolor.c jcdctmgr.c jchuff.c \ + jcinit.c jcmainct.c jcmarker.c jcmaster.c jcomapi.c jcparam.c \ + jcphuff.c jcprepct.c jcsample.c jctrans.c jdapimin.c jdapistd.c \ + jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c jddctmgr.c jdhuff.c \ + jdinput.c jdmainct.c jdmarker.c jdmaster.c jdmerge.c jdphuff.c \ + jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c jfdctfst.c \ + jfdctint.c jidctflt.c jidctfst.c jidctint.c jidctred.c jquant1.c \ + jquant2.c jutils.c jmemmgr.c +# memmgr back ends: compile only one of these into a working library +SYSDEPSOURCES= jmemansi.c jmemname.c jmemnobs.c jmemdos.c jmemmac.c +# source files: cjpeg/djpeg/jpegtran applications, also rdjpgcom/wrjpgcom +APPSOURCES= cjpeg.c djpeg.c jpegtran.c rdjpgcom.c wrjpgcom.c cdjpeg.c \ + rdcolmap.c rdswitch.c transupp.c rdppm.c wrppm.c rdgif.c wrgif.c \ + rdtarga.c wrtarga.c rdbmp.c wrbmp.c rdrle.c wrrle.c +SOURCES= $(LIBSOURCES) $(SYSDEPSOURCES) $(APPSOURCES) +# files included by source files +INCLUDES= jchuff.h jdhuff.h jdct.h jerror.h jinclude.h jmemsys.h jmorecfg.h \ + jpegint.h jpeglib.h jversion.h cdjpeg.h cderror.h transupp.h +# documentation, test, and support files +DOCS= README install.doc usage.doc cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 \ + wrjpgcom.1 wizard.doc example.c libjpeg.doc structure.doc \ + coderules.doc filelist.doc change.log +MKFILES= configure makefile.cfg makefile.ansi makefile.unix makefile.bcc \ + makefile.mc6 makefile.dj makefile.wat makefile.vc makelib.ds \ + makeapps.ds makeproj.mac makcjpeg.st makdjpeg.st makljpeg.st \ + maktjpeg.st makefile.manx makefile.sas makefile.mms makefile.vms \ + makvms.opt +CONFIGFILES= jconfig.cfg jconfig.bcc jconfig.mc6 jconfig.dj jconfig.wat \ + jconfig.vc jconfig.mac jconfig.st jconfig.manx jconfig.sas \ + jconfig.vms +CONFIGUREFILES= config.guess config.sub install-sh ltconfig ltmain.sh +OTHERFILES= jconfig.doc ckconfig.c ansi2knr.c ansi2knr.1 jmemdosa.asm +TESTFILES= testorig.jpg testimg.ppm testimg.bmp testimg.jpg testprog.jpg \ + testimgp.jpg +DISTFILES= $(DOCS) $(MKFILES) $(CONFIGFILES) $(SOURCES) $(INCLUDES) \ + $(CONFIGUREFILES) $(OTHERFILES) $(TESTFILES) +# library object files common to compression and decompression +COMOBJECTS= jcomapi.obj jutils.obj jerror.obj jmemmgr.obj $(SYSDEPMEM) +# compression library object files +CLIBOBJECTS= jcapimin.obj jcapistd.obj jctrans.obj jcparam.obj jdatadst.obj \ + jcinit.obj jcmaster.obj jcmarker.obj jcmainct.obj jcprepct.obj \ + jccoefct.obj jccolor.obj jcsample.obj jchuff.obj jcphuff.obj \ + jcdctmgr.obj jfdctfst.obj jfdctflt.obj jfdctint.obj +# decompression library object files +DLIBOBJECTS= jdapimin.obj jdapistd.obj jdtrans.obj jdatasrc.obj \ + jdmaster.obj jdinput.obj jdmarker.obj jdhuff.obj jdphuff.obj \ + jdmainct.obj jdcoefct.obj jdpostct.obj jddctmgr.obj jidctfst.obj \ + jidctflt.obj jidctint.obj jidctred.obj jdsample.obj jdcolor.obj \ + jquant1.obj jquant2.obj jdmerge.obj +# These objectfiles are included in libjpeg.lib +LIBOBJECTS= $(CLIBOBJECTS) $(DLIBOBJECTS) $(COMOBJECTS) +# object files for sample applications (excluding library files) +COBJECTS= cjpeg.obj rdppm.obj rdgif.obj rdtarga.obj rdrle.obj rdbmp.obj \ + rdswitch.obj cdjpeg.obj +DOBJECTS= djpeg.obj wrppm.obj wrgif.obj wrtarga.obj wrrle.obj wrbmp.obj \ + rdcolmap.obj cdjpeg.obj +TROBJECTS= jpegtran.obj rdswitch.obj cdjpeg.obj transupp.obj + +# Template command for compiling .c to .obj +.c.obj: + $(cc) $(CFLAGS) $*.c + + +all: libjpeg.lib cjpeg.exe djpeg.exe jpegtran.exe rdjpgcom.exe wrjpgcom.exe + +libjpeg.lib: $(LIBOBJECTS) + $(RM) libjpeg.lib + lib -out:libjpeg.lib $(LIBOBJECTS) + +cjpeg.exe: $(COBJECTS) libjpeg.lib + $(link) $(LDFLAGS) -out:cjpeg.exe $(COBJECTS) libjpeg.lib $(LDLIBS) + +djpeg.exe: $(DOBJECTS) libjpeg.lib + $(link) $(LDFLAGS) -out:djpeg.exe $(DOBJECTS) libjpeg.lib $(LDLIBS) + +jpegtran.exe: $(TROBJECTS) libjpeg.lib + $(link) $(LDFLAGS) -out:jpegtran.exe $(TROBJECTS) libjpeg.lib $(LDLIBS) + +rdjpgcom.exe: rdjpgcom.obj + $(link) $(LDFLAGS) -out:rdjpgcom.exe rdjpgcom.obj $(LDLIBS) + +wrjpgcom.exe: wrjpgcom.obj + $(link) $(LDFLAGS) -out:wrjpgcom.exe wrjpgcom.obj $(LDLIBS) + + +clean: + $(RM) *.obj *.exe libjpeg.lib + $(RM) testout* + +test: cjpeg.exe djpeg.exe jpegtran.exe + $(RM) testout* + .\djpeg -dct int -ppm -outfile testout.ppm testorig.jpg + .\djpeg -dct int -bmp -colors 256 -outfile testout.bmp testorig.jpg + .\cjpeg -dct int -outfile testout.jpg testimg.ppm + .\djpeg -dct int -ppm -outfile testoutp.ppm testprog.jpg + .\cjpeg -dct int -progressive -opt -outfile testoutp.jpg testimg.ppm + .\jpegtran -outfile testoutt.jpg testprog.jpg + fc /b testimg.ppm testout.ppm + fc /b testimg.bmp testout.bmp + fc /b testimg.jpg testout.jpg + fc /b testimg.ppm testoutp.ppm + fc /b testimgp.jpg testoutp.jpg + fc /b testorig.jpg testoutt.jpg + + +jcapimin.obj: jcapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcapistd.obj: jcapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jccoefct.obj: jccoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jccolor.obj: jccolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcdctmgr.obj: jcdctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jchuff.obj: jchuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jchuff.h +jcinit.obj: jcinit.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcmainct.obj: jcmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcmarker.obj: jcmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcmaster.obj: jcmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcomapi.obj: jcomapi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcparam.obj: jcparam.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcphuff.obj: jcphuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jchuff.h +jcprepct.obj: jcprepct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcsample.obj: jcsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jctrans.obj: jctrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdapimin.obj: jdapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdapistd.obj: jdapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdatadst.obj: jdatadst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h +jdatasrc.obj: jdatasrc.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h +jdcoefct.obj: jdcoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdcolor.obj: jdcolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jddctmgr.obj: jddctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jdhuff.obj: jdhuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdhuff.h +jdinput.obj: jdinput.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdmainct.obj: jdmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdmarker.obj: jdmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdmaster.obj: jdmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdmerge.obj: jdmerge.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdphuff.obj: jdphuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdhuff.h +jdpostct.obj: jdpostct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdsample.obj: jdsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdtrans.obj: jdtrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jerror.obj: jerror.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jversion.h jerror.h +jfdctflt.obj: jfdctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jfdctfst.obj: jfdctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jfdctint.obj: jfdctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jidctflt.obj: jidctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jidctfst.obj: jidctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jidctint.obj: jidctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jidctred.obj: jidctred.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jquant1.obj: jquant1.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jquant2.obj: jquant2.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jutils.obj: jutils.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jmemmgr.obj: jmemmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +jmemansi.obj: jmemansi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +jmemname.obj: jmemname.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +jmemnobs.obj: jmemnobs.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +jmemdos.obj: jmemdos.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +jmemmac.obj: jmemmac.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +cjpeg.obj: cjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h +djpeg.obj: djpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h +jpegtran.obj: jpegtran.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h transupp.h jversion.h +rdjpgcom.obj: rdjpgcom.c jinclude.h jconfig.h +wrjpgcom.obj: wrjpgcom.c jinclude.h jconfig.h +cdjpeg.obj: cdjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdcolmap.obj: rdcolmap.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdswitch.obj: rdswitch.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +transupp.obj: transupp.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h transupp.h +rdppm.obj: rdppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +wrppm.obj: wrppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdgif.obj: rdgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +wrgif.obj: wrgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdtarga.obj: rdtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +wrtarga.obj: wrtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdbmp.obj: rdbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +wrbmp.obj: wrbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdrle.obj: rdrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +wrrle.obj: wrrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h diff --git a/mk4/modimage/jpeg-6b/makefile.vms b/mk4/modimage/jpeg-6b/makefile.vms new file mode 100644 index 0000000..a42358d --- /dev/null +++ b/mk4/modimage/jpeg-6b/makefile.vms @@ -0,0 +1,142 @@ +$! Makefile for Independent JPEG Group's software +$! +$! This is a command procedure for Digital VMS systems that do not have MMS. +$! It builds the JPEG software by brute force, recompiling everything whether +$! or not it is necessary. It then runs the basic self-test. +$! Thanks to Rick Dyson (dyson@iowasp.physics.uiowa.edu) +$! and Tim Bell (tbell@netcom.com) for their help. +$! +$! Read installation instructions before running this!! +$! +$ If F$Mode () .eqs. "INTERACTIVE" +$ Then +$ VERIFY = F$Verify (0) +$ Else +$ VERIFY = F$Verify (1) +$ EndIf +$ On Control_Y Then GoTo End +$ On Error Then GoTo End +$ +$ If F$GetSyi ("HW_MODEL") .gt. 1023 +$ Then +$ OPT = "" +$ Else +$ OPT = ",Sys$Disk:[]makvms.opt/Option" +$ EndIf +$ +$ DoCompile := CC /NoDebug /Optimize /NoList +$! +$ DoCompile jcapimin.c +$ DoCompile jcapistd.c +$ DoCompile jctrans.c +$ DoCompile jcparam.c +$ DoCompile jdatadst.c +$ DoCompile jcinit.c +$ DoCompile jcmaster.c +$ DoCompile jcmarker.c +$ DoCompile jcmainct.c +$ DoCompile jcprepct.c +$ DoCompile jccoefct.c +$ DoCompile jccolor.c +$ DoCompile jcsample.c +$ DoCompile jchuff.c +$ DoCompile jcphuff.c +$ DoCompile jcdctmgr.c +$ DoCompile jfdctfst.c +$ DoCompile jfdctflt.c +$ DoCompile jfdctint.c +$ DoCompile jdapimin.c +$ DoCompile jdapistd.c +$ DoCompile jdtrans.c +$ DoCompile jdatasrc.c +$ DoCompile jdmaster.c +$ DoCompile jdinput.c +$ DoCompile jdmarker.c +$ DoCompile jdhuff.c +$ DoCompile jdphuff.c +$ DoCompile jdmainct.c +$ DoCompile jdcoefct.c +$ DoCompile jdpostct.c +$ DoCompile jddctmgr.c +$ DoCompile jidctfst.c +$ DoCompile jidctflt.c +$ DoCompile jidctint.c +$ DoCompile jidctred.c +$ DoCompile jdsample.c +$ DoCompile jdcolor.c +$ DoCompile jquant1.c +$ DoCompile jquant2.c +$ DoCompile jdmerge.c +$ DoCompile jcomapi.c +$ DoCompile jutils.c +$ DoCompile jerror.c +$ DoCompile jmemmgr.c +$ DoCompile jmemnobs.c +$! +$ Library /Create libjpeg.olb jcapimin.obj,jcapistd.obj,jctrans.obj, - + jcparam.obj,jdatadst.obj,jcinit.obj,jcmaster.obj,jcmarker.obj, - + jcmainct.obj,jcprepct.obj,jccoefct.obj,jccolor.obj,jcsample.obj, - + jchuff.obj,jcphuff.obj,jcdctmgr.obj,jfdctfst.obj,jfdctflt.obj, - + jfdctint.obj,jdapimin.obj,jdapistd.obj,jdtrans.obj,jdatasrc.obj, - + jdmaster.obj,jdinput.obj,jdmarker.obj,jdhuff.obj,jdphuff.obj, - + jdmainct.obj,jdcoefct.obj,jdpostct.obj,jddctmgr.obj,jidctfst.obj, - + jidctflt.obj,jidctint.obj,jidctred.obj,jdsample.obj,jdcolor.obj, - + jquant1.obj,jquant2.obj,jdmerge.obj,jcomapi.obj,jutils.obj, - + jerror.obj,jmemmgr.obj,jmemnobs.obj +$! +$ DoCompile cjpeg.c +$ DoCompile rdppm.c +$ DoCompile rdgif.c +$ DoCompile rdtarga.c +$ DoCompile rdrle.c +$ DoCompile rdbmp.c +$ DoCompile rdswitch.c +$ DoCompile cdjpeg.c +$! +$ Link /NoMap /Executable = cjpeg.exe cjpeg.obj,rdppm.obj,rdgif.obj, - + rdtarga.obj,rdrle.obj,rdbmp.obj,rdswitch.obj,cdjpeg.obj,libjpeg.olb/Library'OPT' +$! +$ DoCompile djpeg.c +$ DoCompile wrppm.c +$ DoCompile wrgif.c +$ DoCompile wrtarga.c +$ DoCompile wrrle.c +$ DoCompile wrbmp.c +$ DoCompile rdcolmap.c +$ DoCompile cdjpeg.c +$! +$ Link /NoMap /Executable = djpeg.exe djpeg.obj,wrppm.obj,wrgif.obj, - + wrtarga.obj,wrrle.obj,wrbmp.obj,rdcolmap.obj,cdjpeg.obj,libjpeg.olb/Library'OPT' +$! +$ DoCompile jpegtran.c +$ DoCompile rdswitch.c +$ DoCompile cdjpeg.c +$ DoCompile transupp.c +$! +$ Link /NoMap /Executable = jpegtran.exe jpegtran.obj,rdswitch.obj, - + cdjpeg.obj,transupp.obj,libjpeg.olb/Library'OPT' +$! +$ DoCompile rdjpgcom.c +$ Link /NoMap /Executable = rdjpgcom.exe rdjpgcom.obj'OPT' +$! +$ DoCompile wrjpgcom.c +$ Link /NoMap /Executable = wrjpgcom.exe wrjpgcom.obj'OPT' +$! +$! Run the self-test +$! +$ mcr sys$disk:[]djpeg -dct int -ppm -outfile testout.ppm testorig.jpg +$ mcr sys$disk:[]djpeg -dct int -bmp -colors 256 -outfile testout.bmp testorig.jpg +$ mcr sys$disk:[]cjpeg -dct int -outfile testout.jpg testimg.ppm +$ mcr sys$disk:[]djpeg -dct int -ppm -outfile testoutp.ppm testprog.jpg +$ mcr sys$disk:[]cjpeg -dct int -progressive -opt -outfile testoutp.jpg testimg.ppm +$ mcr sys$disk:[]jpegtran -outfile testoutt.jpg testprog.jpg +$ Backup /Compare/Log testimg.ppm testout.ppm +$ Backup /Compare/Log testimg.bmp testout.bmp +$ Backup /Compare/Log testimg.jpg testout.jpg +$ Backup /Compare/Log testimg.ppm testoutp.ppm +$ Backup /Compare/Log testimgp.jpg testoutp.jpg +$ Backup /Compare/Log testorig.jpg testoutt.jpg +$! +$End: +$ If Verify Then Set Verify +$ Exit diff --git a/mk4/modimage/jpeg-6b/makefile.wat b/mk4/modimage/jpeg-6b/makefile.wat new file mode 100644 index 0000000..d953e46 --- /dev/null +++ b/mk4/modimage/jpeg-6b/makefile.wat @@ -0,0 +1,233 @@ +# Makefile for Independent JPEG Group's software + +# This makefile is suitable for Watcom C/C++ 10.0 on MS-DOS (using +# dos4g extender), OS/2, and Windows NT console mode. +# Thanks to Janos Haide, jhaide@btrvtech.com. + +# Read installation instructions before saying "wmake" !! + +# Uncomment line for desired system +SYSTEM=DOS +#SYSTEM=OS2 +#SYSTEM=NT + +# The name of your C compiler: +CC= wcl386 + +# You may need to adjust these cc options: +CFLAGS= -4r -ort -wx -zq -bt=$(SYSTEM) +# Caution: avoid -ol or -ox; these generate bad code with 10.0 or 10.0a. +# Generally, we recommend defining any configuration symbols in jconfig.h, +# NOT via -D switches here. + +# Link-time cc options: +!ifeq SYSTEM DOS +LDFLAGS= -zq -l=dos4g +!else ifeq SYSTEM OS2 +LDFLAGS= -zq -l=os2v2 +!else ifeq SYSTEM NT +LDFLAGS= -zq -l=nt +!endif + +# Put here the object file name for the correct system-dependent memory +# manager file. jmemnobs should work fine for dos4g or OS/2 environment. +SYSDEPMEM= jmemnobs.obj + +# End of configurable options. + + +# source files: JPEG library proper +LIBSOURCES= jcapimin.c jcapistd.c jccoefct.c jccolor.c jcdctmgr.c jchuff.c & + jcinit.c jcmainct.c jcmarker.c jcmaster.c jcomapi.c jcparam.c & + jcphuff.c jcprepct.c jcsample.c jctrans.c jdapimin.c jdapistd.c & + jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c jddctmgr.c jdhuff.c & + jdinput.c jdmainct.c jdmarker.c jdmaster.c jdmerge.c jdphuff.c & + jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c jfdctfst.c & + jfdctint.c jidctflt.c jidctfst.c jidctint.c jidctred.c jquant1.c & + jquant2.c jutils.c jmemmgr.c +# memmgr back ends: compile only one of these into a working library +SYSDEPSOURCES= jmemansi.c jmemname.c jmemnobs.c jmemdos.c jmemmac.c +# source files: cjpeg/djpeg/jpegtran applications, also rdjpgcom/wrjpgcom +APPSOURCES= cjpeg.c djpeg.c jpegtran.c rdjpgcom.c wrjpgcom.c cdjpeg.c & + rdcolmap.c rdswitch.c transupp.c rdppm.c wrppm.c rdgif.c wrgif.c & + rdtarga.c wrtarga.c rdbmp.c wrbmp.c rdrle.c wrrle.c +SOURCES= $(LIBSOURCES) $(SYSDEPSOURCES) $(APPSOURCES) +# files included by source files +INCLUDES= jchuff.h jdhuff.h jdct.h jerror.h jinclude.h jmemsys.h jmorecfg.h & + jpegint.h jpeglib.h jversion.h cdjpeg.h cderror.h transupp.h +# documentation, test, and support files +DOCS= README install.doc usage.doc cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 & + wrjpgcom.1 wizard.doc example.c libjpeg.doc structure.doc & + coderules.doc filelist.doc change.log +MKFILES= configure makefile.cfg makefile.ansi makefile.unix makefile.bcc & + makefile.mc6 makefile.dj makefile.wat makefile.vc makelib.ds & + makeapps.ds makeproj.mac makcjpeg.st makdjpeg.st makljpeg.st & + maktjpeg.st makefile.manx makefile.sas makefile.mms makefile.vms & + makvms.opt +CONFIGFILES= jconfig.cfg jconfig.bcc jconfig.mc6 jconfig.dj jconfig.wat & + jconfig.vc jconfig.mac jconfig.st jconfig.manx jconfig.sas & + jconfig.vms +CONFIGUREFILES= config.guess config.sub install-sh ltconfig ltmain.sh +OTHERFILES= jconfig.doc ckconfig.c ansi2knr.c ansi2knr.1 jmemdosa.asm +TESTFILES= testorig.jpg testimg.ppm testimg.bmp testimg.jpg testprog.jpg & + testimgp.jpg +DISTFILES= $(DOCS) $(MKFILES) $(CONFIGFILES) $(SOURCES) $(INCLUDES) & + $(CONFIGUREFILES) $(OTHERFILES) $(TESTFILES) +# library object files common to compression and decompression +COMOBJECTS= jcomapi.obj jutils.obj jerror.obj jmemmgr.obj $(SYSDEPMEM) +# compression library object files +CLIBOBJECTS= jcapimin.obj jcapistd.obj jctrans.obj jcparam.obj jdatadst.obj & + jcinit.obj jcmaster.obj jcmarker.obj jcmainct.obj jcprepct.obj & + jccoefct.obj jccolor.obj jcsample.obj jchuff.obj jcphuff.obj & + jcdctmgr.obj jfdctfst.obj jfdctflt.obj jfdctint.obj +# decompression library object files +DLIBOBJECTS= jdapimin.obj jdapistd.obj jdtrans.obj jdatasrc.obj & + jdmaster.obj jdinput.obj jdmarker.obj jdhuff.obj jdphuff.obj & + jdmainct.obj jdcoefct.obj jdpostct.obj jddctmgr.obj jidctfst.obj & + jidctflt.obj jidctint.obj jidctred.obj jdsample.obj jdcolor.obj & + jquant1.obj jquant2.obj jdmerge.obj +# These objectfiles are included in libjpeg.lib +LIBOBJECTS= $(CLIBOBJECTS) $(DLIBOBJECTS) $(COMOBJECTS) +# object files for sample applications (excluding library files) +COBJECTS= cjpeg.obj rdppm.obj rdgif.obj rdtarga.obj rdrle.obj rdbmp.obj & + rdswitch.obj cdjpeg.obj +DOBJECTS= djpeg.obj wrppm.obj wrgif.obj wrtarga.obj wrrle.obj wrbmp.obj & + rdcolmap.obj cdjpeg.obj +TROBJECTS= jpegtran.obj rdswitch.obj cdjpeg.obj transupp.obj + + +all: libjpeg.lib cjpeg.exe djpeg.exe jpegtran.exe rdjpgcom.exe wrjpgcom.exe + +libjpeg.lib: $(LIBOBJECTS) + - del libjpeg.lib + * wlib -n libjpeg.lib $(LIBOBJECTS) + +cjpeg.exe: $(COBJECTS) libjpeg.lib + $(CC) $(LDFLAGS) $(COBJECTS) libjpeg.lib + +djpeg.exe: $(DOBJECTS) libjpeg.lib + $(CC) $(LDFLAGS) $(DOBJECTS) libjpeg.lib + +jpegtran.exe: $(TROBJECTS) libjpeg.lib + $(CC) $(LDFLAGS) $(TROBJECTS) libjpeg.lib + +rdjpgcom.exe: rdjpgcom.c + $(CC) $(CFLAGS) $(LDFLAGS) rdjpgcom.c + +wrjpgcom.exe: wrjpgcom.c + $(CC) $(CFLAGS) $(LDFLAGS) wrjpgcom.c + +.c.obj: + $(CC) $(CFLAGS) -c $< + +jconfig.h: jconfig.doc + echo You must prepare a system-dependent jconfig.h file. + echo Please read the installation directions in install.doc. + exit 1 + +clean: .SYMBOLIC + - del *.obj + - del libjpeg.lib + - del cjpeg.exe + - del djpeg.exe + - del jpegtran.exe + - del rdjpgcom.exe + - del wrjpgcom.exe + - del testout*.* + +test: cjpeg.exe djpeg.exe jpegtran.exe .SYMBOLIC + - del testout*.* + djpeg -dct int -ppm -outfile testout.ppm testorig.jpg + djpeg -dct int -bmp -colors 256 -outfile testout.bmp testorig.jpg + cjpeg -dct int -outfile testout.jpg testimg.ppm + djpeg -dct int -ppm -outfile testoutp.ppm testprog.jpg + cjpeg -dct int -progressive -opt -outfile testoutp.jpg testimg.ppm + jpegtran -outfile testoutt.jpg testprog.jpg +!ifeq SYSTEM DOS + fc /b testimg.ppm testout.ppm + fc /b testimg.bmp testout.bmp + fc /b testimg.jpg testout.jpg + fc /b testimg.ppm testoutp.ppm + fc /b testimgp.jpg testoutp.jpg + fc /b testorig.jpg testoutt.jpg +!else + echo n > n.tmp + comp testimg.ppm testout.ppm < n.tmp + comp testimg.bmp testout.bmp < n.tmp + comp testimg.jpg testout.jpg < n.tmp + comp testimg.ppm testoutp.ppm < n.tmp + comp testimgp.jpg testoutp.jpg < n.tmp + comp testorig.jpg testoutt.jpg < n.tmp + del n.tmp +!endif + + +jcapimin.obj: jcapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcapistd.obj: jcapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jccoefct.obj: jccoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jccolor.obj: jccolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcdctmgr.obj: jcdctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jchuff.obj: jchuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jchuff.h +jcinit.obj: jcinit.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcmainct.obj: jcmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcmarker.obj: jcmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcmaster.obj: jcmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcomapi.obj: jcomapi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcparam.obj: jcparam.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcphuff.obj: jcphuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jchuff.h +jcprepct.obj: jcprepct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jcsample.obj: jcsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jctrans.obj: jctrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdapimin.obj: jdapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdapistd.obj: jdapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdatadst.obj: jdatadst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h +jdatasrc.obj: jdatasrc.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h +jdcoefct.obj: jdcoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdcolor.obj: jdcolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jddctmgr.obj: jddctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jdhuff.obj: jdhuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdhuff.h +jdinput.obj: jdinput.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdmainct.obj: jdmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdmarker.obj: jdmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdmaster.obj: jdmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdmerge.obj: jdmerge.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdphuff.obj: jdphuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdhuff.h +jdpostct.obj: jdpostct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdsample.obj: jdsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jdtrans.obj: jdtrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jerror.obj: jerror.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jversion.h jerror.h +jfdctflt.obj: jfdctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jfdctfst.obj: jfdctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jfdctint.obj: jfdctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jidctflt.obj: jidctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jidctfst.obj: jidctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jidctint.obj: jidctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jidctred.obj: jidctred.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h +jquant1.obj: jquant1.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jquant2.obj: jquant2.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jutils.obj: jutils.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h +jmemmgr.obj: jmemmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +jmemansi.obj: jmemansi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +jmemname.obj: jmemname.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +jmemnobs.obj: jmemnobs.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +jmemdos.obj: jmemdos.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +jmemmac.obj: jmemmac.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h +cjpeg.obj: cjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h +djpeg.obj: djpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h +jpegtran.obj: jpegtran.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h transupp.h jversion.h +rdjpgcom.obj: rdjpgcom.c jinclude.h jconfig.h +wrjpgcom.obj: wrjpgcom.c jinclude.h jconfig.h +cdjpeg.obj: cdjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdcolmap.obj: rdcolmap.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdswitch.obj: rdswitch.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +transupp.obj: transupp.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h transupp.h +rdppm.obj: rdppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +wrppm.obj: wrppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdgif.obj: rdgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +wrgif.obj: wrgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdtarga.obj: rdtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +wrtarga.obj: wrtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdbmp.obj: rdbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +wrbmp.obj: wrbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +rdrle.obj: rdrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h +wrrle.obj: wrrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h diff --git a/mk4/modimage/jpeg-6b/makelib.ds b/mk4/modimage/jpeg-6b/makelib.ds new file mode 100644 index 0000000..c7ad36d --- /dev/null +++ b/mk4/modimage/jpeg-6b/makelib.ds @@ -0,0 +1,1046 @@ +# Microsoft Developer Studio Generated NMAKE File, Format Version 4.20 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +!IF "$(CFG)" == "" +CFG=jpeg - Win32 +!MESSAGE No configuration specified. Defaulting to jpeg - Win32. +!ENDIF + +!IF "$(CFG)" != "jpeg - Win32" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE on this makefile +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "jpeg.mak" CFG="jpeg - Win32" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "jpeg - Win32" (based on "Win32 (x86) Static Library") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF +################################################################################ +# Begin Project +# PROP Target_Last_Scanned "jpeg - Win32" +CPP=cl.exe + +!IF "$(CFG)" == "jpeg - Win32" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +OUTDIR=.\Release +INTDIR=.\Release + +ALL : "$(OUTDIR)\jpeg.lib" + +CLEAN : + -@erase "$(INTDIR)\jcapimin.obj" + -@erase "$(INTDIR)\jcapistd.obj" + -@erase "$(INTDIR)\jctrans.obj" + -@erase "$(INTDIR)\jcparam.obj" + -@erase "$(INTDIR)\jdatadst.obj" + -@erase "$(INTDIR)\jcinit.obj" + -@erase "$(INTDIR)\jcmaster.obj" + -@erase "$(INTDIR)\jcmarker.obj" + -@erase "$(INTDIR)\jcmainct.obj" + -@erase "$(INTDIR)\jcprepct.obj" + -@erase "$(INTDIR)\jccoefct.obj" + -@erase "$(INTDIR)\jccolor.obj" + -@erase "$(INTDIR)\jcsample.obj" + -@erase "$(INTDIR)\jchuff.obj" + -@erase "$(INTDIR)\jcphuff.obj" + -@erase "$(INTDIR)\jcdctmgr.obj" + -@erase "$(INTDIR)\jfdctfst.obj" + -@erase "$(INTDIR)\jfdctflt.obj" + -@erase "$(INTDIR)\jfdctint.obj" + -@erase "$(INTDIR)\jdapimin.obj" + -@erase "$(INTDIR)\jdapistd.obj" + -@erase "$(INTDIR)\jdtrans.obj" + -@erase "$(INTDIR)\jdatasrc.obj" + -@erase "$(INTDIR)\jdmaster.obj" + -@erase "$(INTDIR)\jdinput.obj" + -@erase "$(INTDIR)\jdmarker.obj" + -@erase "$(INTDIR)\jdhuff.obj" + -@erase "$(INTDIR)\jdphuff.obj" + -@erase "$(INTDIR)\jdmainct.obj" + -@erase "$(INTDIR)\jdcoefct.obj" + -@erase "$(INTDIR)\jdpostct.obj" + -@erase "$(INTDIR)\jddctmgr.obj" + -@erase "$(INTDIR)\jidctfst.obj" + -@erase "$(INTDIR)\jidctflt.obj" + -@erase "$(INTDIR)\jidctint.obj" + -@erase "$(INTDIR)\jidctred.obj" + -@erase "$(INTDIR)\jdsample.obj" + -@erase "$(INTDIR)\jdcolor.obj" + -@erase "$(INTDIR)\jquant1.obj" + -@erase "$(INTDIR)\jquant2.obj" + -@erase "$(INTDIR)\jdmerge.obj" + -@erase "$(INTDIR)\jcomapi.obj" + -@erase "$(INTDIR)\jutils.obj" + -@erase "$(INTDIR)\jerror.obj" + -@erase "$(INTDIR)\jmemmgr.obj" + -@erase "$(INTDIR)\jmemnobs.obj" + -@erase "$(OUTDIR)\jpeg.lib" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c +CPP_PROJ=/nologo /ML /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS"\ + /Fp"$(INTDIR)/jpeg.pch" /YX /Fo"$(INTDIR)/" /c +CPP_OBJS=.\Release/ +CPP_SBRS=.\. +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o"$(OUTDIR)/jpeg.bsc" +BSC32_SBRS= \ + +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo +LIB32_FLAGS=/nologo /out:"$(OUTDIR)/jpeg.lib" +LIB32_OBJS= \ + "$(INTDIR)\jcapimin.obj" \ + "$(INTDIR)\jcapistd.obj" \ + "$(INTDIR)\jctrans.obj" \ + "$(INTDIR)\jcparam.obj" \ + "$(INTDIR)\jdatadst.obj" \ + "$(INTDIR)\jcinit.obj" \ + "$(INTDIR)\jcmaster.obj" \ + "$(INTDIR)\jcmarker.obj" \ + "$(INTDIR)\jcmainct.obj" \ + "$(INTDIR)\jcprepct.obj" \ + "$(INTDIR)\jccoefct.obj" \ + "$(INTDIR)\jccolor.obj" \ + "$(INTDIR)\jcsample.obj" \ + "$(INTDIR)\jchuff.obj" \ + "$(INTDIR)\jcphuff.obj" \ + "$(INTDIR)\jcdctmgr.obj" \ + "$(INTDIR)\jfdctfst.obj" \ + "$(INTDIR)\jfdctflt.obj" \ + "$(INTDIR)\jfdctint.obj" \ + "$(INTDIR)\jdapimin.obj" \ + "$(INTDIR)\jdapistd.obj" \ + "$(INTDIR)\jdtrans.obj" \ + "$(INTDIR)\jdatasrc.obj" \ + "$(INTDIR)\jdmaster.obj" \ + "$(INTDIR)\jdinput.obj" \ + "$(INTDIR)\jdmarker.obj" \ + "$(INTDIR)\jdhuff.obj" \ + "$(INTDIR)\jdphuff.obj" \ + "$(INTDIR)\jdmainct.obj" \ + "$(INTDIR)\jdcoefct.obj" \ + "$(INTDIR)\jdpostct.obj" \ + "$(INTDIR)\jddctmgr.obj" \ + "$(INTDIR)\jidctfst.obj" \ + "$(INTDIR)\jidctflt.obj" \ + "$(INTDIR)\jidctint.obj" \ + "$(INTDIR)\jidctred.obj" \ + "$(INTDIR)\jdsample.obj" \ + "$(INTDIR)\jdcolor.obj" \ + "$(INTDIR)\jquant1.obj" \ + "$(INTDIR)\jquant2.obj" \ + "$(INTDIR)\jdmerge.obj" \ + "$(INTDIR)\jcomapi.obj" \ + "$(INTDIR)\jutils.obj" \ + "$(INTDIR)\jerror.obj" \ + "$(INTDIR)\jmemmgr.obj" \ + "$(INTDIR)\jmemnobs.obj" + +"$(OUTDIR)\jpeg.lib" : "$(OUTDIR)" $(DEF_FILE) $(LIB32_OBJS) + $(LIB32) @<< + $(LIB32_FLAGS) $(DEF_FLAGS) $(LIB32_OBJS) +<< + +!ENDIF + +.c{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.c{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +################################################################################ +# Begin Target + +# Name "jpeg - Win32" + +!IF "$(CFG)" == "jpeg - Win32" + +!ENDIF + +################################################################################ +# Begin Source File + +SOURCE="jcapimin.c" +DEP_CPP_JCAPI=\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jpegint.h"\ + "jerror.h"\ + + +"$(INTDIR)\jcapimin.obj" : $(SOURCE) $(DEP_CPP_JCAPI) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="jcapistd.c" +DEP_CPP_JCAPIS=\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jpegint.h"\ + "jerror.h"\ + + +"$(INTDIR)\jcapistd.obj" : $(SOURCE) $(DEP_CPP_JCAPIS) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="jccoefct.c" +DEP_CPP_JCCOE=\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jpegint.h"\ + "jerror.h"\ + + +"$(INTDIR)\jccoefct.obj" : $(SOURCE) $(DEP_CPP_JCCOE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="jccolor.c" +DEP_CPP_JCCOL=\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jpegint.h"\ + "jerror.h"\ + + +"$(INTDIR)\jccolor.obj" : $(SOURCE) $(DEP_CPP_JCCOL) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="jcdctmgr.c" +DEP_CPP_JCDCT=\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jpegint.h"\ + "jerror.h"\ + "jdct.h"\ + + +"$(INTDIR)\jcdctmgr.obj" : $(SOURCE) $(DEP_CPP_JCDCT) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="jchuff.c" +DEP_CPP_JCHUF=\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jpegint.h"\ + "jerror.h"\ + "jchuff.h"\ + + +"$(INTDIR)\jchuff.obj" : $(SOURCE) $(DEP_CPP_JCHUF) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="jcinit.c" +DEP_CPP_JCINI=\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jpegint.h"\ + "jerror.h"\ + + +"$(INTDIR)\jcinit.obj" : $(SOURCE) $(DEP_CPP_JCINI) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="jcmainct.c" +DEP_CPP_JCMAI=\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jpegint.h"\ + "jerror.h"\ + + +"$(INTDIR)\jcmainct.obj" : $(SOURCE) $(DEP_CPP_JCMAI) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="jcmarker.c" +DEP_CPP_JCMAR=\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jpegint.h"\ + "jerror.h"\ + + +"$(INTDIR)\jcmarker.obj" : $(SOURCE) $(DEP_CPP_JCMAR) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="jcmaster.c" +DEP_CPP_JCMAS=\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jpegint.h"\ + "jerror.h"\ + + +"$(INTDIR)\jcmaster.obj" : $(SOURCE) $(DEP_CPP_JCMAS) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="jcomapi.c" +DEP_CPP_JCOMA=\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jpegint.h"\ + "jerror.h"\ + + +"$(INTDIR)\jcomapi.obj" : $(SOURCE) $(DEP_CPP_JCOMA) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="jcparam.c" +DEP_CPP_JCPAR=\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jpegint.h"\ + "jerror.h"\ + + +"$(INTDIR)\jcparam.obj" : $(SOURCE) $(DEP_CPP_JCPAR) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="jcphuff.c" +DEP_CPP_JCPHU=\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jpegint.h"\ + "jerror.h"\ + "jchuff.h"\ + + +"$(INTDIR)\jcphuff.obj" : $(SOURCE) $(DEP_CPP_JCPHU) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="jcprepct.c" +DEP_CPP_JCPRE=\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jpegint.h"\ + "jerror.h"\ + + +"$(INTDIR)\jcprepct.obj" : $(SOURCE) $(DEP_CPP_JCPRE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="jcsample.c" +DEP_CPP_JCSAM=\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jpegint.h"\ + "jerror.h"\ + + +"$(INTDIR)\jcsample.obj" : $(SOURCE) $(DEP_CPP_JCSAM) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="jctrans.c" +DEP_CPP_JCTRA=\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jpegint.h"\ + "jerror.h"\ + + +"$(INTDIR)\jctrans.obj" : $(SOURCE) $(DEP_CPP_JCTRA) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="jdapimin.c" +DEP_CPP_JDAPI=\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jpegint.h"\ + "jerror.h"\ + + +"$(INTDIR)\jdapimin.obj" : $(SOURCE) $(DEP_CPP_JDAPI) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="jdapistd.c" +DEP_CPP_JDAPIS=\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jpegint.h"\ + "jerror.h"\ + + +"$(INTDIR)\jdapistd.obj" : $(SOURCE) $(DEP_CPP_JDAPIS) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="jdatadst.c" +DEP_CPP_JDATA=\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jerror.h"\ + + +"$(INTDIR)\jdatadst.obj" : $(SOURCE) $(DEP_CPP_JDATA) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="jdatasrc.c" +DEP_CPP_JDATAS=\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jerror.h"\ + + +"$(INTDIR)\jdatasrc.obj" : $(SOURCE) $(DEP_CPP_JDATAS) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="jdcoefct.c" +DEP_CPP_JDCOE=\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jpegint.h"\ + "jerror.h"\ + + +"$(INTDIR)\jdcoefct.obj" : $(SOURCE) $(DEP_CPP_JDCOE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="jdcolor.c" +DEP_CPP_JDCOL=\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jpegint.h"\ + "jerror.h"\ + + +"$(INTDIR)\jdcolor.obj" : $(SOURCE) $(DEP_CPP_JDCOL) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="jddctmgr.c" +DEP_CPP_JDDCT=\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jpegint.h"\ + "jerror.h"\ + "jdct.h"\ + + +"$(INTDIR)\jddctmgr.obj" : $(SOURCE) $(DEP_CPP_JDDCT) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="jdhuff.c" +DEP_CPP_JDHUF=\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jpegint.h"\ + "jerror.h"\ + "jdhuff.h"\ + + +"$(INTDIR)\jdhuff.obj" : $(SOURCE) $(DEP_CPP_JDHUF) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="jdinput.c" +DEP_CPP_JDINP=\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jpegint.h"\ + "jerror.h"\ + + +"$(INTDIR)\jdinput.obj" : $(SOURCE) $(DEP_CPP_JDINP) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="jdmainct.c" +DEP_CPP_JDMAI=\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jpegint.h"\ + "jerror.h"\ + + +"$(INTDIR)\jdmainct.obj" : $(SOURCE) $(DEP_CPP_JDMAI) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="jdmarker.c" +DEP_CPP_JDMAR=\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jpegint.h"\ + "jerror.h"\ + + +"$(INTDIR)\jdmarker.obj" : $(SOURCE) $(DEP_CPP_JDMAR) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="jdmaster.c" +DEP_CPP_JDMAS=\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jpegint.h"\ + "jerror.h"\ + + +"$(INTDIR)\jdmaster.obj" : $(SOURCE) $(DEP_CPP_JDMAS) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="jdmerge.c" +DEP_CPP_JDMER=\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jpegint.h"\ + "jerror.h"\ + + +"$(INTDIR)\jdmerge.obj" : $(SOURCE) $(DEP_CPP_JDMER) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="jdphuff.c" +DEP_CPP_JDPHU=\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jpegint.h"\ + "jerror.h"\ + "jdhuff.h"\ + + +"$(INTDIR)\jdphuff.obj" : $(SOURCE) $(DEP_CPP_JDPHU) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="jdpostct.c" +DEP_CPP_JDPOS=\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jpegint.h"\ + "jerror.h"\ + + +"$(INTDIR)\jdpostct.obj" : $(SOURCE) $(DEP_CPP_JDPOS) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="jdsample.c" +DEP_CPP_JDSAM=\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jpegint.h"\ + "jerror.h"\ + + +"$(INTDIR)\jdsample.obj" : $(SOURCE) $(DEP_CPP_JDSAM) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="jdtrans.c" +DEP_CPP_JDTRA=\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jpegint.h"\ + "jerror.h"\ + + +"$(INTDIR)\jdtrans.obj" : $(SOURCE) $(DEP_CPP_JDTRA) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="jerror.c" +DEP_CPP_JERRO=\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jversion.h"\ + "jerror.h"\ + + +"$(INTDIR)\jerror.obj" : $(SOURCE) $(DEP_CPP_JERRO) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="jfdctflt.c" +DEP_CPP_JFDCT=\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jpegint.h"\ + "jerror.h"\ + "jdct.h"\ + + +"$(INTDIR)\jfdctflt.obj" : $(SOURCE) $(DEP_CPP_JFDCT) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="jfdctfst.c" +DEP_CPP_JFDCTF=\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jpegint.h"\ + "jerror.h"\ + "jdct.h"\ + + +"$(INTDIR)\jfdctfst.obj" : $(SOURCE) $(DEP_CPP_JFDCTF) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="jfdctint.c" +DEP_CPP_JFDCTI=\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jpegint.h"\ + "jerror.h"\ + "jdct.h"\ + + +"$(INTDIR)\jfdctint.obj" : $(SOURCE) $(DEP_CPP_JFDCTI) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="jidctflt.c" +DEP_CPP_JIDCT=\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jpegint.h"\ + "jerror.h"\ + "jdct.h"\ + + +"$(INTDIR)\jidctflt.obj" : $(SOURCE) $(DEP_CPP_JIDCT) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="jidctfst.c" +DEP_CPP_JIDCTF=\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jpegint.h"\ + "jerror.h"\ + "jdct.h"\ + + +"$(INTDIR)\jidctfst.obj" : $(SOURCE) $(DEP_CPP_JIDCTF) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="jidctint.c" +DEP_CPP_JIDCTI=\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jpegint.h"\ + "jerror.h"\ + "jdct.h"\ + + +"$(INTDIR)\jidctint.obj" : $(SOURCE) $(DEP_CPP_JIDCTI) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="jidctred.c" +DEP_CPP_JIDCTR=\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jpegint.h"\ + "jerror.h"\ + "jdct.h"\ + + +"$(INTDIR)\jidctred.obj" : $(SOURCE) $(DEP_CPP_JIDCTR) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="jquant1.c" +DEP_CPP_JQUAN=\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jpegint.h"\ + "jerror.h"\ + + +"$(INTDIR)\jquant1.obj" : $(SOURCE) $(DEP_CPP_JQUAN) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="jquant2.c" +DEP_CPP_JQUANT=\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jpegint.h"\ + "jerror.h"\ + + +"$(INTDIR)\jquant2.obj" : $(SOURCE) $(DEP_CPP_JQUANT) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="jutils.c" +DEP_CPP_JUTIL=\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jpegint.h"\ + "jerror.h"\ + + +"$(INTDIR)\jutils.obj" : $(SOURCE) $(DEP_CPP_JUTIL) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="jmemmgr.c" +DEP_CPP_JMEMM=\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jpegint.h"\ + "jerror.h"\ + "jmemsys.h"\ + + +"$(INTDIR)\jmemmgr.obj" : $(SOURCE) $(DEP_CPP_JMEMM) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE="jmemnobs.c" +DEP_CPP_JMEMN=\ + "jinclude.h"\ + "jconfig.h"\ + "jpeglib.h"\ + "jmorecfg.h"\ + "jpegint.h"\ + "jerror.h"\ + "jmemsys.h"\ + + +"$(INTDIR)\jmemnobs.obj" : $(SOURCE) $(DEP_CPP_JMEMN) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +# End Target +# End Project +################################################################################ + diff --git a/mk4/modimage/jpeg-6b/makeproj.mac b/mk4/modimage/jpeg-6b/makeproj.mac new file mode 100644 index 0000000..ed277c8 --- /dev/null +++ b/mk4/modimage/jpeg-6b/makeproj.mac @@ -0,0 +1,213 @@ +-- +-- makeproj.mac +-- +-- This AppleScript builds Code Warrior PRO Release 2 project files for the +-- libjpeg library as well as the test programs 'cjpeg', 'djpeg', 'jpegtran'. +-- (We'd distribute real project files, except they're not text +-- and would create maintenance headaches.) +-- +-- The script then compiles and links the library and the test programs. +-- NOTE: if you haven't already created a 'jconfig.h' file, the script +-- automatically copies 'jconfig.mac' to 'jconfig.h'. +-- +-- To use this script, you must have AppleScript 1.1 or later installed +-- and a suitable AppleScript editor like Script Editor or Script Debugger +-- (http://www.latenightsw.com). Open this file with your AppleScript +-- editor and execute the "run" command to build the projects. +-- +-- Thanks to Dan Sears and Don Agro for this script. +-- Questions about this script can be addressed to dogpark@interlog.com +-- + +on run + + choose folder with prompt ">>> Select IJG source folder <<<" + set ijg_folder to result + + choose folder with prompt ">>> Select MetroWerks folder <<<" + set cw_folder to result + + -- if jconfig.h doesn't already exist, copy jconfig.mac + + tell application "Finder" + if not (exists file "jconfig.h" of ijg_folder) then + duplicate {file "jconfig.mac" of folder ijg_folder} + select file "jconfig.mac copy" of folder ijg_folder + set name of selection to "jconfig.h" + end if + end tell + + tell application "CodeWarrior IDE 2.1" + with timeout of 10000 seconds + + -- create libjpeg project + + activate + Create Project (ijg_folder as string) & "libjpeg.proj" + Set Preferences of panel "Target Settings" to {Target Name:"libjpeg"} + Set Preferences of panel "PPC Project" to {File Name:"libjpeg"} + Set Preferences of panel "Target Settings" to {Linker:"MacOS PPC Linker"} + Set Preferences of panel "PPC Project" to {Project Type:library} + Set Preferences of panel "C/C++ Compiler" to {ANSI Strict:true} + Set Preferences of panel "C/C++ Compiler" to {Enums Always Ints:true} + Set Preferences of panel "PPC Codegen" to {Struct Alignment:PowerPC} + Set Preferences of panel "PPC Linker" to {Generate SYM File:false} + + Add Files (ijg_folder as string) & "jcapimin.c" To Segment 1 + Add Files (ijg_folder as string) & "jcapistd.c" To Segment 1 + Add Files (ijg_folder as string) & "jctrans.c" To Segment 1 + Add Files (ijg_folder as string) & "jcparam.c" To Segment 1 + Add Files (ijg_folder as string) & "jdatadst.c" To Segment 1 + Add Files (ijg_folder as string) & "jcinit.c" To Segment 1 + Add Files (ijg_folder as string) & "jcmaster.c" To Segment 1 + Add Files (ijg_folder as string) & "jcmarker.c" To Segment 1 + Add Files (ijg_folder as string) & "jcmainct.c" To Segment 1 + Add Files (ijg_folder as string) & "jcprepct.c" To Segment 1 + Add Files (ijg_folder as string) & "jccoefct.c" To Segment 1 + Add Files (ijg_folder as string) & "jccolor.c" To Segment 1 + Add Files (ijg_folder as string) & "jcsample.c" To Segment 1 + Add Files (ijg_folder as string) & "jchuff.c" To Segment 1 + Add Files (ijg_folder as string) & "jcphuff.c" To Segment 1 + Add Files (ijg_folder as string) & "jcdctmgr.c" To Segment 1 + Add Files (ijg_folder as string) & "jfdctfst.c" To Segment 1 + Add Files (ijg_folder as string) & "jfdctflt.c" To Segment 1 + Add Files (ijg_folder as string) & "jfdctint.c" To Segment 1 + Add Files (ijg_folder as string) & "jdapimin.c" To Segment 1 + Add Files (ijg_folder as string) & "jdapistd.c" To Segment 1 + Add Files (ijg_folder as string) & "jdtrans.c" To Segment 1 + Add Files (ijg_folder as string) & "jdatasrc.c" To Segment 1 + Add Files (ijg_folder as string) & "jdmaster.c" To Segment 1 + Add Files (ijg_folder as string) & "jdinput.c" To Segment 1 + Add Files (ijg_folder as string) & "jdmarker.c" To Segment 1 + Add Files (ijg_folder as string) & "jdhuff.c" To Segment 1 + Add Files (ijg_folder as string) & "jdphuff.c" To Segment 1 + Add Files (ijg_folder as string) & "jdmainct.c" To Segment 1 + Add Files (ijg_folder as string) & "jdcoefct.c" To Segment 1 + Add Files (ijg_folder as string) & "jdpostct.c" To Segment 1 + Add Files (ijg_folder as string) & "jddctmgr.c" To Segment 1 + Add Files (ijg_folder as string) & "jidctfst.c" To Segment 1 + Add Files (ijg_folder as string) & "jidctflt.c" To Segment 1 + Add Files (ijg_folder as string) & "jidctint.c" To Segment 1 + Add Files (ijg_folder as string) & "jidctred.c" To Segment 1 + Add Files (ijg_folder as string) & "jdsample.c" To Segment 1 + Add Files (ijg_folder as string) & "jdcolor.c" To Segment 1 + Add Files (ijg_folder as string) & "jquant1.c" To Segment 1 + Add Files (ijg_folder as string) & "jquant2.c" To Segment 1 + Add Files (ijg_folder as string) & "jdmerge.c" To Segment 1 + Add Files (ijg_folder as string) & "jcomapi.c" To Segment 1 + Add Files (ijg_folder as string) & "jutils.c" To Segment 1 + Add Files (ijg_folder as string) & "jerror.c" To Segment 1 + Add Files (ijg_folder as string) & "jmemmgr.c" To Segment 1 + Add Files (ijg_folder as string) & "jmemmac.c" To Segment 1 + + -- compile and link the library + + Make Project + Close Project + + -- create cjpeg project + + activate + Create Project (ijg_folder as string) & "cjpeg.proj" + Set Preferences of panel "Target Settings" to {Target Name:"cjpeg"} + Set Preferences of panel "PPC Project" to {File Name:"cjpeg"} + Set Preferences of panel "Target Settings" to {Linker:"MacOS PPC Linker"} + Set Preferences of panel "C/C++ Compiler" to {ANSI Strict:true} + Set Preferences of panel "C/C++ Compiler" to {Enums Always Ints:true} + Set Preferences of panel "PPC Codegen" to {Struct Alignment:PowerPC} + Set Preferences of panel "PPC Linker" to {Generate SYM File:false} + + Add Files (ijg_folder as string) & "cjpeg.c" To Segment 1 + Add Files (ijg_folder as string) & "rdppm.c" To Segment 1 + Add Files (ijg_folder as string) & "rdgif.c" To Segment 1 + Add Files (ijg_folder as string) & "rdtarga.c" To Segment 1 + Add Files (ijg_folder as string) & "rdrle.c" To Segment 1 + Add Files (ijg_folder as string) & "rdbmp.c" To Segment 1 + Add Files (ijg_folder as string) & "rdswitch.c" To Segment 1 + Add Files (ijg_folder as string) & "cdjpeg.c" To Segment 1 + + Add Files (ijg_folder as string) & "libjpeg" To Segment 2 + + Add Files (cw_folder as string) & "Metrowerks CodeWarrior:Metrowerks Standard Library:MSL C:Bin:MSL C.PPC.Lib" To Segment 3 + Add Files (cw_folder as string) & "Metrowerks CodeWarrior:Metrowerks Standard Library:MSL C:Bin:MSL SIOUX.PPC.Lib" To Segment 3 + Add Files (cw_folder as string) & "Metrowerks CodeWarrior:MacOS Support:Libraries:Runtime:Runtime PPC:MSL RuntimePPC.Lib" To Segment 3 + + Add Files (cw_folder as string) & "Metrowerks CodeWarrior:MacOS Support:Libraries:MacOS Common:InterfaceLib" To Segment 4 + Add Files (cw_folder as string) & "Metrowerks CodeWarrior:MacOS Support:Libraries:MacOS Common:MathLib" To Segment 4 + + -- compile and link cjpeg + + Make Project + Close Project + + -- create djpeg project + + activate + Create Project (ijg_folder as string) & "djpeg.proj" + Set Preferences of panel "Target Settings" to {Target Name:"djpeg"} + Set Preferences of panel "PPC Project" to {File Name:"djpeg"} + Set Preferences of panel "Target Settings" to {Linker:"MacOS PPC Linker"} + Set Preferences of panel "C/C++ Compiler" to {ANSI Strict:true} + Set Preferences of panel "C/C++ Compiler" to {Enums Always Ints:true} + Set Preferences of panel "PPC Codegen" to {Struct Alignment:PowerPC} + Set Preferences of panel "PPC Linker" to {Generate SYM File:false} + + Add Files (ijg_folder as string) & "djpeg.c" To Segment 1 + Add Files (ijg_folder as string) & "wrppm.c" To Segment 1 + Add Files (ijg_folder as string) & "wrgif.c" To Segment 1 + Add Files (ijg_folder as string) & "wrtarga.c" To Segment 1 + Add Files (ijg_folder as string) & "wrrle.c" To Segment 1 + Add Files (ijg_folder as string) & "wrbmp.c" To Segment 1 + Add Files (ijg_folder as string) & "rdcolmap.c" To Segment 1 + Add Files (ijg_folder as string) & "cdjpeg.c" To Segment 1 + + Add Files (ijg_folder as string) & "libjpeg" To Segment 2 + + Add Files (cw_folder as string) & "Metrowerks CodeWarrior:Metrowerks Standard Library:MSL C:Bin:MSL C.PPC.Lib" To Segment 3 + Add Files (cw_folder as string) & "Metrowerks CodeWarrior:Metrowerks Standard Library:MSL C:Bin:MSL SIOUX.PPC.Lib" To Segment 3 + Add Files (cw_folder as string) & "Metrowerks CodeWarrior:MacOS Support:Libraries:Runtime:Runtime PPC:MSL RuntimePPC.Lib" To Segment 3 + + Add Files (cw_folder as string) & "Metrowerks CodeWarrior:MacOS Support:Libraries:MacOS Common:InterfaceLib" To Segment 4 + Add Files (cw_folder as string) & "Metrowerks CodeWarrior:MacOS Support:Libraries:MacOS Common:MathLib" To Segment 4 + + -- compile and link djpeg + + Make Project + Close Project + + -- create jpegtran project + + activate + Create Project (ijg_folder as string) & "jpegtran.proj" + Set Preferences of panel "Target Settings" to {Target Name:"jpegtran"} + Set Preferences of panel "PPC Project" to {File Name:"jpegtran"} + Set Preferences of panel "Target Settings" to {Linker:"MacOS PPC Linker"} + Set Preferences of panel "C/C++ Compiler" to {ANSI Strict:true} + Set Preferences of panel "C/C++ Compiler" to {Enums Always Ints:true} + Set Preferences of panel "PPC Codegen" to {Struct Alignment:PowerPC} + Set Preferences of panel "PPC Linker" to {Generate SYM File:false} + + Add Files (ijg_folder as string) & "jpegtran.c" To Segment 1 + Add Files (ijg_folder as string) & "rdswitch.c" To Segment 1 + Add Files (ijg_folder as string) & "cdjpeg.c" To Segment 1 + Add Files (ijg_folder as string) & "transupp.c" To Segment 1 + + Add Files (ijg_folder as string) & "libjpeg" To Segment 2 + + Add Files (cw_folder as string) & "Metrowerks CodeWarrior:Metrowerks Standard Library:MSL C:Bin:MSL C.PPC.Lib" To Segment 3 + Add Files (cw_folder as string) & "Metrowerks CodeWarrior:Metrowerks Standard Library:MSL C:Bin:MSL SIOUX.PPC.Lib" To Segment 3 + Add Files (cw_folder as string) & "Metrowerks CodeWarrior:MacOS Support:Libraries:Runtime:Runtime PPC:MSL RuntimePPC.Lib" To Segment 3 + + Add Files (cw_folder as string) & "Metrowerks CodeWarrior:MacOS Support:Libraries:MacOS Common:InterfaceLib" To Segment 4 + Add Files (cw_folder as string) & "Metrowerks CodeWarrior:MacOS Support:Libraries:MacOS Common:MathLib" To Segment 4 + + -- compile and link jpegtran + + Make Project + Close Project + + quit + + end timeout + end tell +end run diff --git a/mk4/modimage/jpeg-6b/makljpeg.st b/mk4/modimage/jpeg-6b/makljpeg.st new file mode 100644 index 0000000..813493e --- /dev/null +++ b/mk4/modimage/jpeg-6b/makljpeg.st @@ -0,0 +1,70 @@ +; Project file for Independent JPEG Group's software +; +; This project file is for Atari ST/STE/TT systems using Pure C or Turbo C. +; Thanks to Frank Moehle (Frank.Moehle@arbi.informatik.uni-oldenburg.de), +; Dr. B. Setzepfandt (bernd@gina.uni-muenster.de), +; and Guido Vollbeding (guivol@esc.de). +; +; To use this file, rename it to libjpeg.prj. +; Read installation instructions before trying to make the program! +; +; +; * * * Output file * * * +libjpeg.lib +; +; * * * COMPILER OPTIONS * * * +.C[-P] ; absolute calls +.C[-M] ; and no string merging, folks +.C[-w-cln] ; no "constant is long" warnings +.C[-w-par] ; no "parameter xxxx unused" +.C[-w-rch] ; no "unreachable code" +.C[-wsig] ; warn if significant digits may be lost +.L[-J] ; link new Obj-format (so we get a library) += +; * * * * List of modules * * * * +jcapimin.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h) +jcapistd.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h) +jccoefct.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h) +jccolor.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h) +jcdctmgr.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,jdct.h) +jchuff.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,jchuff.h) +jcinit.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h) +jcmainct.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h) +jcmarker.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h) +jcmaster.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h) +jcomapi.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h) +jcparam.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h) +jcphuff.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,jchuff.h) +jcprepct.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h) +jcsample.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h) +jctrans.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h) +jdapimin.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h) +jdapistd.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h) +jdatadst.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h) +jdatasrc.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h) +jdcoefct.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h) +jdcolor.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h) +jddctmgr.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,jdct.h) +jdhuff.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,jdhuff.h) +jdinput.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h) +jdmainct.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h) +jdmarker.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h) +jdmaster.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h) +jdmerge.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h) +jdphuff.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,jdhuff.h) +jdpostct.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h) +jdsample.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h) +jdtrans.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h) +jerror.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jversion.h,jerror.h) +jfdctflt.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,jdct.h) +jfdctfst.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,jdct.h) +jfdctint.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,jdct.h) +jidctflt.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,jdct.h) +jidctfst.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,jdct.h) +jidctint.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,jdct.h) +jidctred.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,jdct.h) +jquant1.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h) +jquant2.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h) +jutils.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h) +jmemmgr.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,jmemsys.h) +jmemansi.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,jmemsys.h) diff --git a/mk4/modimage/jpeg-6b/maktjpeg.st b/mk4/modimage/jpeg-6b/maktjpeg.st new file mode 100644 index 0000000..31f4d16 --- /dev/null +++ b/mk4/modimage/jpeg-6b/maktjpeg.st @@ -0,0 +1,32 @@ +; Project file for Independent JPEG Group's software +; +; This project file is for Atari ST/STE/TT systems using Pure C or Turbo C. +; Thanks to Frank Moehle (Frank.Moehle@arbi.informatik.uni-oldenburg.de), +; Dr. B. Setzepfandt (bernd@gina.uni-muenster.de), +; and Guido Vollbeding (guivol@esc.de). +; +; To use this file, rename it to jpegtran.prj. +; If you are using Turbo C, change filenames beginning with "pc..." to "tc..." +; Read installation instructions before trying to make the program! +; +; +; * * * Output file * * * +jpegtran.ttp +; +; * * * COMPILER OPTIONS * * * +.C[-P] ; absolute calls +.C[-M] ; and no string merging, folks +.C[-w-cln] ; no "constant is long" warnings +.C[-w-par] ; no "parameter xxxx unused" +.C[-w-rch] ; no "unreachable code" +.C[-wsig] ; warn if significant digits may be lost += +; * * * * List of modules * * * * +pcstart.o +jpegtran.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h,transupp.h,jversion.h) +cdjpeg.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h) +rdswitch.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h) +transupp.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,transupp.h) +libjpeg.lib ; built by libjpeg.prj +pcstdlib.lib ; standard library +pcextlib.lib ; extended library diff --git a/mk4/modimage/jpeg-6b/makvms.opt b/mk4/modimage/jpeg-6b/makvms.opt new file mode 100644 index 0000000..675e8fe --- /dev/null +++ b/mk4/modimage/jpeg-6b/makvms.opt @@ -0,0 +1,4 @@ +! A pointer to the VAX/VMS C Run-Time Shareable Library. +! This file is needed by makefile.mms and makefile.vms, +! but only for the older VAX C compiler. DEC C does not need it. +Sys$Library:VAXCRTL.EXE /Share diff --git a/mk4/modimage/jpeg-6b/rdbmp.c b/mk4/modimage/jpeg-6b/rdbmp.c new file mode 100644 index 0000000..b05fe2a --- /dev/null +++ b/mk4/modimage/jpeg-6b/rdbmp.c @@ -0,0 +1,439 @@ +/* + * rdbmp.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to read input images in Microsoft "BMP" + * format (MS Windows 3.x, OS/2 1.x, and OS/2 2.x flavors). + * Currently, only 8-bit and 24-bit images are supported, not 1-bit or + * 4-bit (feeding such low-depth images into JPEG would be silly anyway). + * Also, we don't support RLE-compressed files. + * + * These routines may need modification for non-Unix environments or + * specialized applications. As they stand, they assume input from + * an ordinary stdio stream. They further assume that reading begins + * at the start of the file; start_input may need work if the + * user interface has already read some data (e.g., to determine that + * the file is indeed BMP format). + * + * This code contributed by James Arthur Boucher. + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ + +#ifdef BMP_SUPPORTED + + +/* Macros to deal with unsigned chars as efficiently as compiler allows */ + +#ifdef HAVE_UNSIGNED_CHAR +typedef unsigned char U_CHAR; +#define UCH(x) ((int) (x)) +#else /* !HAVE_UNSIGNED_CHAR */ +#ifdef CHAR_IS_UNSIGNED +typedef char U_CHAR; +#define UCH(x) ((int) (x)) +#else +typedef char U_CHAR; +#define UCH(x) ((int) (x) & 0xFF) +#endif +#endif /* HAVE_UNSIGNED_CHAR */ + + +#define ReadOK(file,buffer,len) (JFREAD(file,buffer,len) == ((size_t) (len))) + + +/* Private version of data source object */ + +typedef struct _bmp_source_struct * bmp_source_ptr; + +typedef struct _bmp_source_struct { + struct cjpeg_source_struct pub; /* public fields */ + + j_compress_ptr cinfo; /* back link saves passing separate parm */ + + JSAMPARRAY colormap; /* BMP colormap (converted to my format) */ + + jvirt_sarray_ptr whole_image; /* Needed to reverse row order */ + JDIMENSION source_row; /* Current source row number */ + JDIMENSION row_width; /* Physical width of scanlines in file */ + + int bits_per_pixel; /* remembers 8- or 24-bit format */ +} bmp_source_struct; + + +LOCAL(int) +read_byte (bmp_source_ptr sinfo) +/* Read next byte from BMP file */ +{ + register FILE *infile = sinfo->pub.input_file; + register int c; + + if ((c = getc(infile)) == EOF) + ERREXIT(sinfo->cinfo, JERR_INPUT_EOF); + return c; +} + + +LOCAL(void) +read_colormap (bmp_source_ptr sinfo, int cmaplen, int mapentrysize) +/* Read the colormap from a BMP file */ +{ + int i; + + switch (mapentrysize) { + case 3: + /* BGR format (occurs in OS/2 files) */ + for (i = 0; i < cmaplen; i++) { + sinfo->colormap[2][i] = (JSAMPLE) read_byte(sinfo); + sinfo->colormap[1][i] = (JSAMPLE) read_byte(sinfo); + sinfo->colormap[0][i] = (JSAMPLE) read_byte(sinfo); + } + break; + case 4: + /* BGR0 format (occurs in MS Windows files) */ + for (i = 0; i < cmaplen; i++) { + sinfo->colormap[2][i] = (JSAMPLE) read_byte(sinfo); + sinfo->colormap[1][i] = (JSAMPLE) read_byte(sinfo); + sinfo->colormap[0][i] = (JSAMPLE) read_byte(sinfo); + (void) read_byte(sinfo); + } + break; + default: + ERREXIT(sinfo->cinfo, JERR_BMP_BADCMAP); + break; + } +} + + +/* + * Read one row of pixels. + * The image has been read into the whole_image array, but is otherwise + * unprocessed. We must read it out in top-to-bottom row order, and if + * it is an 8-bit image, we must expand colormapped pixels to 24bit format. + */ + +METHODDEF(JDIMENSION) +get_8bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +/* This version is for reading 8-bit colormap indexes */ +{ + bmp_source_ptr source = (bmp_source_ptr) sinfo; + register JSAMPARRAY colormap = source->colormap; + JSAMPARRAY image_ptr; + register int t; + register JSAMPROW inptr, outptr; + register JDIMENSION col; + + /* Fetch next row from virtual array */ + source->source_row--; + image_ptr = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, source->whole_image, + source->source_row, (JDIMENSION) 1, FALSE); + + /* Expand the colormap indexes to real data */ + inptr = image_ptr[0]; + outptr = source->pub.buffer[0]; + for (col = cinfo->image_width; col > 0; col--) { + t = GETJSAMPLE(*inptr++); + *outptr++ = colormap[0][t]; /* can omit GETJSAMPLE() safely */ + *outptr++ = colormap[1][t]; + *outptr++ = colormap[2][t]; + } + + return 1; +} + + +METHODDEF(JDIMENSION) +get_24bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +/* This version is for reading 24-bit pixels */ +{ + bmp_source_ptr source = (bmp_source_ptr) sinfo; + JSAMPARRAY image_ptr; + register JSAMPROW inptr, outptr; + register JDIMENSION col; + + /* Fetch next row from virtual array */ + source->source_row--; + image_ptr = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, source->whole_image, + source->source_row, (JDIMENSION) 1, FALSE); + + /* Transfer data. Note source values are in BGR order + * (even though Microsoft's own documents say the opposite). + */ + inptr = image_ptr[0]; + outptr = source->pub.buffer[0]; + for (col = cinfo->image_width; col > 0; col--) { + outptr[2] = *inptr++; /* can omit GETJSAMPLE() safely */ + outptr[1] = *inptr++; + outptr[0] = *inptr++; + outptr += 3; + } + + return 1; +} + + +/* + * This method loads the image into whole_image during the first call on + * get_pixel_rows. The get_pixel_rows pointer is then adjusted to call + * get_8bit_row or get_24bit_row on subsequent calls. + */ + +METHODDEF(JDIMENSION) +preload_image (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +{ + bmp_source_ptr source = (bmp_source_ptr) sinfo; + register FILE *infile = source->pub.input_file; + register int c; + register JSAMPROW out_ptr; + JSAMPARRAY image_ptr; + JDIMENSION row, col; + cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress; + + /* Read the data into a virtual array in input-file row order. */ + for (row = 0; row < cinfo->image_height; row++) { + if (progress != NULL) { + progress->pub.pass_counter = (long) row; + progress->pub.pass_limit = (long) cinfo->image_height; + (*progress->pub.progress_monitor) ((j_common_ptr) cinfo); + } + image_ptr = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, source->whole_image, + row, (JDIMENSION) 1, TRUE); + out_ptr = image_ptr[0]; + for (col = source->row_width; col > 0; col--) { + /* inline copy of read_byte() for speed */ + if ((c = getc(infile)) == EOF) + ERREXIT(cinfo, JERR_INPUT_EOF); + *out_ptr++ = (JSAMPLE) c; + } + } + if (progress != NULL) + progress->completed_extra_passes++; + + /* Set up to read from the virtual array in top-to-bottom order */ + switch (source->bits_per_pixel) { + case 8: + source->pub.get_pixel_rows = get_8bit_row; + break; + case 24: + source->pub.get_pixel_rows = get_24bit_row; + break; + default: + ERREXIT(cinfo, JERR_BMP_BADDEPTH); + } + source->source_row = cinfo->image_height; + + /* And read the first row */ + return (*source->pub.get_pixel_rows) (cinfo, sinfo); +} + + +/* + * Read the file header; return image size and component count. + */ + +METHODDEF(void) +start_input_bmp (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +{ + bmp_source_ptr source = (bmp_source_ptr) sinfo; + U_CHAR bmpfileheader[14]; + U_CHAR bmpinfoheader[64]; +#define GET_2B(array,offset) ((unsigned int) UCH(array[offset]) + \ + (((unsigned int) UCH(array[offset+1])) << 8)) +#define GET_4B(array,offset) ((INT32) UCH(array[offset]) + \ + (((INT32) UCH(array[offset+1])) << 8) + \ + (((INT32) UCH(array[offset+2])) << 16) + \ + (((INT32) UCH(array[offset+3])) << 24)) + INT32 bfOffBits; + INT32 headerSize; + INT32 biWidth = 0; /* initialize to avoid compiler warning */ + INT32 biHeight = 0; + unsigned int biPlanes; + INT32 biCompression; + INT32 biXPelsPerMeter,biYPelsPerMeter; + INT32 biClrUsed = 0; + int mapentrysize = 0; /* 0 indicates no colormap */ + INT32 bPad; + JDIMENSION row_width; + + /* Read and verify the bitmap file header */ + if (! ReadOK(source->pub.input_file, bmpfileheader, 14)) + ERREXIT(cinfo, JERR_INPUT_EOF); + if (GET_2B(bmpfileheader,0) != 0x4D42) /* 'BM' */ + ERREXIT(cinfo, JERR_BMP_NOT); + bfOffBits = (INT32) GET_4B(bmpfileheader,10); + /* We ignore the remaining fileheader fields */ + + /* The infoheader might be 12 bytes (OS/2 1.x), 40 bytes (Windows), + * or 64 bytes (OS/2 2.x). Check the first 4 bytes to find out which. + */ + if (! ReadOK(source->pub.input_file, bmpinfoheader, 4)) + ERREXIT(cinfo, JERR_INPUT_EOF); + headerSize = (INT32) GET_4B(bmpinfoheader,0); + if (headerSize < 12 || headerSize > 64) + ERREXIT(cinfo, JERR_BMP_BADHEADER); + if (! ReadOK(source->pub.input_file, bmpinfoheader+4, headerSize-4)) + ERREXIT(cinfo, JERR_INPUT_EOF); + + switch ((int) headerSize) { + case 12: + /* Decode OS/2 1.x header (Microsoft calls this a BITMAPCOREHEADER) */ + biWidth = (INT32) GET_2B(bmpinfoheader,4); + biHeight = (INT32) GET_2B(bmpinfoheader,6); + biPlanes = GET_2B(bmpinfoheader,8); + source->bits_per_pixel = (int) GET_2B(bmpinfoheader,10); + + switch (source->bits_per_pixel) { + case 8: /* colormapped image */ + mapentrysize = 3; /* OS/2 uses RGBTRIPLE colormap */ + TRACEMS2(cinfo, 1, JTRC_BMP_OS2_MAPPED, (int) biWidth, (int) biHeight); + break; + case 24: /* RGB image */ + TRACEMS2(cinfo, 1, JTRC_BMP_OS2, (int) biWidth, (int) biHeight); + break; + default: + ERREXIT(cinfo, JERR_BMP_BADDEPTH); + break; + } + if (biPlanes != 1) + ERREXIT(cinfo, JERR_BMP_BADPLANES); + break; + case 40: + case 64: + /* Decode Windows 3.x header (Microsoft calls this a BITMAPINFOHEADER) */ + /* or OS/2 2.x header, which has additional fields that we ignore */ + biWidth = GET_4B(bmpinfoheader,4); + biHeight = GET_4B(bmpinfoheader,8); + biPlanes = GET_2B(bmpinfoheader,12); + source->bits_per_pixel = (int) GET_2B(bmpinfoheader,14); + biCompression = GET_4B(bmpinfoheader,16); + biXPelsPerMeter = GET_4B(bmpinfoheader,24); + biYPelsPerMeter = GET_4B(bmpinfoheader,28); + biClrUsed = GET_4B(bmpinfoheader,32); + /* biSizeImage, biClrImportant fields are ignored */ + + switch (source->bits_per_pixel) { + case 8: /* colormapped image */ + mapentrysize = 4; /* Windows uses RGBQUAD colormap */ + TRACEMS2(cinfo, 1, JTRC_BMP_MAPPED, (int) biWidth, (int) biHeight); + break; + case 24: /* RGB image */ + TRACEMS2(cinfo, 1, JTRC_BMP, (int) biWidth, (int) biHeight); + break; + default: + ERREXIT(cinfo, JERR_BMP_BADDEPTH); + break; + } + if (biPlanes != 1) + ERREXIT(cinfo, JERR_BMP_BADPLANES); + if (biCompression != 0) + ERREXIT(cinfo, JERR_BMP_COMPRESSED); + + if (biXPelsPerMeter > 0 && biYPelsPerMeter > 0) { + /* Set JFIF density parameters from the BMP data */ + cinfo->X_density = (UINT16) (biXPelsPerMeter/100); /* 100 cm per meter */ + cinfo->Y_density = (UINT16) (biYPelsPerMeter/100); + cinfo->density_unit = 2; /* dots/cm */ + } + break; + default: + ERREXIT(cinfo, JERR_BMP_BADHEADER); + break; + } + + /* Compute distance to bitmap data --- will adjust for colormap below */ + bPad = bfOffBits - (headerSize + 14); + + /* Read the colormap, if any */ + if (mapentrysize > 0) { + if (biClrUsed <= 0) + biClrUsed = 256; /* assume it's 256 */ + else if (biClrUsed > 256) + ERREXIT(cinfo, JERR_BMP_BADCMAP); + /* Allocate space to store the colormap */ + source->colormap = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) biClrUsed, (JDIMENSION) 3); + /* and read it from the file */ + read_colormap(source, (int) biClrUsed, mapentrysize); + /* account for size of colormap */ + bPad -= biClrUsed * mapentrysize; + } + + /* Skip any remaining pad bytes */ + if (bPad < 0) /* incorrect bfOffBits value? */ + ERREXIT(cinfo, JERR_BMP_BADHEADER); + while (--bPad >= 0) { + (void) read_byte(source); + } + + /* Compute row width in file, including padding to 4-byte boundary */ + if (source->bits_per_pixel == 24) + row_width = (JDIMENSION) (biWidth * 3); + else + row_width = (JDIMENSION) biWidth; + while ((row_width & 3) != 0) row_width++; + source->row_width = row_width; + + /* Allocate space for inversion array, prepare for preload pass */ + source->whole_image = (*cinfo->mem->request_virt_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, + row_width, (JDIMENSION) biHeight, (JDIMENSION) 1); + source->pub.get_pixel_rows = preload_image; + if (cinfo->progress != NULL) { + cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress; + progress->total_extra_passes++; /* count file input as separate pass */ + } + + /* Allocate one-row buffer for returned data */ + source->pub.buffer = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) (biWidth * 3), (JDIMENSION) 1); + source->pub.buffer_height = 1; + + cinfo->in_color_space = JCS_RGB; + cinfo->input_components = 3; + cinfo->data_precision = 8; + cinfo->image_width = (JDIMENSION) biWidth; + cinfo->image_height = (JDIMENSION) biHeight; +} + + +/* + * Finish up at the end of the file. + */ + +METHODDEF(void) +finish_input_bmp (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +{ + /* no work */ +} + + +/* + * The module selection routine for BMP format input. + */ + +GLOBAL(cjpeg_source_ptr) +jinit_read_bmp (j_compress_ptr cinfo) +{ + bmp_source_ptr source; + + /* Create module interface object */ + source = (bmp_source_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(bmp_source_struct)); + source->cinfo = cinfo; /* make back link for subroutines */ + /* Fill in method ptrs, except get_pixel_rows which start_input sets */ + source->pub.start_input = start_input_bmp; + source->pub.finish_input = finish_input_bmp; + + return (cjpeg_source_ptr) source; +} + +#endif /* BMP_SUPPORTED */ diff --git a/mk4/modimage/jpeg-6b/rdcolmap.c b/mk4/modimage/jpeg-6b/rdcolmap.c new file mode 100644 index 0000000..42b3437 --- /dev/null +++ b/mk4/modimage/jpeg-6b/rdcolmap.c @@ -0,0 +1,253 @@ +/* + * rdcolmap.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file implements djpeg's "-map file" switch. It reads a source image + * and constructs a colormap to be supplied to the JPEG decompressor. + * + * Currently, these file formats are supported for the map file: + * GIF: the contents of the GIF's global colormap are used. + * PPM (either text or raw flavor): the entire file is read and + * each unique pixel value is entered in the map. + * Note that reading a large PPM file will be horrendously slow. + * Typically, a PPM-format map file should contain just one pixel + * of each desired color. Such a file can be extracted from an + * ordinary image PPM file with ppmtomap(1). + * + * Rescaling a PPM that has a maxval unequal to MAXJSAMPLE is not + * currently implemented. + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ + +#ifdef QUANT_2PASS_SUPPORTED /* otherwise can't quantize to supplied map */ + +/* Portions of this code are based on the PBMPLUS library, which is: +** +** Copyright (C) 1988 by Jef Poskanzer. +** +** 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. This software is provided "as is" without express or +** implied warranty. +*/ + + +/* + * Add a (potentially) new color to the color map. + */ + +LOCAL(void) +add_map_entry (j_decompress_ptr cinfo, int R, int G, int B) +{ + JSAMPROW colormap0 = cinfo->colormap[0]; + JSAMPROW colormap1 = cinfo->colormap[1]; + JSAMPROW colormap2 = cinfo->colormap[2]; + int ncolors = cinfo->actual_number_of_colors; + int index; + + /* Check for duplicate color. */ + for (index = 0; index < ncolors; index++) { + if (GETJSAMPLE(colormap0[index]) == R && + GETJSAMPLE(colormap1[index]) == G && + GETJSAMPLE(colormap2[index]) == B) + return; /* color is already in map */ + } + + /* Check for map overflow. */ + if (ncolors >= (MAXJSAMPLE+1)) + ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, (MAXJSAMPLE+1)); + + /* OK, add color to map. */ + colormap0[ncolors] = (JSAMPLE) R; + colormap1[ncolors] = (JSAMPLE) G; + colormap2[ncolors] = (JSAMPLE) B; + cinfo->actual_number_of_colors++; +} + + +/* + * Extract color map from a GIF file. + */ + +LOCAL(void) +read_gif_map (j_decompress_ptr cinfo, FILE * infile) +{ + int header[13]; + int i, colormaplen; + int R, G, B; + + /* Initial 'G' has already been read by read_color_map */ + /* Read the rest of the GIF header and logical screen descriptor */ + for (i = 1; i < 13; i++) { + if ((header[i] = getc(infile)) == EOF) + ERREXIT(cinfo, JERR_BAD_CMAP_FILE); + } + + /* Verify GIF Header */ + if (header[1] != 'I' || header[2] != 'F') + ERREXIT(cinfo, JERR_BAD_CMAP_FILE); + + /* There must be a global color map. */ + if ((header[10] & 0x80) == 0) + ERREXIT(cinfo, JERR_BAD_CMAP_FILE); + + /* OK, fetch it. */ + colormaplen = 2 << (header[10] & 0x07); + + for (i = 0; i < colormaplen; i++) { + R = getc(infile); + G = getc(infile); + B = getc(infile); + if (R == EOF || G == EOF || B == EOF) + ERREXIT(cinfo, JERR_BAD_CMAP_FILE); + add_map_entry(cinfo, + R << (BITS_IN_JSAMPLE-8), + G << (BITS_IN_JSAMPLE-8), + B << (BITS_IN_JSAMPLE-8)); + } +} + + +/* Support routines for reading PPM */ + + +LOCAL(int) +pbm_getc (FILE * infile) +/* Read next char, skipping over any comments */ +/* A comment/newline sequence is returned as a newline */ +{ + register int ch; + + ch = getc(infile); + if (ch == '#') { + do { + ch = getc(infile); + } while (ch != '\n' && ch != EOF); + } + return ch; +} + + +LOCAL(unsigned int) +read_pbm_integer (j_decompress_ptr cinfo, FILE * infile) +/* Read an unsigned decimal integer from the PPM file */ +/* Swallows one trailing character after the integer */ +/* Note that on a 16-bit-int machine, only values up to 64k can be read. */ +/* This should not be a problem in practice. */ +{ + register int ch; + register unsigned int val; + + /* Skip any leading whitespace */ + do { + ch = pbm_getc(infile); + if (ch == EOF) + ERREXIT(cinfo, JERR_BAD_CMAP_FILE); + } while (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r'); + + if (ch < '0' || ch > '9') + ERREXIT(cinfo, JERR_BAD_CMAP_FILE); + + val = ch - '0'; + while ((ch = pbm_getc(infile)) >= '0' && ch <= '9') { + val *= 10; + val += ch - '0'; + } + return val; +} + + +/* + * Extract color map from a PPM file. + */ + +LOCAL(void) +read_ppm_map (j_decompress_ptr cinfo, FILE * infile) +{ + int c; + unsigned int w, h, maxval, row, col; + int R, G, B; + + /* Initial 'P' has already been read by read_color_map */ + c = getc(infile); /* save format discriminator for a sec */ + + /* while we fetch the remaining header info */ + w = read_pbm_integer(cinfo, infile); + h = read_pbm_integer(cinfo, infile); + maxval = read_pbm_integer(cinfo, infile); + + if (w <= 0 || h <= 0 || maxval <= 0) /* error check */ + ERREXIT(cinfo, JERR_BAD_CMAP_FILE); + + /* For now, we don't support rescaling from an unusual maxval. */ + if (maxval != (unsigned int) MAXJSAMPLE) + ERREXIT(cinfo, JERR_BAD_CMAP_FILE); + + switch (c) { + case '3': /* it's a text-format PPM file */ + for (row = 0; row < h; row++) { + for (col = 0; col < w; col++) { + R = read_pbm_integer(cinfo, infile); + G = read_pbm_integer(cinfo, infile); + B = read_pbm_integer(cinfo, infile); + add_map_entry(cinfo, R, G, B); + } + } + break; + + case '6': /* it's a raw-format PPM file */ + for (row = 0; row < h; row++) { + for (col = 0; col < w; col++) { + R = getc(infile); + G = getc(infile); + B = getc(infile); + if (R == EOF || G == EOF || B == EOF) + ERREXIT(cinfo, JERR_BAD_CMAP_FILE); + add_map_entry(cinfo, R, G, B); + } + } + break; + + default: + ERREXIT(cinfo, JERR_BAD_CMAP_FILE); + break; + } +} + + +/* + * Main entry point from djpeg.c. + * Input: opened input file (from file name argument on command line). + * Output: colormap and actual_number_of_colors fields are set in cinfo. + */ + +GLOBAL(void) +read_color_map (j_decompress_ptr cinfo, FILE * infile) +{ + /* Allocate space for a color map of maximum supported size. */ + cinfo->colormap = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) (MAXJSAMPLE+1), (JDIMENSION) 3); + cinfo->actual_number_of_colors = 0; /* initialize map to empty */ + + /* Read first byte to determine file format */ + switch (getc(infile)) { + case 'G': + read_gif_map(cinfo, infile); + break; + case 'P': + read_ppm_map(cinfo, infile); + break; + default: + ERREXIT(cinfo, JERR_BAD_CMAP_FILE); + break; + } +} + +#endif /* QUANT_2PASS_SUPPORTED */ diff --git a/mk4/modimage/jpeg-6b/rdgif.c b/mk4/modimage/jpeg-6b/rdgif.c new file mode 100644 index 0000000..b27c167 --- /dev/null +++ b/mk4/modimage/jpeg-6b/rdgif.c @@ -0,0 +1,38 @@ +/* + * rdgif.c + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to read input images in GIF format. + * + ***************************************************************************** + * NOTE: to avoid entanglements with Unisys' patent on LZW compression, * + * the ability to read GIF files has been removed from the IJG distribution. * + * Sorry about that. * + ***************************************************************************** + * + * We are required to state that + * "The Graphics Interchange Format(c) is the Copyright property of + * CompuServe Incorporated. GIF(sm) is a Service Mark property of + * CompuServe Incorporated." + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ + +#ifdef GIF_SUPPORTED + +/* + * The module selection routine for GIF format input. + */ + +GLOBAL(cjpeg_source_ptr) +jinit_read_gif (j_compress_ptr cinfo) +{ + fprintf(stderr, "GIF input is unsupported for legal reasons. Sorry.\n"); + exit(EXIT_FAILURE); + return NULL; /* keep compiler happy */ +} + +#endif /* GIF_SUPPORTED */ diff --git a/mk4/modimage/jpeg-6b/rdjpgcom.1 b/mk4/modimage/jpeg-6b/rdjpgcom.1 new file mode 100644 index 0000000..2bba04e --- /dev/null +++ b/mk4/modimage/jpeg-6b/rdjpgcom.1 @@ -0,0 +1,54 @@ +.TH RDJPGCOM 1 "11 October 1997" +.SH NAME +rdjpgcom \- display text comments from a JPEG file +.SH SYNOPSIS +.B rdjpgcom +[ +.B \-verbose +] +[ +.I filename +] +.LP +.SH DESCRIPTION +.LP +.B rdjpgcom +reads the named JPEG/JFIF file, or the standard input if no file is named, +and prints any text comments found in the file on the standard output. +.PP +The JPEG standard allows "comment" (COM) blocks to occur within a JPEG file. +Although the standard doesn't actually define what COM blocks are for, they +are widely used to hold user-supplied text strings. This lets you add +annotations, titles, index terms, etc to your JPEG files, and later retrieve +them as text. COM blocks do not interfere with the image stored in the JPEG +file. The maximum size of a COM block is 64K, but you can have as many of +them as you like in one JPEG file. +.SH OPTIONS +.TP +.B \-verbose +Causes +.B rdjpgcom +to also display the JPEG image dimensions. +.PP +Switch names may be abbreviated, and are not case sensitive. +.SH HINTS +.B rdjpgcom +does not depend on the IJG JPEG library. Its source code is intended as an +illustration of the minimum amount of code required to parse a JPEG file +header correctly. +.PP +In +.B \-verbose +mode, +.B rdjpgcom +will also attempt to print the contents of any "APP12" markers as text. +Some digital cameras produce APP12 markers containing useful textual +information. If you like, you can modify the source code to print +other APPn marker types as well. +.SH SEE ALSO +.BR cjpeg (1), +.BR djpeg (1), +.BR jpegtran (1), +.BR wrjpgcom (1) +.SH AUTHOR +Independent JPEG Group diff --git a/mk4/modimage/jpeg-6b/rdjpgcom.c b/mk4/modimage/jpeg-6b/rdjpgcom.c new file mode 100644 index 0000000..ffe6fc6 --- /dev/null +++ b/mk4/modimage/jpeg-6b/rdjpgcom.c @@ -0,0 +1,496 @@ +/* + * rdjpgcom.c + * + * Copyright (C) 1994-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a very simple stand-alone application that displays + * the text in COM (comment) markers in a JFIF file. + * This may be useful as an example of the minimum logic needed to parse + * JPEG markers. + */ + +#define JPEG_CJPEG_DJPEG /* to get the command-line config symbols */ +#include "jinclude.h" /* get auto-config symbols, */ + +#include /* to declare isupper(), tolower() */ +#ifdef USE_SETMODE +#include /* to declare setmode()'s parameter macros */ +/* If you have setmode() but not , just delete this line: */ +#include /* to declare setmode() */ +#endif + +#ifdef USE_CCOMMAND /* command-line reader for Macintosh */ +#ifdef __MWERKS__ +#include /* Metrowerks needs this */ +#include /* ... and this */ +#endif +#ifdef THINK_C +#include /* Think declares it here */ +#endif +#endif + +#ifdef DONT_USE_B_MODE /* define mode parameters for fopen() */ +#define READ_BINARY "r" +#else +#ifdef VMS /* VMS is very nonstandard */ +#define READ_BINARY "rb", "ctx=stm" +#else /* standard ANSI-compliant case */ +#define READ_BINARY "rb" +#endif +#endif + +#ifndef EXIT_FAILURE /* define exit() codes if not provided */ +#define EXIT_FAILURE 1 +#endif +#ifndef EXIT_SUCCESS +#ifdef VMS +#define EXIT_SUCCESS 1 /* VMS is very nonstandard */ +#else +#define EXIT_SUCCESS 0 +#endif +#endif + + +/* + * These macros are used to read the input file. + * To reuse this code in another application, you might need to change these. + */ + +static FILE * infile; /* input JPEG file */ + +/* Return next input byte, or EOF if no more */ +#define NEXTBYTE() getc(infile) + + +/* Error exit handler */ +#define ERREXIT(msg) (fprintf(stderr, "%s\n", msg), exit(EXIT_FAILURE)) + + +/* Read one byte, testing for EOF */ +static int +read_1_byte (void) +{ + int c; + + c = NEXTBYTE(); + if (c == EOF) + ERREXIT("Premature EOF in JPEG file"); + return c; +} + +/* Read 2 bytes, convert to unsigned int */ +/* All 2-byte quantities in JPEG markers are MSB first */ +static unsigned int +read_2_bytes (void) +{ + int c1, c2; + + c1 = NEXTBYTE(); + if (c1 == EOF) + ERREXIT("Premature EOF in JPEG file"); + c2 = NEXTBYTE(); + if (c2 == EOF) + ERREXIT("Premature EOF in JPEG file"); + return (((unsigned int) c1) << 8) + ((unsigned int) c2); +} + + +/* + * JPEG markers consist of one or more 0xFF bytes, followed by a marker + * code byte (which is not an FF). Here are the marker codes of interest + * in this program. (See jdmarker.c for a more complete list.) + */ + +#define M_SOF0 0xC0 /* Start Of Frame N */ +#define M_SOF1 0xC1 /* N indicates which compression process */ +#define M_SOF2 0xC2 /* Only SOF0-SOF2 are now in common use */ +#define M_SOF3 0xC3 +#define M_SOF5 0xC5 /* NB: codes C4 and CC are NOT SOF markers */ +#define M_SOF6 0xC6 +#define M_SOF7 0xC7 +#define M_SOF9 0xC9 +#define M_SOF10 0xCA +#define M_SOF11 0xCB +#define M_SOF13 0xCD +#define M_SOF14 0xCE +#define M_SOF15 0xCF +#define M_SOI 0xD8 /* Start Of Image (beginning of datastream) */ +#define M_EOI 0xD9 /* End Of Image (end of datastream) */ +#define M_SOS 0xDA /* Start Of Scan (begins compressed data) */ +#define M_APP0 0xE0 /* Application-specific marker, type N */ +#define M_APP12 0xEC /* (we don't bother to list all 16 APPn's) */ +#define M_COM 0xFE /* COMment */ + + +/* + * Find the next JPEG marker and return its marker code. + * We expect at least one FF byte, possibly more if the compressor used FFs + * to pad the file. + * There could also be non-FF garbage between markers. The treatment of such + * garbage is unspecified; we choose to skip over it but emit a warning msg. + * NB: this routine must not be used after seeing SOS marker, since it will + * not deal correctly with FF/00 sequences in the compressed image data... + */ + +static int +next_marker (void) +{ + int c; + int discarded_bytes = 0; + + /* Find 0xFF byte; count and skip any non-FFs. */ + c = read_1_byte(); + while (c != 0xFF) { + discarded_bytes++; + c = read_1_byte(); + } + /* Get marker code byte, swallowing any duplicate FF bytes. Extra FFs + * are legal as pad bytes, so don't count them in discarded_bytes. + */ + do { + c = read_1_byte(); + } while (c == 0xFF); + + if (discarded_bytes != 0) { + fprintf(stderr, "Warning: garbage data found in JPEG file\n"); + } + + return c; +} + + +/* + * Read the initial marker, which should be SOI. + * For a JFIF file, the first two bytes of the file should be literally + * 0xFF M_SOI. To be more general, we could use next_marker, but if the + * input file weren't actually JPEG at all, next_marker might read the whole + * file and then return a misleading error message... + */ + +static int +first_marker (void) +{ + int c1, c2; + + c1 = NEXTBYTE(); + c2 = NEXTBYTE(); + if (c1 != 0xFF || c2 != M_SOI) + ERREXIT("Not a JPEG file"); + return c2; +} + + +/* + * Most types of marker are followed by a variable-length parameter segment. + * This routine skips over the parameters for any marker we don't otherwise + * want to process. + * Note that we MUST skip the parameter segment explicitly in order not to + * be fooled by 0xFF bytes that might appear within the parameter segment; + * such bytes do NOT introduce new markers. + */ + +static void +skip_variable (void) +/* Skip over an unknown or uninteresting variable-length marker */ +{ + unsigned int length; + + /* Get the marker parameter length count */ + length = read_2_bytes(); + /* Length includes itself, so must be at least 2 */ + if (length < 2) + ERREXIT("Erroneous JPEG marker length"); + length -= 2; + /* Skip over the remaining bytes */ + while (length > 0) { + (void) read_1_byte(); + length--; + } +} + + +/* + * Process a COM marker. + * We want to print out the marker contents as legible text; + * we must guard against non-text junk and varying newline representations. + */ + +static void +process_COM (void) +{ + unsigned int length; + int ch; + int lastch = 0; + + /* Get the marker parameter length count */ + length = read_2_bytes(); + /* Length includes itself, so must be at least 2 */ + if (length < 2) + ERREXIT("Erroneous JPEG marker length"); + length -= 2; + + while (length > 0) { + ch = read_1_byte(); + /* Emit the character in a readable form. + * Nonprintables are converted to \nnn form, + * while \ is converted to \\. + * Newlines in CR, CR/LF, or LF form will be printed as one newline. + */ + if (ch == '\r') { + printf("\n"); + } else if (ch == '\n') { + if (lastch != '\r') + printf("\n"); + } else if (ch == '\\') { + printf("\\\\"); + } else if (isprint(ch)) { + putc(ch, stdout); + } else { + printf("\\%03o", ch); + } + lastch = ch; + length--; + } + printf("\n"); +} + + +/* + * Process a SOFn marker. + * This code is only needed if you want to know the image dimensions... + */ + +static void +process_SOFn (int marker) +{ + unsigned int length; + unsigned int image_height, image_width; + int data_precision, num_components; + const char * process; + int ci; + + length = read_2_bytes(); /* usual parameter length count */ + + data_precision = read_1_byte(); + image_height = read_2_bytes(); + image_width = read_2_bytes(); + num_components = read_1_byte(); + + switch (marker) { + case M_SOF0: process = "Baseline"; break; + case M_SOF1: process = "Extended sequential"; break; + case M_SOF2: process = "Progressive"; break; + case M_SOF3: process = "Lossless"; break; + case M_SOF5: process = "Differential sequential"; break; + case M_SOF6: process = "Differential progressive"; break; + case M_SOF7: process = "Differential lossless"; break; + case M_SOF9: process = "Extended sequential, arithmetic coding"; break; + case M_SOF10: process = "Progressive, arithmetic coding"; break; + case M_SOF11: process = "Lossless, arithmetic coding"; break; + case M_SOF13: process = "Differential sequential, arithmetic coding"; break; + case M_SOF14: process = "Differential progressive, arithmetic coding"; break; + case M_SOF15: process = "Differential lossless, arithmetic coding"; break; + default: process = "Unknown"; break; + } + + printf("JPEG image is %uw * %uh, %d color components, %d bits per sample\n", + image_width, image_height, num_components, data_precision); + printf("JPEG process: %s\n", process); + + if (length != (unsigned int) (8 + num_components * 3)) + ERREXIT("Bogus SOF marker length"); + + for (ci = 0; ci < num_components; ci++) { + (void) read_1_byte(); /* Component ID code */ + (void) read_1_byte(); /* H, V sampling factors */ + (void) read_1_byte(); /* Quantization table number */ + } +} + + +/* + * Parse the marker stream until SOS or EOI is seen; + * display any COM markers. + * While the companion program wrjpgcom will always insert COM markers before + * SOFn, other implementations might not, so we scan to SOS before stopping. + * If we were only interested in the image dimensions, we would stop at SOFn. + * (Conversely, if we only cared about COM markers, there would be no need + * for special code to handle SOFn; we could treat it like other markers.) + */ + +static int +scan_JPEG_header (int verbose) +{ + int marker; + + /* Expect SOI at start of file */ + if (first_marker() != M_SOI) + ERREXIT("Expected SOI marker first"); + + /* Scan miscellaneous markers until we reach SOS. */ + for (;;) { + marker = next_marker(); + switch (marker) { + /* Note that marker codes 0xC4, 0xC8, 0xCC are not, and must not be, + * treated as SOFn. C4 in particular is actually DHT. + */ + case M_SOF0: /* Baseline */ + case M_SOF1: /* Extended sequential, Huffman */ + case M_SOF2: /* Progressive, Huffman */ + case M_SOF3: /* Lossless, Huffman */ + case M_SOF5: /* Differential sequential, Huffman */ + case M_SOF6: /* Differential progressive, Huffman */ + case M_SOF7: /* Differential lossless, Huffman */ + case M_SOF9: /* Extended sequential, arithmetic */ + case M_SOF10: /* Progressive, arithmetic */ + case M_SOF11: /* Lossless, arithmetic */ + case M_SOF13: /* Differential sequential, arithmetic */ + case M_SOF14: /* Differential progressive, arithmetic */ + case M_SOF15: /* Differential lossless, arithmetic */ + if (verbose) + process_SOFn(marker); + else + skip_variable(); + break; + + case M_SOS: /* stop before hitting compressed data */ + return marker; + + case M_EOI: /* in case it's a tables-only JPEG stream */ + return marker; + + case M_COM: + process_COM(); + break; + + case M_APP12: + /* Some digital camera makers put useful textual information into + * APP12 markers, so we print those out too when in -verbose mode. + */ + if (verbose) { + printf("APP12 contains:\n"); + process_COM(); + } else + skip_variable(); + break; + + default: /* Anything else just gets skipped */ + skip_variable(); /* we assume it has a parameter count... */ + break; + } + } /* end loop */ +} + + +/* Command line parsing code */ + +static const char * progname; /* program name for error messages */ + + +static void +usage (void) +/* complain about bad command line */ +{ + fprintf(stderr, "rdjpgcom displays any textual comments in a JPEG file.\n"); + + fprintf(stderr, "Usage: %s [switches] [inputfile]\n", progname); + + fprintf(stderr, "Switches (names may be abbreviated):\n"); + fprintf(stderr, " -verbose Also display dimensions of JPEG image\n"); + + exit(EXIT_FAILURE); +} + + +static int +keymatch (char * arg, const char * keyword, int minchars) +/* Case-insensitive matching of (possibly abbreviated) keyword switches. */ +/* keyword is the constant keyword (must be lower case already), */ +/* minchars is length of minimum legal abbreviation. */ +{ + register int ca, ck; + register int nmatched = 0; + + while ((ca = *arg++) != '\0') { + if ((ck = *keyword++) == '\0') + return 0; /* arg longer than keyword, no good */ + if (isupper(ca)) /* force arg to lcase (assume ck is already) */ + ca = tolower(ca); + if (ca != ck) + return 0; /* no good */ + nmatched++; /* count matched characters */ + } + /* reached end of argument; fail if it's too short for unique abbrev */ + if (nmatched < minchars) + return 0; + return 1; /* A-OK */ +} + + +/* + * The main program. + */ + +int +main (int argc, char **argv) +{ + int argn; + char * arg; + int verbose = 0; + + /* On Mac, fetch a command line. */ +#ifdef USE_CCOMMAND + argc = ccommand(&argv); +#endif + + progname = argv[0]; + if (progname == NULL || progname[0] == 0) + progname = "rdjpgcom"; /* in case C library doesn't provide it */ + + /* Parse switches, if any */ + for (argn = 1; argn < argc; argn++) { + arg = argv[argn]; + if (arg[0] != '-') + break; /* not switch, must be file name */ + arg++; /* advance over '-' */ + if (keymatch(arg, "verbose", 1)) { + verbose++; + } else + usage(); + } + + /* Open the input file. */ + /* Unix style: expect zero or one file name */ + if (argn < argc-1) { + fprintf(stderr, "%s: only one input file\n", progname); + usage(); + } + if (argn < argc) { + if ((infile = fopen(argv[argn], READ_BINARY)) == NULL) { + fprintf(stderr, "%s: can't open %s\n", progname, argv[argn]); + exit(EXIT_FAILURE); + } + } else { + /* default input file is stdin */ +#ifdef USE_SETMODE /* need to hack file mode? */ + setmode(fileno(stdin), O_BINARY); +#endif +#ifdef USE_FDOPEN /* need to re-open in binary mode? */ + if ((infile = fdopen(fileno(stdin), READ_BINARY)) == NULL) { + fprintf(stderr, "%s: can't open stdin\n", progname); + exit(EXIT_FAILURE); + } +#else + infile = stdin; +#endif + } + + /* Scan the JPEG headers. */ + (void) scan_JPEG_header(verbose); + + /* All done. */ + exit(EXIT_SUCCESS); + return 0; /* suppress no-return-value warnings */ +} diff --git a/mk4/modimage/jpeg-6b/rdppm.c b/mk4/modimage/jpeg-6b/rdppm.c new file mode 100644 index 0000000..1df35c1 --- /dev/null +++ b/mk4/modimage/jpeg-6b/rdppm.c @@ -0,0 +1,458 @@ +/* + * rdppm.c + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to read input images in PPM/PGM format. + * The extended 2-byte-per-sample raw PPM/PGM formats are supported. + * The PBMPLUS library is NOT required to compile this software + * (but it is highly useful as a set of PPM image manipulation programs). + * + * These routines may need modification for non-Unix environments or + * specialized applications. As they stand, they assume input from + * an ordinary stdio stream. They further assume that reading begins + * at the start of the file; start_input may need work if the + * user interface has already read some data (e.g., to determine that + * the file is indeed PPM format). + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ + +#ifdef PPM_SUPPORTED + + +/* Portions of this code are based on the PBMPLUS library, which is: +** +** Copyright (C) 1988 by Jef Poskanzer. +** +** 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. This software is provided "as is" without express or +** implied warranty. +*/ + + +/* Macros to deal with unsigned chars as efficiently as compiler allows */ + +#ifdef HAVE_UNSIGNED_CHAR +typedef unsigned char U_CHAR; +#define UCH(x) ((int) (x)) +#else /* !HAVE_UNSIGNED_CHAR */ +#ifdef CHAR_IS_UNSIGNED +typedef char U_CHAR; +#define UCH(x) ((int) (x)) +#else +typedef char U_CHAR; +#define UCH(x) ((int) (x) & 0xFF) +#endif +#endif /* HAVE_UNSIGNED_CHAR */ + + +#define ReadOK(file,buffer,len) (JFREAD(file,buffer,len) == ((size_t) (len))) + + +/* + * On most systems, reading individual bytes with getc() is drastically less + * efficient than buffering a row at a time with fread(). On PCs, we must + * allocate the buffer in near data space, because we are assuming small-data + * memory model, wherein fread() can't reach far memory. If you need to + * process very wide images on a PC, you might have to compile in large-memory + * model, or else replace fread() with a getc() loop --- which will be much + * slower. + */ + + +/* Private version of data source object */ + +typedef struct { + struct cjpeg_source_struct pub; /* public fields */ + + U_CHAR *iobuffer; /* non-FAR pointer to I/O buffer */ + JSAMPROW pixrow; /* FAR pointer to same */ + size_t buffer_width; /* width of I/O buffer */ + JSAMPLE *rescale; /* => maxval-remapping array, or NULL */ +} ppm_source_struct; + +typedef ppm_source_struct * ppm_source_ptr; + + +LOCAL(int) +pbm_getc (FILE * infile) +/* Read next char, skipping over any comments */ +/* A comment/newline sequence is returned as a newline */ +{ + register int ch; + + ch = getc(infile); + if (ch == '#') { + do { + ch = getc(infile); + } while (ch != '\n' && ch != EOF); + } + return ch; +} + + +LOCAL(unsigned int) +read_pbm_integer (j_compress_ptr cinfo, FILE * infile) +/* Read an unsigned decimal integer from the PPM file */ +/* Swallows one trailing character after the integer */ +/* Note that on a 16-bit-int machine, only values up to 64k can be read. */ +/* This should not be a problem in practice. */ +{ + register int ch; + register unsigned int val; + + /* Skip any leading whitespace */ + do { + ch = pbm_getc(infile); + if (ch == EOF) + ERREXIT(cinfo, JERR_INPUT_EOF); + } while (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r'); + + if (ch < '0' || ch > '9') + ERREXIT(cinfo, JERR_PPM_NONNUMERIC); + + val = ch - '0'; + while ((ch = pbm_getc(infile)) >= '0' && ch <= '9') { + val *= 10; + val += ch - '0'; + } + return val; +} + + +/* + * Read one row of pixels. + * + * We provide several different versions depending on input file format. + * In all cases, input is scaled to the size of JSAMPLE. + * + * A really fast path is provided for reading byte/sample raw files with + * maxval = MAXJSAMPLE, which is the normal case for 8-bit data. + */ + + +METHODDEF(JDIMENSION) +get_text_gray_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +/* This version is for reading text-format PGM files with any maxval */ +{ + ppm_source_ptr source = (ppm_source_ptr) sinfo; + FILE * infile = source->pub.input_file; + register JSAMPROW ptr; + register JSAMPLE *rescale = source->rescale; + JDIMENSION col; + + ptr = source->pub.buffer[0]; + for (col = cinfo->image_width; col > 0; col--) { + *ptr++ = rescale[read_pbm_integer(cinfo, infile)]; + } + return 1; +} + + +METHODDEF(JDIMENSION) +get_text_rgb_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +/* This version is for reading text-format PPM files with any maxval */ +{ + ppm_source_ptr source = (ppm_source_ptr) sinfo; + FILE * infile = source->pub.input_file; + register JSAMPROW ptr; + register JSAMPLE *rescale = source->rescale; + JDIMENSION col; + + ptr = source->pub.buffer[0]; + for (col = cinfo->image_width; col > 0; col--) { + *ptr++ = rescale[read_pbm_integer(cinfo, infile)]; + *ptr++ = rescale[read_pbm_integer(cinfo, infile)]; + *ptr++ = rescale[read_pbm_integer(cinfo, infile)]; + } + return 1; +} + + +METHODDEF(JDIMENSION) +get_scaled_gray_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +/* This version is for reading raw-byte-format PGM files with any maxval */ +{ + ppm_source_ptr source = (ppm_source_ptr) sinfo; + register JSAMPROW ptr; + register U_CHAR * bufferptr; + register JSAMPLE *rescale = source->rescale; + JDIMENSION col; + + if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width)) + ERREXIT(cinfo, JERR_INPUT_EOF); + ptr = source->pub.buffer[0]; + bufferptr = source->iobuffer; + for (col = cinfo->image_width; col > 0; col--) { + *ptr++ = rescale[UCH(*bufferptr++)]; + } + return 1; +} + + +METHODDEF(JDIMENSION) +get_scaled_rgb_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +/* This version is for reading raw-byte-format PPM files with any maxval */ +{ + ppm_source_ptr source = (ppm_source_ptr) sinfo; + register JSAMPROW ptr; + register U_CHAR * bufferptr; + register JSAMPLE *rescale = source->rescale; + JDIMENSION col; + + if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width)) + ERREXIT(cinfo, JERR_INPUT_EOF); + ptr = source->pub.buffer[0]; + bufferptr = source->iobuffer; + for (col = cinfo->image_width; col > 0; col--) { + *ptr++ = rescale[UCH(*bufferptr++)]; + *ptr++ = rescale[UCH(*bufferptr++)]; + *ptr++ = rescale[UCH(*bufferptr++)]; + } + return 1; +} + + +METHODDEF(JDIMENSION) +get_raw_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +/* This version is for reading raw-byte-format files with maxval = MAXJSAMPLE. + * In this case we just read right into the JSAMPLE buffer! + * Note that same code works for PPM and PGM files. + */ +{ + ppm_source_ptr source = (ppm_source_ptr) sinfo; + + if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width)) + ERREXIT(cinfo, JERR_INPUT_EOF); + return 1; +} + + +METHODDEF(JDIMENSION) +get_word_gray_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +/* This version is for reading raw-word-format PGM files with any maxval */ +{ + ppm_source_ptr source = (ppm_source_ptr) sinfo; + register JSAMPROW ptr; + register U_CHAR * bufferptr; + register JSAMPLE *rescale = source->rescale; + JDIMENSION col; + + if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width)) + ERREXIT(cinfo, JERR_INPUT_EOF); + ptr = source->pub.buffer[0]; + bufferptr = source->iobuffer; + for (col = cinfo->image_width; col > 0; col--) { + register int temp; + temp = UCH(*bufferptr++); + temp |= UCH(*bufferptr++) << 8; + *ptr++ = rescale[temp]; + } + return 1; +} + + +METHODDEF(JDIMENSION) +get_word_rgb_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +/* This version is for reading raw-word-format PPM files with any maxval */ +{ + ppm_source_ptr source = (ppm_source_ptr) sinfo; + register JSAMPROW ptr; + register U_CHAR * bufferptr; + register JSAMPLE *rescale = source->rescale; + JDIMENSION col; + + if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width)) + ERREXIT(cinfo, JERR_INPUT_EOF); + ptr = source->pub.buffer[0]; + bufferptr = source->iobuffer; + for (col = cinfo->image_width; col > 0; col--) { + register int temp; + temp = UCH(*bufferptr++); + temp |= UCH(*bufferptr++) << 8; + *ptr++ = rescale[temp]; + temp = UCH(*bufferptr++); + temp |= UCH(*bufferptr++) << 8; + *ptr++ = rescale[temp]; + temp = UCH(*bufferptr++); + temp |= UCH(*bufferptr++) << 8; + *ptr++ = rescale[temp]; + } + return 1; +} + + +/* + * Read the file header; return image size and component count. + */ + +METHODDEF(void) +start_input_ppm (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +{ + ppm_source_ptr source = (ppm_source_ptr) sinfo; + int c; + unsigned int w, h, maxval; + boolean need_iobuffer, use_raw_buffer, need_rescale; + + if (getc(source->pub.input_file) != 'P') + ERREXIT(cinfo, JERR_PPM_NOT); + + c = getc(source->pub.input_file); /* subformat discriminator character */ + + /* detect unsupported variants (ie, PBM) before trying to read header */ + switch (c) { + case '2': /* it's a text-format PGM file */ + case '3': /* it's a text-format PPM file */ + case '5': /* it's a raw-format PGM file */ + case '6': /* it's a raw-format PPM file */ + break; + default: + ERREXIT(cinfo, JERR_PPM_NOT); + break; + } + + /* fetch the remaining header info */ + w = read_pbm_integer(cinfo, source->pub.input_file); + h = read_pbm_integer(cinfo, source->pub.input_file); + maxval = read_pbm_integer(cinfo, source->pub.input_file); + + if (w <= 0 || h <= 0 || maxval <= 0) /* error check */ + ERREXIT(cinfo, JERR_PPM_NOT); + + cinfo->data_precision = BITS_IN_JSAMPLE; /* we always rescale data to this */ + cinfo->image_width = (JDIMENSION) w; + cinfo->image_height = (JDIMENSION) h; + + /* initialize flags to most common settings */ + need_iobuffer = TRUE; /* do we need an I/O buffer? */ + use_raw_buffer = FALSE; /* do we map input buffer onto I/O buffer? */ + need_rescale = TRUE; /* do we need a rescale array? */ + + switch (c) { + case '2': /* it's a text-format PGM file */ + cinfo->input_components = 1; + cinfo->in_color_space = JCS_GRAYSCALE; + TRACEMS2(cinfo, 1, JTRC_PGM_TEXT, w, h); + source->pub.get_pixel_rows = get_text_gray_row; + need_iobuffer = FALSE; + break; + + case '3': /* it's a text-format PPM file */ + cinfo->input_components = 3; + cinfo->in_color_space = JCS_RGB; + TRACEMS2(cinfo, 1, JTRC_PPM_TEXT, w, h); + source->pub.get_pixel_rows = get_text_rgb_row; + need_iobuffer = FALSE; + break; + + case '5': /* it's a raw-format PGM file */ + cinfo->input_components = 1; + cinfo->in_color_space = JCS_GRAYSCALE; + TRACEMS2(cinfo, 1, JTRC_PGM, w, h); + if (maxval > 255) { + source->pub.get_pixel_rows = get_word_gray_row; + } else if (maxval == MAXJSAMPLE && SIZEOF(JSAMPLE) == SIZEOF(U_CHAR)) { + source->pub.get_pixel_rows = get_raw_row; + use_raw_buffer = TRUE; + need_rescale = FALSE; + } else { + source->pub.get_pixel_rows = get_scaled_gray_row; + } + break; + + case '6': /* it's a raw-format PPM file */ + cinfo->input_components = 3; + cinfo->in_color_space = JCS_RGB; + TRACEMS2(cinfo, 1, JTRC_PPM, w, h); + if (maxval > 255) { + source->pub.get_pixel_rows = get_word_rgb_row; + } else if (maxval == MAXJSAMPLE && SIZEOF(JSAMPLE) == SIZEOF(U_CHAR)) { + source->pub.get_pixel_rows = get_raw_row; + use_raw_buffer = TRUE; + need_rescale = FALSE; + } else { + source->pub.get_pixel_rows = get_scaled_rgb_row; + } + break; + } + + /* Allocate space for I/O buffer: 1 or 3 bytes or words/pixel. */ + if (need_iobuffer) { + source->buffer_width = (size_t) w * cinfo->input_components * + ((maxval<=255) ? SIZEOF(U_CHAR) : (2*SIZEOF(U_CHAR))); + source->iobuffer = (U_CHAR *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + source->buffer_width); + } + + /* Create compressor input buffer. */ + if (use_raw_buffer) { + /* For unscaled raw-input case, we can just map it onto the I/O buffer. */ + /* Synthesize a JSAMPARRAY pointer structure */ + /* Cast here implies near->far pointer conversion on PCs */ + source->pixrow = (JSAMPROW) source->iobuffer; + source->pub.buffer = & source->pixrow; + source->pub.buffer_height = 1; + } else { + /* Need to translate anyway, so make a separate sample buffer. */ + source->pub.buffer = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) w * cinfo->input_components, (JDIMENSION) 1); + source->pub.buffer_height = 1; + } + + /* Compute the rescaling array if required. */ + if (need_rescale) { + INT32 val, half_maxval; + + /* On 16-bit-int machines we have to be careful of maxval = 65535 */ + source->rescale = (JSAMPLE *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (size_t) (((long) maxval + 1L) * SIZEOF(JSAMPLE))); + half_maxval = maxval / 2; + for (val = 0; val <= (INT32) maxval; val++) { + /* The multiplication here must be done in 32 bits to avoid overflow */ + source->rescale[val] = (JSAMPLE) ((val*MAXJSAMPLE + half_maxval)/maxval); + } + } +} + + +/* + * Finish up at the end of the file. + */ + +METHODDEF(void) +finish_input_ppm (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +{ + /* no work */ +} + + +/* + * The module selection routine for PPM format input. + */ + +GLOBAL(cjpeg_source_ptr) +jinit_read_ppm (j_compress_ptr cinfo) +{ + ppm_source_ptr source; + + /* Create module interface object */ + source = (ppm_source_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(ppm_source_struct)); + /* Fill in method ptrs, except get_pixel_rows which start_input sets */ + source->pub.start_input = start_input_ppm; + source->pub.finish_input = finish_input_ppm; + + return (cjpeg_source_ptr) source; +} + +#endif /* PPM_SUPPORTED */ diff --git a/mk4/modimage/jpeg-6b/rdrle.c b/mk4/modimage/jpeg-6b/rdrle.c new file mode 100644 index 0000000..542bc37 --- /dev/null +++ b/mk4/modimage/jpeg-6b/rdrle.c @@ -0,0 +1,387 @@ +/* + * rdrle.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to read input images in Utah RLE format. + * The Utah Raster Toolkit library is required (version 3.1 or later). + * + * These routines may need modification for non-Unix environments or + * specialized applications. As they stand, they assume input from + * an ordinary stdio stream. They further assume that reading begins + * at the start of the file; start_input may need work if the + * user interface has already read some data (e.g., to determine that + * the file is indeed RLE format). + * + * Based on code contributed by Mike Lijewski, + * with updates from Robert Hutchinson. + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ + +#ifdef RLE_SUPPORTED + +/* rle.h is provided by the Utah Raster Toolkit. */ + +#include + +/* + * We assume that JSAMPLE has the same representation as rle_pixel, + * to wit, "unsigned char". Hence we can't cope with 12- or 16-bit samples. + */ + +#if BITS_IN_JSAMPLE != 8 + Sorry, this code only copes with 8-bit JSAMPLEs. /* deliberate syntax err */ +#endif + +/* + * We support the following types of RLE files: + * + * GRAYSCALE - 8 bits, no colormap + * MAPPEDGRAY - 8 bits, 1 channel colomap + * PSEUDOCOLOR - 8 bits, 3 channel colormap + * TRUECOLOR - 24 bits, 3 channel colormap + * DIRECTCOLOR - 24 bits, no colormap + * + * For now, we ignore any alpha channel in the image. + */ + +typedef enum + { GRAYSCALE, MAPPEDGRAY, PSEUDOCOLOR, TRUECOLOR, DIRECTCOLOR } rle_kind; + + +/* + * Since RLE stores scanlines bottom-to-top, we have to invert the image + * to conform to JPEG's top-to-bottom order. To do this, we read the + * incoming image into a virtual array on the first get_pixel_rows call, + * then fetch the required row from the virtual array on subsequent calls. + */ + +typedef struct _rle_source_struct * rle_source_ptr; + +typedef struct _rle_source_struct { + struct cjpeg_source_struct pub; /* public fields */ + + rle_kind visual; /* actual type of input file */ + jvirt_sarray_ptr image; /* virtual array to hold the image */ + JDIMENSION row; /* current row # in the virtual array */ + rle_hdr header; /* Input file information */ + rle_pixel** rle_row; /* holds a row returned by rle_getrow() */ + +} rle_source_struct; + + +/* + * Read the file header; return image size and component count. + */ + +METHODDEF(void) +start_input_rle (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +{ + rle_source_ptr source = (rle_source_ptr) sinfo; + JDIMENSION width, height; +#ifdef PROGRESS_REPORT + cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress; +#endif + + /* Use RLE library routine to get the header info */ + source->header = *rle_hdr_init(NULL); + source->header.rle_file = source->pub.input_file; + switch (rle_get_setup(&(source->header))) { + case RLE_SUCCESS: + /* A-OK */ + break; + case RLE_NOT_RLE: + ERREXIT(cinfo, JERR_RLE_NOT); + break; + case RLE_NO_SPACE: + ERREXIT(cinfo, JERR_RLE_MEM); + break; + case RLE_EMPTY: + ERREXIT(cinfo, JERR_RLE_EMPTY); + break; + case RLE_EOF: + ERREXIT(cinfo, JERR_RLE_EOF); + break; + default: + ERREXIT(cinfo, JERR_RLE_BADERROR); + break; + } + + /* Figure out what we have, set private vars and return values accordingly */ + + width = source->header.xmax - source->header.xmin + 1; + height = source->header.ymax - source->header.ymin + 1; + source->header.xmin = 0; /* realign horizontally */ + source->header.xmax = width-1; + + cinfo->image_width = width; + cinfo->image_height = height; + cinfo->data_precision = 8; /* we can only handle 8 bit data */ + + if (source->header.ncolors == 1 && source->header.ncmap == 0) { + source->visual = GRAYSCALE; + TRACEMS2(cinfo, 1, JTRC_RLE_GRAY, width, height); + } else if (source->header.ncolors == 1 && source->header.ncmap == 1) { + source->visual = MAPPEDGRAY; + TRACEMS3(cinfo, 1, JTRC_RLE_MAPGRAY, width, height, + 1 << source->header.cmaplen); + } else if (source->header.ncolors == 1 && source->header.ncmap == 3) { + source->visual = PSEUDOCOLOR; + TRACEMS3(cinfo, 1, JTRC_RLE_MAPPED, width, height, + 1 << source->header.cmaplen); + } else if (source->header.ncolors == 3 && source->header.ncmap == 3) { + source->visual = TRUECOLOR; + TRACEMS3(cinfo, 1, JTRC_RLE_FULLMAP, width, height, + 1 << source->header.cmaplen); + } else if (source->header.ncolors == 3 && source->header.ncmap == 0) { + source->visual = DIRECTCOLOR; + TRACEMS2(cinfo, 1, JTRC_RLE, width, height); + } else + ERREXIT(cinfo, JERR_RLE_UNSUPPORTED); + + if (source->visual == GRAYSCALE || source->visual == MAPPEDGRAY) { + cinfo->in_color_space = JCS_GRAYSCALE; + cinfo->input_components = 1; + } else { + cinfo->in_color_space = JCS_RGB; + cinfo->input_components = 3; + } + + /* + * A place to hold each scanline while it's converted. + * (GRAYSCALE scanlines don't need converting) + */ + if (source->visual != GRAYSCALE) { + source->rle_row = (rle_pixel**) (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) width, (JDIMENSION) cinfo->input_components); + } + + /* request a virtual array to hold the image */ + source->image = (*cinfo->mem->request_virt_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, + (JDIMENSION) (width * source->header.ncolors), + (JDIMENSION) height, (JDIMENSION) 1); + +#ifdef PROGRESS_REPORT + if (progress != NULL) { + /* count file input as separate pass */ + progress->total_extra_passes++; + } +#endif + + source->pub.buffer_height = 1; +} + + +/* + * Read one row of pixels. + * Called only after load_image has read the image into the virtual array. + * Used for GRAYSCALE, MAPPEDGRAY, TRUECOLOR, and DIRECTCOLOR images. + */ + +METHODDEF(JDIMENSION) +get_rle_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +{ + rle_source_ptr source = (rle_source_ptr) sinfo; + + source->row--; + source->pub.buffer = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, source->image, source->row, (JDIMENSION) 1, FALSE); + + return 1; +} + +/* + * Read one row of pixels. + * Called only after load_image has read the image into the virtual array. + * Used for PSEUDOCOLOR images. + */ + +METHODDEF(JDIMENSION) +get_pseudocolor_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +{ + rle_source_ptr source = (rle_source_ptr) sinfo; + JSAMPROW src_row, dest_row; + JDIMENSION col; + rle_map *colormap; + int val; + + colormap = source->header.cmap; + dest_row = source->pub.buffer[0]; + source->row--; + src_row = * (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, source->image, source->row, (JDIMENSION) 1, FALSE); + + for (col = cinfo->image_width; col > 0; col--) { + val = GETJSAMPLE(*src_row++); + *dest_row++ = (JSAMPLE) (colormap[val ] >> 8); + *dest_row++ = (JSAMPLE) (colormap[val + 256] >> 8); + *dest_row++ = (JSAMPLE) (colormap[val + 512] >> 8); + } + + return 1; +} + + +/* + * Load the image into a virtual array. We have to do this because RLE + * files start at the lower left while the JPEG standard has them starting + * in the upper left. This is called the first time we want to get a row + * of input. What we do is load the RLE data into the array and then call + * the appropriate routine to read one row from the array. Before returning, + * we set source->pub.get_pixel_rows so that subsequent calls go straight to + * the appropriate row-reading routine. + */ + +METHODDEF(JDIMENSION) +load_image (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +{ + rle_source_ptr source = (rle_source_ptr) sinfo; + JDIMENSION row, col; + JSAMPROW scanline, red_ptr, green_ptr, blue_ptr; + rle_pixel **rle_row; + rle_map *colormap; + char channel; +#ifdef PROGRESS_REPORT + cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress; +#endif + + colormap = source->header.cmap; + rle_row = source->rle_row; + + /* Read the RLE data into our virtual array. + * We assume here that (a) rle_pixel is represented the same as JSAMPLE, + * and (b) we are not on a machine where FAR pointers differ from regular. + */ + RLE_CLR_BIT(source->header, RLE_ALPHA); /* don't read the alpha channel */ + +#ifdef PROGRESS_REPORT + if (progress != NULL) { + progress->pub.pass_limit = cinfo->image_height; + progress->pub.pass_counter = 0; + (*progress->pub.progress_monitor) ((j_common_ptr) cinfo); + } +#endif + + switch (source->visual) { + + case GRAYSCALE: + case PSEUDOCOLOR: + for (row = 0; row < cinfo->image_height; row++) { + rle_row = (rle_pixel **) (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, source->image, row, (JDIMENSION) 1, TRUE); + rle_getrow(&source->header, rle_row); +#ifdef PROGRESS_REPORT + if (progress != NULL) { + progress->pub.pass_counter++; + (*progress->pub.progress_monitor) ((j_common_ptr) cinfo); + } +#endif + } + break; + + case MAPPEDGRAY: + case TRUECOLOR: + for (row = 0; row < cinfo->image_height; row++) { + scanline = * (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, source->image, row, (JDIMENSION) 1, TRUE); + rle_row = source->rle_row; + rle_getrow(&source->header, rle_row); + + for (col = 0; col < cinfo->image_width; col++) { + for (channel = 0; channel < source->header.ncolors; channel++) { + *scanline++ = (JSAMPLE) + (colormap[GETJSAMPLE(rle_row[channel][col]) + 256 * channel] >> 8); + } + } + +#ifdef PROGRESS_REPORT + if (progress != NULL) { + progress->pub.pass_counter++; + (*progress->pub.progress_monitor) ((j_common_ptr) cinfo); + } +#endif + } + break; + + case DIRECTCOLOR: + for (row = 0; row < cinfo->image_height; row++) { + scanline = * (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, source->image, row, (JDIMENSION) 1, TRUE); + rle_getrow(&source->header, rle_row); + + red_ptr = rle_row[0]; + green_ptr = rle_row[1]; + blue_ptr = rle_row[2]; + + for (col = cinfo->image_width; col > 0; col--) { + *scanline++ = *red_ptr++; + *scanline++ = *green_ptr++; + *scanline++ = *blue_ptr++; + } + +#ifdef PROGRESS_REPORT + if (progress != NULL) { + progress->pub.pass_counter++; + (*progress->pub.progress_monitor) ((j_common_ptr) cinfo); + } +#endif + } + } + +#ifdef PROGRESS_REPORT + if (progress != NULL) + progress->completed_extra_passes++; +#endif + + /* Set up to call proper row-extraction routine in future */ + if (source->visual == PSEUDOCOLOR) { + source->pub.buffer = source->rle_row; + source->pub.get_pixel_rows = get_pseudocolor_row; + } else { + source->pub.get_pixel_rows = get_rle_row; + } + source->row = cinfo->image_height; + + /* And fetch the topmost (bottommost) row */ + return (*source->pub.get_pixel_rows) (cinfo, sinfo); +} + + +/* + * Finish up at the end of the file. + */ + +METHODDEF(void) +finish_input_rle (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +{ + /* no work */ +} + + +/* + * The module selection routine for RLE format input. + */ + +GLOBAL(cjpeg_source_ptr) +jinit_read_rle (j_compress_ptr cinfo) +{ + rle_source_ptr source; + + /* Create module interface object */ + source = (rle_source_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(rle_source_struct)); + /* Fill in method ptrs */ + source->pub.start_input = start_input_rle; + source->pub.finish_input = finish_input_rle; + source->pub.get_pixel_rows = load_image; + + return (cjpeg_source_ptr) source; +} + +#endif /* RLE_SUPPORTED */ diff --git a/mk4/modimage/jpeg-6b/rdswitch.c b/mk4/modimage/jpeg-6b/rdswitch.c new file mode 100644 index 0000000..4f4bb4f --- /dev/null +++ b/mk4/modimage/jpeg-6b/rdswitch.c @@ -0,0 +1,332 @@ +/* + * rdswitch.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to process some of cjpeg's more complicated + * command-line switches. Switches processed here are: + * -qtables file Read quantization tables from text file + * -scans file Read scan script from text file + * -qslots N[,N,...] Set component quantization table selectors + * -sample HxV[,HxV,...] Set component sampling factors + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ +#include /* to declare isdigit(), isspace() */ + + +LOCAL(int) +text_getc (FILE * file) +/* Read next char, skipping over any comments (# to end of line) */ +/* A comment/newline sequence is returned as a newline */ +{ + register int ch; + + ch = getc(file); + if (ch == '#') { + do { + ch = getc(file); + } while (ch != '\n' && ch != EOF); + } + return ch; +} + + +LOCAL(boolean) +read_text_integer (FILE * file, long * result, int * termchar) +/* Read an unsigned decimal integer from a file, store it in result */ +/* Reads one trailing character after the integer; returns it in termchar */ +{ + register int ch; + register long val; + + /* Skip any leading whitespace, detect EOF */ + do { + ch = text_getc(file); + if (ch == EOF) { + *termchar = ch; + return FALSE; + } + } while (isspace(ch)); + + if (! isdigit(ch)) { + *termchar = ch; + return FALSE; + } + + val = ch - '0'; + while ((ch = text_getc(file)) != EOF) { + if (! isdigit(ch)) + break; + val *= 10; + val += ch - '0'; + } + *result = val; + *termchar = ch; + return TRUE; +} + + +GLOBAL(boolean) +read_quant_tables (j_compress_ptr cinfo, char * filename, + int scale_factor, boolean force_baseline) +/* Read a set of quantization tables from the specified file. + * The file is plain ASCII text: decimal numbers with whitespace between. + * Comments preceded by '#' may be included in the file. + * There may be one to NUM_QUANT_TBLS tables in the file, each of 64 values. + * The tables are implicitly numbered 0,1,etc. + * NOTE: does not affect the qslots mapping, which will default to selecting + * table 0 for luminance (or primary) components, 1 for chrominance components. + * You must use -qslots if you want a different component->table mapping. + */ +{ + FILE * fp; + int tblno, i, termchar; + long val; + unsigned int table[DCTSIZE2]; + + if ((fp = fopen(filename, "r")) == NULL) { + fprintf(stderr, "Can't open table file %s\n", filename); + return FALSE; + } + tblno = 0; + + while (read_text_integer(fp, &val, &termchar)) { /* read 1st element of table */ + if (tblno >= NUM_QUANT_TBLS) { + fprintf(stderr, "Too many tables in file %s\n", filename); + fclose(fp); + return FALSE; + } + table[0] = (unsigned int) val; + for (i = 1; i < DCTSIZE2; i++) { + if (! read_text_integer(fp, &val, &termchar)) { + fprintf(stderr, "Invalid table data in file %s\n", filename); + fclose(fp); + return FALSE; + } + table[i] = (unsigned int) val; + } + jpeg_add_quant_table(cinfo, tblno, table, scale_factor, force_baseline); + tblno++; + } + + if (termchar != EOF) { + fprintf(stderr, "Non-numeric data in file %s\n", filename); + fclose(fp); + return FALSE; + } + + fclose(fp); + return TRUE; +} + + +#ifdef C_MULTISCAN_FILES_SUPPORTED + +LOCAL(boolean) +read_scan_integer (FILE * file, long * result, int * termchar) +/* Variant of read_text_integer that always looks for a non-space termchar; + * this simplifies parsing of punctuation in scan scripts. + */ +{ + register int ch; + + if (! read_text_integer(file, result, termchar)) + return FALSE; + ch = *termchar; + while (ch != EOF && isspace(ch)) + ch = text_getc(file); + if (isdigit(ch)) { /* oops, put it back */ + if (ungetc(ch, file) == EOF) + return FALSE; + ch = ' '; + } else { + /* Any separators other than ';' and ':' are ignored; + * this allows user to insert commas, etc, if desired. + */ + if (ch != EOF && ch != ';' && ch != ':') + ch = ' '; + } + *termchar = ch; + return TRUE; +} + + +GLOBAL(boolean) +read_scan_script (j_compress_ptr cinfo, char * filename) +/* Read a scan script from the specified text file. + * Each entry in the file defines one scan to be emitted. + * Entries are separated by semicolons ';'. + * An entry contains one to four component indexes, + * optionally followed by a colon ':' and four progressive-JPEG parameters. + * The component indexes denote which component(s) are to be transmitted + * in the current scan. The first component has index 0. + * Sequential JPEG is used if the progressive-JPEG parameters are omitted. + * The file is free format text: any whitespace may appear between numbers + * and the ':' and ';' punctuation marks. Also, other punctuation (such + * as commas or dashes) can be placed between numbers if desired. + * Comments preceded by '#' may be included in the file. + * Note: we do very little validity checking here; + * jcmaster.c will validate the script parameters. + */ +{ + FILE * fp; + int scanno, ncomps, termchar; + long val; + jpeg_scan_info * scanptr; +#define MAX_SCANS 100 /* quite arbitrary limit */ + jpeg_scan_info scans[MAX_SCANS]; + + if ((fp = fopen(filename, "r")) == NULL) { + fprintf(stderr, "Can't open scan definition file %s\n", filename); + return FALSE; + } + scanptr = scans; + scanno = 0; + + while (read_scan_integer(fp, &val, &termchar)) { + if (scanno >= MAX_SCANS) { + fprintf(stderr, "Too many scans defined in file %s\n", filename); + fclose(fp); + return FALSE; + } + scanptr->component_index[0] = (int) val; + ncomps = 1; + while (termchar == ' ') { + if (ncomps >= MAX_COMPS_IN_SCAN) { + fprintf(stderr, "Too many components in one scan in file %s\n", + filename); + fclose(fp); + return FALSE; + } + if (! read_scan_integer(fp, &val, &termchar)) + goto bogus; + scanptr->component_index[ncomps] = (int) val; + ncomps++; + } + scanptr->comps_in_scan = ncomps; + if (termchar == ':') { + if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ') + goto bogus; + scanptr->Ss = (int) val; + if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ') + goto bogus; + scanptr->Se = (int) val; + if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ') + goto bogus; + scanptr->Ah = (int) val; + if (! read_scan_integer(fp, &val, &termchar)) + goto bogus; + scanptr->Al = (int) val; + } else { + /* set non-progressive parameters */ + scanptr->Ss = 0; + scanptr->Se = DCTSIZE2-1; + scanptr->Ah = 0; + scanptr->Al = 0; + } + if (termchar != ';' && termchar != EOF) { +bogus: + fprintf(stderr, "Invalid scan entry format in file %s\n", filename); + fclose(fp); + return FALSE; + } + scanptr++, scanno++; + } + + if (termchar != EOF) { + fprintf(stderr, "Non-numeric data in file %s\n", filename); + fclose(fp); + return FALSE; + } + + if (scanno > 0) { + /* Stash completed scan list in cinfo structure. + * NOTE: for cjpeg's use, JPOOL_IMAGE is the right lifetime for this data, + * but if you want to compress multiple images you'd want JPOOL_PERMANENT. + */ + scanptr = (jpeg_scan_info *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + scanno * SIZEOF(jpeg_scan_info)); + MEMCOPY(scanptr, scans, scanno * SIZEOF(jpeg_scan_info)); + cinfo->scan_info = scanptr; + cinfo->num_scans = scanno; + } + + fclose(fp); + return TRUE; +} + +#endif /* C_MULTISCAN_FILES_SUPPORTED */ + + +GLOBAL(boolean) +set_quant_slots (j_compress_ptr cinfo, char *arg) +/* Process a quantization-table-selectors parameter string, of the form + * N[,N,...] + * If there are more components than parameters, the last value is replicated. + */ +{ + int val = 0; /* default table # */ + int ci; + char ch; + + for (ci = 0; ci < MAX_COMPONENTS; ci++) { + if (*arg) { + ch = ','; /* if not set by sscanf, will be ',' */ + if (sscanf(arg, "%d%c", &val, &ch) < 1) + return FALSE; + if (ch != ',') /* syntax check */ + return FALSE; + if (val < 0 || val >= NUM_QUANT_TBLS) { + fprintf(stderr, "JPEG quantization tables are numbered 0..%d\n", + NUM_QUANT_TBLS-1); + return FALSE; + } + cinfo->comp_info[ci].quant_tbl_no = val; + while (*arg && *arg++ != ',') /* advance to next segment of arg string */ + ; + } else { + /* reached end of parameter, set remaining components to last table */ + cinfo->comp_info[ci].quant_tbl_no = val; + } + } + return TRUE; +} + + +GLOBAL(boolean) +set_sample_factors (j_compress_ptr cinfo, char *arg) +/* Process a sample-factors parameter string, of the form + * HxV[,HxV,...] + * If there are more components than parameters, "1x1" is assumed for the rest. + */ +{ + int ci, val1, val2; + char ch1, ch2; + + for (ci = 0; ci < MAX_COMPONENTS; ci++) { + if (*arg) { + ch2 = ','; /* if not set by sscanf, will be ',' */ + if (sscanf(arg, "%d%c%d%c", &val1, &ch1, &val2, &ch2) < 3) + return FALSE; + if ((ch1 != 'x' && ch1 != 'X') || ch2 != ',') /* syntax check */ + return FALSE; + if (val1 <= 0 || val1 > 4 || val2 <= 0 || val2 > 4) { + fprintf(stderr, "JPEG sampling factors must be 1..4\n"); + return FALSE; + } + cinfo->comp_info[ci].h_samp_factor = val1; + cinfo->comp_info[ci].v_samp_factor = val2; + while (*arg && *arg++ != ',') /* advance to next segment of arg string */ + ; + } else { + /* reached end of parameter, set remaining components to 1x1 sampling */ + cinfo->comp_info[ci].h_samp_factor = 1; + cinfo->comp_info[ci].v_samp_factor = 1; + } + } + return TRUE; +} diff --git a/mk4/modimage/jpeg-6b/rdtarga.c b/mk4/modimage/jpeg-6b/rdtarga.c new file mode 100644 index 0000000..4c2cd26 --- /dev/null +++ b/mk4/modimage/jpeg-6b/rdtarga.c @@ -0,0 +1,500 @@ +/* + * rdtarga.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to read input images in Targa format. + * + * These routines may need modification for non-Unix environments or + * specialized applications. As they stand, they assume input from + * an ordinary stdio stream. They further assume that reading begins + * at the start of the file; start_input may need work if the + * user interface has already read some data (e.g., to determine that + * the file is indeed Targa format). + * + * Based on code contributed by Lee Daniel Crocker. + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ + +#ifdef TARGA_SUPPORTED + + +/* Macros to deal with unsigned chars as efficiently as compiler allows */ + +#ifdef HAVE_UNSIGNED_CHAR +typedef unsigned char U_CHAR; +#define UCH(x) ((int) (x)) +#else /* !HAVE_UNSIGNED_CHAR */ +#ifdef CHAR_IS_UNSIGNED +typedef char U_CHAR; +#define UCH(x) ((int) (x)) +#else +typedef char U_CHAR; +#define UCH(x) ((int) (x) & 0xFF) +#endif +#endif /* HAVE_UNSIGNED_CHAR */ + + +#define ReadOK(file,buffer,len) (JFREAD(file,buffer,len) == ((size_t) (len))) + + +/* Private version of data source object */ + +typedef struct _tga_source_struct * tga_source_ptr; + +typedef struct _tga_source_struct { + struct cjpeg_source_struct pub; /* public fields */ + + j_compress_ptr cinfo; /* back link saves passing separate parm */ + + JSAMPARRAY colormap; /* Targa colormap (converted to my format) */ + + jvirt_sarray_ptr whole_image; /* Needed if funny input row order */ + JDIMENSION current_row; /* Current logical row number to read */ + + /* Pointer to routine to extract next Targa pixel from input file */ + JMETHOD(void, read_pixel, (tga_source_ptr sinfo)); + + /* Result of read_pixel is delivered here: */ + U_CHAR tga_pixel[4]; + + int pixel_size; /* Bytes per Targa pixel (1 to 4) */ + + /* State info for reading RLE-coded pixels; both counts must be init to 0 */ + int block_count; /* # of pixels remaining in RLE block */ + int dup_pixel_count; /* # of times to duplicate previous pixel */ + + /* This saves the correct pixel-row-expansion method for preload_image */ + JMETHOD(JDIMENSION, get_pixel_rows, (j_compress_ptr cinfo, + cjpeg_source_ptr sinfo)); +} tga_source_struct; + + +/* For expanding 5-bit pixel values to 8-bit with best rounding */ + +static const UINT8 c5to8bits[32] = { + 0, 8, 16, 25, 33, 41, 49, 58, + 66, 74, 82, 90, 99, 107, 115, 123, + 132, 140, 148, 156, 165, 173, 181, 189, + 197, 206, 214, 222, 230, 239, 247, 255 +}; + + + +LOCAL(int) +read_byte (tga_source_ptr sinfo) +/* Read next byte from Targa file */ +{ + register FILE *infile = sinfo->pub.input_file; + register int c; + + if ((c = getc(infile)) == EOF) + ERREXIT(sinfo->cinfo, JERR_INPUT_EOF); + return c; +} + + +LOCAL(void) +read_colormap (tga_source_ptr sinfo, int cmaplen, int mapentrysize) +/* Read the colormap from a Targa file */ +{ + int i; + + /* Presently only handles 24-bit BGR format */ + if (mapentrysize != 24) + ERREXIT(sinfo->cinfo, JERR_TGA_BADCMAP); + + for (i = 0; i < cmaplen; i++) { + sinfo->colormap[2][i] = (JSAMPLE) read_byte(sinfo); + sinfo->colormap[1][i] = (JSAMPLE) read_byte(sinfo); + sinfo->colormap[0][i] = (JSAMPLE) read_byte(sinfo); + } +} + + +/* + * read_pixel methods: get a single pixel from Targa file into tga_pixel[] + */ + +METHODDEF(void) +read_non_rle_pixel (tga_source_ptr sinfo) +/* Read one Targa pixel from the input file; no RLE expansion */ +{ + register FILE *infile = sinfo->pub.input_file; + register int i; + + for (i = 0; i < sinfo->pixel_size; i++) { + sinfo->tga_pixel[i] = (U_CHAR) getc(infile); + } +} + + +METHODDEF(void) +read_rle_pixel (tga_source_ptr sinfo) +/* Read one Targa pixel from the input file, expanding RLE data as needed */ +{ + register FILE *infile = sinfo->pub.input_file; + register int i; + + /* Duplicate previously read pixel? */ + if (sinfo->dup_pixel_count > 0) { + sinfo->dup_pixel_count--; + return; + } + + /* Time to read RLE block header? */ + if (--sinfo->block_count < 0) { /* decrement pixels remaining in block */ + i = read_byte(sinfo); + if (i & 0x80) { /* Start of duplicate-pixel block? */ + sinfo->dup_pixel_count = i & 0x7F; /* number of dups after this one */ + sinfo->block_count = 0; /* then read new block header */ + } else { + sinfo->block_count = i & 0x7F; /* number of pixels after this one */ + } + } + + /* Read next pixel */ + for (i = 0; i < sinfo->pixel_size; i++) { + sinfo->tga_pixel[i] = (U_CHAR) getc(infile); + } +} + + +/* + * Read one row of pixels. + * + * We provide several different versions depending on input file format. + */ + + +METHODDEF(JDIMENSION) +get_8bit_gray_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +/* This version is for reading 8-bit grayscale pixels */ +{ + tga_source_ptr source = (tga_source_ptr) sinfo; + register JSAMPROW ptr; + register JDIMENSION col; + + ptr = source->pub.buffer[0]; + for (col = cinfo->image_width; col > 0; col--) { + (*source->read_pixel) (source); /* Load next pixel into tga_pixel */ + *ptr++ = (JSAMPLE) UCH(source->tga_pixel[0]); + } + return 1; +} + +METHODDEF(JDIMENSION) +get_8bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +/* This version is for reading 8-bit colormap indexes */ +{ + tga_source_ptr source = (tga_source_ptr) sinfo; + register int t; + register JSAMPROW ptr; + register JDIMENSION col; + register JSAMPARRAY colormap = source->colormap; + + ptr = source->pub.buffer[0]; + for (col = cinfo->image_width; col > 0; col--) { + (*source->read_pixel) (source); /* Load next pixel into tga_pixel */ + t = UCH(source->tga_pixel[0]); + *ptr++ = colormap[0][t]; + *ptr++ = colormap[1][t]; + *ptr++ = colormap[2][t]; + } + return 1; +} + +METHODDEF(JDIMENSION) +get_16bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +/* This version is for reading 16-bit pixels */ +{ + tga_source_ptr source = (tga_source_ptr) sinfo; + register int t; + register JSAMPROW ptr; + register JDIMENSION col; + + ptr = source->pub.buffer[0]; + for (col = cinfo->image_width; col > 0; col--) { + (*source->read_pixel) (source); /* Load next pixel into tga_pixel */ + t = UCH(source->tga_pixel[0]); + t += UCH(source->tga_pixel[1]) << 8; + /* We expand 5 bit data to 8 bit sample width. + * The format of the 16-bit (LSB first) input word is + * xRRRRRGGGGGBBBBB + */ + ptr[2] = (JSAMPLE) c5to8bits[t & 0x1F]; + t >>= 5; + ptr[1] = (JSAMPLE) c5to8bits[t & 0x1F]; + t >>= 5; + ptr[0] = (JSAMPLE) c5to8bits[t & 0x1F]; + ptr += 3; + } + return 1; +} + +METHODDEF(JDIMENSION) +get_24bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +/* This version is for reading 24-bit pixels */ +{ + tga_source_ptr source = (tga_source_ptr) sinfo; + register JSAMPROW ptr; + register JDIMENSION col; + + ptr = source->pub.buffer[0]; + for (col = cinfo->image_width; col > 0; col--) { + (*source->read_pixel) (source); /* Load next pixel into tga_pixel */ + *ptr++ = (JSAMPLE) UCH(source->tga_pixel[2]); /* change BGR to RGB order */ + *ptr++ = (JSAMPLE) UCH(source->tga_pixel[1]); + *ptr++ = (JSAMPLE) UCH(source->tga_pixel[0]); + } + return 1; +} + +/* + * Targa also defines a 32-bit pixel format with order B,G,R,A. + * We presently ignore the attribute byte, so the code for reading + * these pixels is identical to the 24-bit routine above. + * This works because the actual pixel length is only known to read_pixel. + */ + +#define get_32bit_row get_24bit_row + + +/* + * This method is for re-reading the input data in standard top-down + * row order. The entire image has already been read into whole_image + * with proper conversion of pixel format, but it's in a funny row order. + */ + +METHODDEF(JDIMENSION) +get_memory_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +{ + tga_source_ptr source = (tga_source_ptr) sinfo; + JDIMENSION source_row; + + /* Compute row of source that maps to current_row of normal order */ + /* For now, assume image is bottom-up and not interlaced. */ + /* NEEDS WORK to support interlaced images! */ + source_row = cinfo->image_height - source->current_row - 1; + + /* Fetch that row from virtual array */ + source->pub.buffer = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, source->whole_image, + source_row, (JDIMENSION) 1, FALSE); + + source->current_row++; + return 1; +} + + +/* + * This method loads the image into whole_image during the first call on + * get_pixel_rows. The get_pixel_rows pointer is then adjusted to call + * get_memory_row on subsequent calls. + */ + +METHODDEF(JDIMENSION) +preload_image (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +{ + tga_source_ptr source = (tga_source_ptr) sinfo; + JDIMENSION row; + cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress; + + /* Read the data into a virtual array in input-file row order. */ + for (row = 0; row < cinfo->image_height; row++) { + if (progress != NULL) { + progress->pub.pass_counter = (long) row; + progress->pub.pass_limit = (long) cinfo->image_height; + (*progress->pub.progress_monitor) ((j_common_ptr) cinfo); + } + source->pub.buffer = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, source->whole_image, row, (JDIMENSION) 1, TRUE); + (*source->get_pixel_rows) (cinfo, sinfo); + } + if (progress != NULL) + progress->completed_extra_passes++; + + /* Set up to read from the virtual array in unscrambled order */ + source->pub.get_pixel_rows = get_memory_row; + source->current_row = 0; + /* And read the first row */ + return get_memory_row(cinfo, sinfo); +} + + +/* + * Read the file header; return image size and component count. + */ + +METHODDEF(void) +start_input_tga (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +{ + tga_source_ptr source = (tga_source_ptr) sinfo; + U_CHAR targaheader[18]; + int idlen, cmaptype, subtype, flags, interlace_type, components; + unsigned int width, height, maplen; + boolean is_bottom_up; + +#define GET_2B(offset) ((unsigned int) UCH(targaheader[offset]) + \ + (((unsigned int) UCH(targaheader[offset+1])) << 8)) + + if (! ReadOK(source->pub.input_file, targaheader, 18)) + ERREXIT(cinfo, JERR_INPUT_EOF); + + /* Pretend "15-bit" pixels are 16-bit --- we ignore attribute bit anyway */ + if (targaheader[16] == 15) + targaheader[16] = 16; + + idlen = UCH(targaheader[0]); + cmaptype = UCH(targaheader[1]); + subtype = UCH(targaheader[2]); + maplen = GET_2B(5); + width = GET_2B(12); + height = GET_2B(14); + source->pixel_size = UCH(targaheader[16]) >> 3; + flags = UCH(targaheader[17]); /* Image Descriptor byte */ + + is_bottom_up = ((flags & 0x20) == 0); /* bit 5 set => top-down */ + interlace_type = flags >> 6; /* bits 6/7 are interlace code */ + + if (cmaptype > 1 || /* cmaptype must be 0 or 1 */ + source->pixel_size < 1 || source->pixel_size > 4 || + (UCH(targaheader[16]) & 7) != 0 || /* bits/pixel must be multiple of 8 */ + interlace_type != 0) /* currently don't allow interlaced image */ + ERREXIT(cinfo, JERR_TGA_BADPARMS); + + if (subtype > 8) { + /* It's an RLE-coded file */ + source->read_pixel = read_rle_pixel; + source->block_count = source->dup_pixel_count = 0; + subtype -= 8; + } else { + /* Non-RLE file */ + source->read_pixel = read_non_rle_pixel; + } + + /* Now should have subtype 1, 2, or 3 */ + components = 3; /* until proven different */ + cinfo->in_color_space = JCS_RGB; + + switch (subtype) { + case 1: /* Colormapped image */ + if (source->pixel_size == 1 && cmaptype == 1) + source->get_pixel_rows = get_8bit_row; + else + ERREXIT(cinfo, JERR_TGA_BADPARMS); + TRACEMS2(cinfo, 1, JTRC_TGA_MAPPED, width, height); + break; + case 2: /* RGB image */ + switch (source->pixel_size) { + case 2: + source->get_pixel_rows = get_16bit_row; + break; + case 3: + source->get_pixel_rows = get_24bit_row; + break; + case 4: + source->get_pixel_rows = get_32bit_row; + break; + default: + ERREXIT(cinfo, JERR_TGA_BADPARMS); + break; + } + TRACEMS2(cinfo, 1, JTRC_TGA, width, height); + break; + case 3: /* Grayscale image */ + components = 1; + cinfo->in_color_space = JCS_GRAYSCALE; + if (source->pixel_size == 1) + source->get_pixel_rows = get_8bit_gray_row; + else + ERREXIT(cinfo, JERR_TGA_BADPARMS); + TRACEMS2(cinfo, 1, JTRC_TGA_GRAY, width, height); + break; + default: + ERREXIT(cinfo, JERR_TGA_BADPARMS); + break; + } + + if (is_bottom_up) { + /* Create a virtual array to buffer the upside-down image. */ + source->whole_image = (*cinfo->mem->request_virt_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, + (JDIMENSION) width * components, (JDIMENSION) height, (JDIMENSION) 1); + if (cinfo->progress != NULL) { + cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress; + progress->total_extra_passes++; /* count file input as separate pass */ + } + /* source->pub.buffer will point to the virtual array. */ + source->pub.buffer_height = 1; /* in case anyone looks at it */ + source->pub.get_pixel_rows = preload_image; + } else { + /* Don't need a virtual array, but do need a one-row input buffer. */ + source->whole_image = NULL; + source->pub.buffer = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) width * components, (JDIMENSION) 1); + source->pub.buffer_height = 1; + source->pub.get_pixel_rows = source->get_pixel_rows; + } + + while (idlen--) /* Throw away ID field */ + (void) read_byte(source); + + if (maplen > 0) { + if (maplen > 256 || GET_2B(3) != 0) + ERREXIT(cinfo, JERR_TGA_BADCMAP); + /* Allocate space to store the colormap */ + source->colormap = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, (JDIMENSION) maplen, (JDIMENSION) 3); + /* and read it from the file */ + read_colormap(source, (int) maplen, UCH(targaheader[7])); + } else { + if (cmaptype) /* but you promised a cmap! */ + ERREXIT(cinfo, JERR_TGA_BADPARMS); + source->colormap = NULL; + } + + cinfo->input_components = components; + cinfo->data_precision = 8; + cinfo->image_width = width; + cinfo->image_height = height; +} + + +/* + * Finish up at the end of the file. + */ + +METHODDEF(void) +finish_input_tga (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +{ + /* no work */ +} + + +/* + * The module selection routine for Targa format input. + */ + +GLOBAL(cjpeg_source_ptr) +jinit_read_targa (j_compress_ptr cinfo) +{ + tga_source_ptr source; + + /* Create module interface object */ + source = (tga_source_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(tga_source_struct)); + source->cinfo = cinfo; /* make back link for subroutines */ + /* Fill in method ptrs, except get_pixel_rows which start_input sets */ + source->pub.start_input = start_input_tga; + source->pub.finish_input = finish_input_tga; + + return (cjpeg_source_ptr) source; +} + +#endif /* TARGA_SUPPORTED */ diff --git a/mk4/modimage/jpeg-6b/structure.doc b/mk4/modimage/jpeg-6b/structure.doc new file mode 100644 index 0000000..51c9def --- /dev/null +++ b/mk4/modimage/jpeg-6b/structure.doc @@ -0,0 +1,948 @@ +IJG JPEG LIBRARY: SYSTEM ARCHITECTURE + +Copyright (C) 1991-1995, Thomas G. Lane. +This file is part of the Independent JPEG Group's software. +For conditions of distribution and use, see the accompanying README file. + + +This file provides an overview of the architecture of the IJG JPEG software; +that is, the functions of the various modules in the system and the interfaces +between modules. For more precise details about any data structure or calling +convention, see the include files and comments in the source code. + +We assume that the reader is already somewhat familiar with the JPEG standard. +The README file includes references for learning about JPEG. The file +libjpeg.doc describes the library from the viewpoint of an application +programmer using the library; it's best to read that file before this one. +Also, the file coderules.doc describes the coding style conventions we use. + +In this document, JPEG-specific terminology follows the JPEG standard: + A "component" means a color channel, e.g., Red or Luminance. + A "sample" is a single component value (i.e., one number in the image data). + A "coefficient" is a frequency coefficient (a DCT transform output number). + A "block" is an 8x8 group of samples or coefficients. + An "MCU" (minimum coded unit) is an interleaved set of blocks of size + determined by the sampling factors, or a single block in a + noninterleaved scan. +We do not use the terms "pixel" and "sample" interchangeably. When we say +pixel, we mean an element of the full-size image, while a sample is an element +of the downsampled image. Thus the number of samples may vary across +components while the number of pixels does not. (This terminology is not used +rigorously throughout the code, but it is used in places where confusion would +otherwise result.) + + +*** System features *** + +The IJG distribution contains two parts: + * A subroutine library for JPEG compression and decompression. + * cjpeg/djpeg, two sample applications that use the library to transform + JFIF JPEG files to and from several other image formats. +cjpeg/djpeg are of no great intellectual complexity: they merely add a simple +command-line user interface and I/O routines for several uncompressed image +formats. This document concentrates on the library itself. + +We desire the library to be capable of supporting all JPEG baseline, extended +sequential, and progressive DCT processes. Hierarchical processes are not +supported. + +The library does not support the lossless (spatial) JPEG process. Lossless +JPEG shares little or no code with lossy JPEG, and would normally be used +without the extensive pre- and post-processing provided by this library. +We feel that lossless JPEG is better handled by a separate library. + +Within these limits, any set of compression parameters allowed by the JPEG +spec should be readable for decompression. (We can be more restrictive about +what formats we can generate.) Although the system design allows for all +parameter values, some uncommon settings are not yet implemented and may +never be; nonintegral sampling ratios are the prime example. Furthermore, +we treat 8-bit vs. 12-bit data precision as a compile-time switch, not a +run-time option, because most machines can store 8-bit pixels much more +compactly than 12-bit. + +For legal reasons, JPEG arithmetic coding is not currently supported, but +extending the library to include it would be straightforward. + +By itself, the library handles only interchange JPEG datastreams --- in +particular the widely used JFIF file format. The library can be used by +surrounding code to process interchange or abbreviated JPEG datastreams that +are embedded in more complex file formats. (For example, libtiff uses this +library to implement JPEG compression within the TIFF file format.) + +The library includes a substantial amount of code that is not covered by the +JPEG standard but is necessary for typical applications of JPEG. These +functions preprocess the image before JPEG compression or postprocess it after +decompression. They include colorspace conversion, downsampling/upsampling, +and color quantization. This code can be omitted if not needed. + +A wide range of quality vs. speed tradeoffs are possible in JPEG processing, +and even more so in decompression postprocessing. The decompression library +provides multiple implementations that cover most of the useful tradeoffs, +ranging from very-high-quality down to fast-preview operation. On the +compression side we have generally not provided low-quality choices, since +compression is normally less time-critical. It should be understood that the +low-quality modes may not meet the JPEG standard's accuracy requirements; +nonetheless, they are useful for viewers. + + +*** Portability issues *** + +Portability is an essential requirement for the library. The key portability +issues that show up at the level of system architecture are: + +1. Memory usage. We want the code to be able to run on PC-class machines +with limited memory. Images should therefore be processed sequentially (in +strips), to avoid holding the whole image in memory at once. Where a +full-image buffer is necessary, we should be able to use either virtual memory +or temporary files. + +2. Near/far pointer distinction. To run efficiently on 80x86 machines, the +code should distinguish "small" objects (kept in near data space) from +"large" ones (kept in far data space). This is an annoying restriction, but +fortunately it does not impact code quality for less brain-damaged machines, +and the source code clutter turns out to be minimal with sufficient use of +pointer typedefs. + +3. Data precision. We assume that "char" is at least 8 bits, "short" and +"int" at least 16, "long" at least 32. The code will work fine with larger +data sizes, although memory may be used inefficiently in some cases. However, +the JPEG compressed datastream must ultimately appear on external storage as a +sequence of 8-bit bytes if it is to conform to the standard. This may pose a +problem on machines where char is wider than 8 bits. The library represents +compressed data as an array of values of typedef JOCTET. If no data type +exactly 8 bits wide is available, custom data source and data destination +modules must be written to unpack and pack the chosen JOCTET datatype into +8-bit external representation. + + +*** System overview *** + +The compressor and decompressor are each divided into two main sections: +the JPEG compressor or decompressor proper, and the preprocessing or +postprocessing functions. The interface between these two sections is the +image data that the official JPEG spec regards as its input or output: this +data is in the colorspace to be used for compression, and it is downsampled +to the sampling factors to be used. The preprocessing and postprocessing +steps are responsible for converting a normal image representation to or from +this form. (Those few applications that want to deal with YCbCr downsampled +data can skip the preprocessing or postprocessing step.) + +Looking more closely, the compressor library contains the following main +elements: + + Preprocessing: + * Color space conversion (e.g., RGB to YCbCr). + * Edge expansion and downsampling. Optionally, this step can do simple + smoothing --- this is often helpful for low-quality source data. + JPEG proper: + * MCU assembly, DCT, quantization. + * Entropy coding (sequential or progressive, Huffman or arithmetic). + +In addition to these modules we need overall control, marker generation, +and support code (memory management & error handling). There is also a +module responsible for physically writing the output data --- typically +this is just an interface to fwrite(), but some applications may need to +do something else with the data. + +The decompressor library contains the following main elements: + + JPEG proper: + * Entropy decoding (sequential or progressive, Huffman or arithmetic). + * Dequantization, inverse DCT, MCU disassembly. + Postprocessing: + * Upsampling. Optionally, this step may be able to do more general + rescaling of the image. + * Color space conversion (e.g., YCbCr to RGB). This step may also + provide gamma adjustment [ currently it does not ]. + * Optional color quantization (e.g., reduction to 256 colors). + * Optional color precision reduction (e.g., 24-bit to 15-bit color). + [This feature is not currently implemented.] + +We also need overall control, marker parsing, and a data source module. +The support code (memory management & error handling) can be shared with +the compression half of the library. + +There may be several implementations of each of these elements, particularly +in the decompressor, where a wide range of speed/quality tradeoffs is very +useful. It must be understood that some of the best speedups involve +merging adjacent steps in the pipeline. For example, upsampling, color space +conversion, and color quantization might all be done at once when using a +low-quality ordered-dither technique. The system architecture is designed to +allow such merging where appropriate. + + +Note: it is convenient to regard edge expansion (padding to block boundaries) +as a preprocessing/postprocessing function, even though the JPEG spec includes +it in compression/decompression. We do this because downsampling/upsampling +can be simplified a little if they work on padded data: it's not necessary to +have special cases at the right and bottom edges. Therefore the interface +buffer is always an integral number of blocks wide and high, and we expect +compression preprocessing to pad the source data properly. Padding will occur +only to the next block (8-sample) boundary. In an interleaved-scan situation, +additional dummy blocks may be used to fill out MCUs, but the MCU assembly and +disassembly logic will create or discard these blocks internally. (This is +advantageous for speed reasons, since we avoid DCTing the dummy blocks. +It also permits a small reduction in file size, because the compressor can +choose dummy block contents so as to minimize their size in compressed form. +Finally, it makes the interface buffer specification independent of whether +the file is actually interleaved or not.) Applications that wish to deal +directly with the downsampled data must provide similar buffering and padding +for odd-sized images. + + +*** Poor man's object-oriented programming *** + +It should be clear by now that we have a lot of quasi-independent processing +steps, many of which have several possible behaviors. To avoid cluttering the +code with lots of switch statements, we use a simple form of object-style +programming to separate out the different possibilities. + +For example, two different color quantization algorithms could be implemented +as two separate modules that present the same external interface; at runtime, +the calling code will access the proper module indirectly through an "object". + +We can get the limited features we need while staying within portable C. +The basic tool is a function pointer. An "object" is just a struct +containing one or more function pointer fields, each of which corresponds to +a method name in real object-oriented languages. During initialization we +fill in the function pointers with references to whichever module we have +determined we need to use in this run. Then invocation of the module is done +by indirecting through a function pointer; on most machines this is no more +expensive than a switch statement, which would be the only other way of +making the required run-time choice. The really significant benefit, of +course, is keeping the source code clean and well structured. + +We can also arrange to have private storage that varies between different +implementations of the same kind of object. We do this by making all the +module-specific object structs be separately allocated entities, which will +be accessed via pointers in the master compression or decompression struct. +The "public" fields or methods for a given kind of object are specified by +a commonly known struct. But a module's initialization code can allocate +a larger struct that contains the common struct as its first member, plus +additional private fields. With appropriate pointer casting, the module's +internal functions can access these private fields. (For a simple example, +see jdatadst.c, which implements the external interface specified by struct +jpeg_destination_mgr, but adds extra fields.) + +(Of course this would all be a lot easier if we were using C++, but we are +not yet prepared to assume that everyone has a C++ compiler.) + +An important benefit of this scheme is that it is easy to provide multiple +versions of any method, each tuned to a particular case. While a lot of +precalculation might be done to select an optimal implementation of a method, +the cost per invocation is constant. For example, the upsampling step might +have a "generic" method, plus one or more "hardwired" methods for the most +popular sampling factors; the hardwired methods would be faster because they'd +use straight-line code instead of for-loops. The cost to determine which +method to use is paid only once, at startup, and the selection criteria are +hidden from the callers of the method. + +This plan differs a little bit from usual object-oriented structures, in that +only one instance of each object class will exist during execution. The +reason for having the class structure is that on different runs we may create +different instances (choose to execute different modules). You can think of +the term "method" as denoting the common interface presented by a particular +set of interchangeable functions, and "object" as denoting a group of related +methods, or the total shared interface behavior of a group of modules. + + +*** Overall control structure *** + +We previously mentioned the need for overall control logic in the compression +and decompression libraries. In IJG implementations prior to v5, overall +control was mostly provided by "pipeline control" modules, which proved to be +large, unwieldy, and hard to understand. To improve the situation, the +control logic has been subdivided into multiple modules. The control modules +consist of: + +1. Master control for module selection and initialization. This has two +responsibilities: + + 1A. Startup initialization at the beginning of image processing. + The individual processing modules to be used in this run are selected + and given initialization calls. + + 1B. Per-pass control. This determines how many passes will be performed + and calls each active processing module to configure itself + appropriately at the beginning of each pass. End-of-pass processing, + where necessary, is also invoked from the master control module. + + Method selection is partially distributed, in that a particular processing + module may contain several possible implementations of a particular method, + which it will select among when given its initialization call. The master + control code need only be concerned with decisions that affect more than + one module. + +2. Data buffering control. A separate control module exists for each + inter-processing-step data buffer. This module is responsible for + invoking the processing steps that write or read that data buffer. + +Each buffer controller sees the world as follows: + +input data => processing step A => buffer => processing step B => output data + | | | + ------------------ controller ------------------ + +The controller knows the dataflow requirements of steps A and B: how much data +they want to accept in one chunk and how much they output in one chunk. Its +function is to manage its buffer and call A and B at the proper times. + +A data buffer control module may itself be viewed as a processing step by a +higher-level control module; thus the control modules form a binary tree with +elementary processing steps at the leaves of the tree. + +The control modules are objects. A considerable amount of flexibility can +be had by replacing implementations of a control module. For example: +* Merging of adjacent steps in the pipeline is done by replacing a control + module and its pair of processing-step modules with a single processing- + step module. (Hence the possible merges are determined by the tree of + control modules.) +* In some processing modes, a given interstep buffer need only be a "strip" + buffer large enough to accommodate the desired data chunk sizes. In other + modes, a full-image buffer is needed and several passes are required. + The control module determines which kind of buffer is used and manipulates + virtual array buffers as needed. One or both processing steps may be + unaware of the multi-pass behavior. + +In theory, we might be able to make all of the data buffer controllers +interchangeable and provide just one set of implementations for all. In +practice, each one contains considerable special-case processing for its +particular job. The buffer controller concept should be regarded as an +overall system structuring principle, not as a complete description of the +task performed by any one controller. + + +*** Compression object structure *** + +Here is a sketch of the logical structure of the JPEG compression library: + + |-- Colorspace conversion + |-- Preprocessing controller --| + | |-- Downsampling +Main controller --| + | |-- Forward DCT, quantize + |-- Coefficient controller --| + |-- Entropy encoding + +This sketch also describes the flow of control (subroutine calls) during +typical image data processing. Each of the components shown in the diagram is +an "object" which may have several different implementations available. One +or more source code files contain the actual implementation(s) of each object. + +The objects shown above are: + +* Main controller: buffer controller for the subsampled-data buffer, which + holds the preprocessed input data. This controller invokes preprocessing to + fill the subsampled-data buffer, and JPEG compression to empty it. There is + usually no need for a full-image buffer here; a strip buffer is adequate. + +* Preprocessing controller: buffer controller for the downsampling input data + buffer, which lies between colorspace conversion and downsampling. Note + that a unified conversion/downsampling module would probably replace this + controller entirely. + +* Colorspace conversion: converts application image data into the desired + JPEG color space; also changes the data from pixel-interleaved layout to + separate component planes. Processes one pixel row at a time. + +* Downsampling: performs reduction of chroma components as required. + Optionally may perform pixel-level smoothing as well. Processes a "row + group" at a time, where a row group is defined as Vmax pixel rows of each + component before downsampling, and Vk sample rows afterwards (remember Vk + differs across components). Some downsampling or smoothing algorithms may + require context rows above and below the current row group; the + preprocessing controller is responsible for supplying these rows via proper + buffering. The downsampler is responsible for edge expansion at the right + edge (i.e., extending each sample row to a multiple of 8 samples); but the + preprocessing controller is responsible for vertical edge expansion (i.e., + duplicating the bottom sample row as needed to make a multiple of 8 rows). + +* Coefficient controller: buffer controller for the DCT-coefficient data. + This controller handles MCU assembly, including insertion of dummy DCT + blocks when needed at the right or bottom edge. When performing + Huffman-code optimization or emitting a multiscan JPEG file, this + controller is responsible for buffering the full image. The equivalent of + one fully interleaved MCU row of subsampled data is processed per call, + even when the JPEG file is noninterleaved. + +* Forward DCT and quantization: Perform DCT, quantize, and emit coefficients. + Works on one or more DCT blocks at a time. (Note: the coefficients are now + emitted in normal array order, which the entropy encoder is expected to + convert to zigzag order as necessary. Prior versions of the IJG code did + the conversion to zigzag order within the quantization step.) + +* Entropy encoding: Perform Huffman or arithmetic entropy coding and emit the + coded data to the data destination module. Works on one MCU per call. + For progressive JPEG, the same DCT blocks are fed to the entropy coder + during each pass, and the coder must emit the appropriate subset of + coefficients. + +In addition to the above objects, the compression library includes these +objects: + +* Master control: determines the number of passes required, controls overall + and per-pass initialization of the other modules. + +* Marker writing: generates JPEG markers (except for RSTn, which is emitted + by the entropy encoder when needed). + +* Data destination manager: writes the output JPEG datastream to its final + destination (e.g., a file). The destination manager supplied with the + library knows how to write to a stdio stream; for other behaviors, the + surrounding application may provide its own destination manager. + +* Memory manager: allocates and releases memory, controls virtual arrays + (with backing store management, where required). + +* Error handler: performs formatting and output of error and trace messages; + determines handling of nonfatal errors. The surrounding application may + override some or all of this object's methods to change error handling. + +* Progress monitor: supports output of "percent-done" progress reports. + This object represents an optional callback to the surrounding application: + if wanted, it must be supplied by the application. + +The error handler, destination manager, and progress monitor objects are +defined as separate objects in order to simplify application-specific +customization of the JPEG library. A surrounding application may override +individual methods or supply its own all-new implementation of one of these +objects. The object interfaces for these objects are therefore treated as +part of the application interface of the library, whereas the other objects +are internal to the library. + +The error handler and memory manager are shared by JPEG compression and +decompression; the progress monitor, if used, may be shared as well. + + +*** Decompression object structure *** + +Here is a sketch of the logical structure of the JPEG decompression library: + + |-- Entropy decoding + |-- Coefficient controller --| + | |-- Dequantize, Inverse DCT +Main controller --| + | |-- Upsampling + |-- Postprocessing controller --| |-- Colorspace conversion + |-- Color quantization + |-- Color precision reduction + +As before, this diagram also represents typical control flow. The objects +shown are: + +* Main controller: buffer controller for the subsampled-data buffer, which + holds the output of JPEG decompression proper. This controller's primary + task is to feed the postprocessing procedure. Some upsampling algorithms + may require context rows above and below the current row group; when this + is true, the main controller is responsible for managing its buffer so as + to make context rows available. In the current design, the main buffer is + always a strip buffer; a full-image buffer is never required. + +* Coefficient controller: buffer controller for the DCT-coefficient data. + This controller handles MCU disassembly, including deletion of any dummy + DCT blocks at the right or bottom edge. When reading a multiscan JPEG + file, this controller is responsible for buffering the full image. + (Buffering DCT coefficients, rather than samples, is necessary to support + progressive JPEG.) The equivalent of one fully interleaved MCU row of + subsampled data is processed per call, even when the source JPEG file is + noninterleaved. + +* Entropy decoding: Read coded data from the data source module and perform + Huffman or arithmetic entropy decoding. Works on one MCU per call. + For progressive JPEG decoding, the coefficient controller supplies the prior + coefficients of each MCU (initially all zeroes), which the entropy decoder + modifies in each scan. + +* Dequantization and inverse DCT: like it says. Note that the coefficients + buffered by the coefficient controller have NOT been dequantized; we + merge dequantization and inverse DCT into a single step for speed reasons. + When scaled-down output is asked for, simplified DCT algorithms may be used + that emit only 1x1, 2x2, or 4x4 samples per DCT block, not the full 8x8. + Works on one DCT block at a time. + +* Postprocessing controller: buffer controller for the color quantization + input buffer, when quantization is in use. (Without quantization, this + controller just calls the upsampler.) For two-pass quantization, this + controller is responsible for buffering the full-image data. + +* Upsampling: restores chroma components to full size. (May support more + general output rescaling, too. Note that if undersized DCT outputs have + been emitted by the DCT module, this module must adjust so that properly + sized outputs are created.) Works on one row group at a time. This module + also calls the color conversion module, so its top level is effectively a + buffer controller for the upsampling->color conversion buffer. However, in + all but the highest-quality operating modes, upsampling and color + conversion are likely to be merged into a single step. + +* Colorspace conversion: convert from JPEG color space to output color space, + and change data layout from separate component planes to pixel-interleaved. + Works on one pixel row at a time. + +* Color quantization: reduce the data to colormapped form, using either an + externally specified colormap or an internally generated one. This module + is not used for full-color output. Works on one pixel row at a time; may + require two passes to generate a color map. Note that the output will + always be a single component representing colormap indexes. In the current + design, the output values are JSAMPLEs, so an 8-bit compilation cannot + quantize to more than 256 colors. This is unlikely to be a problem in + practice. + +* Color reduction: this module handles color precision reduction, e.g., + generating 15-bit color (5 bits/primary) from JPEG's 24-bit output. + Not quite clear yet how this should be handled... should we merge it with + colorspace conversion??? + +Note that some high-speed operating modes might condense the entire +postprocessing sequence to a single module (upsample, color convert, and +quantize in one step). + +In addition to the above objects, the decompression library includes these +objects: + +* Master control: determines the number of passes required, controls overall + and per-pass initialization of the other modules. This is subdivided into + input and output control: jdinput.c controls only input-side processing, + while jdmaster.c handles overall initialization and output-side control. + +* Marker reading: decodes JPEG markers (except for RSTn). + +* Data source manager: supplies the input JPEG datastream. The source + manager supplied with the library knows how to read from a stdio stream; + for other behaviors, the surrounding application may provide its own source + manager. + +* Memory manager: same as for compression library. + +* Error handler: same as for compression library. + +* Progress monitor: same as for compression library. + +As with compression, the data source manager, error handler, and progress +monitor are candidates for replacement by a surrounding application. + + +*** Decompression input and output separation *** + +To support efficient incremental display of progressive JPEG files, the +decompressor is divided into two sections that can run independently: + +1. Data input includes marker parsing, entropy decoding, and input into the + coefficient controller's DCT coefficient buffer. Note that this + processing is relatively cheap and fast. + +2. Data output reads from the DCT coefficient buffer and performs the IDCT + and all postprocessing steps. + +For a progressive JPEG file, the data input processing is allowed to get +arbitrarily far ahead of the data output processing. (This occurs only +if the application calls jpeg_consume_input(); otherwise input and output +run in lockstep, since the input section is called only when the output +section needs more data.) In this way the application can avoid making +extra display passes when data is arriving faster than the display pass +can run. Furthermore, it is possible to abort an output pass without +losing anything, since the coefficient buffer is read-only as far as the +output section is concerned. See libjpeg.doc for more detail. + +A full-image coefficient array is only created if the JPEG file has multiple +scans (or if the application specifies buffered-image mode anyway). When +reading a single-scan file, the coefficient controller normally creates only +a one-MCU buffer, so input and output processing must run in lockstep in this +case. jpeg_consume_input() is effectively a no-op in this situation. + +The main impact of dividing the decompressor in this fashion is that we must +be very careful with shared variables in the cinfo data structure. Each +variable that can change during the course of decompression must be +classified as belonging to data input or data output, and each section must +look only at its own variables. For example, the data output section may not +depend on any of the variables that describe the current scan in the JPEG +file, because these may change as the data input section advances into a new +scan. + +The progress monitor is (somewhat arbitrarily) defined to treat input of the +file as one pass when buffered-image mode is not used, and to ignore data +input work completely when buffered-image mode is used. Note that the +library has no reliable way to predict the number of passes when dealing +with a progressive JPEG file, nor can it predict the number of output passes +in buffered-image mode. So the work estimate is inherently bogus anyway. + +No comparable division is currently made in the compression library, because +there isn't any real need for it. + + +*** Data formats *** + +Arrays of pixel sample values use the following data structure: + + typedef something JSAMPLE; a pixel component value, 0..MAXJSAMPLE + typedef JSAMPLE *JSAMPROW; ptr to a row of samples + typedef JSAMPROW *JSAMPARRAY; ptr to a list of rows + typedef JSAMPARRAY *JSAMPIMAGE; ptr to a list of color-component arrays + +The basic element type JSAMPLE will typically be one of unsigned char, +(signed) char, or short. Short will be used if samples wider than 8 bits are +to be supported (this is a compile-time option). Otherwise, unsigned char is +used if possible. If the compiler only supports signed chars, then it is +necessary to mask off the value when reading. Thus, all reads of JSAMPLE +values must be coded as "GETJSAMPLE(value)", where the macro will be defined +as "((value) & 0xFF)" on signed-char machines and "((int) (value))" elsewhere. + +With these conventions, JSAMPLE values can be assumed to be >= 0. This helps +simplify correct rounding during downsampling, etc. The JPEG standard's +specification that sample values run from -128..127 is accommodated by +subtracting 128 just as the sample value is copied into the source array for +the DCT step (this will be an array of signed ints). Similarly, during +decompression the output of the IDCT step will be immediately shifted back to +0..255. (NB: different values are required when 12-bit samples are in use. +The code is written in terms of MAXJSAMPLE and CENTERJSAMPLE, which will be +defined as 255 and 128 respectively in an 8-bit implementation, and as 4095 +and 2048 in a 12-bit implementation.) + +We use a pointer per row, rather than a two-dimensional JSAMPLE array. This +choice costs only a small amount of memory and has several benefits: +* Code using the data structure doesn't need to know the allocated width of + the rows. This simplifies edge expansion/compression, since we can work + in an array that's wider than the logical picture width. +* Indexing doesn't require multiplication; this is a performance win on many + machines. +* Arrays with more than 64K total elements can be supported even on machines + where malloc() cannot allocate chunks larger than 64K. +* The rows forming a component array may be allocated at different times + without extra copying. This trick allows some speedups in smoothing steps + that need access to the previous and next rows. + +Note that each color component is stored in a separate array; we don't use the +traditional layout in which the components of a pixel are stored together. +This simplifies coding of modules that work on each component independently, +because they don't need to know how many components there are. Furthermore, +we can read or write each component to a temporary file independently, which +is helpful when dealing with noninterleaved JPEG files. + +In general, a specific sample value is accessed by code such as + GETJSAMPLE(image[colorcomponent][row][col]) +where col is measured from the image left edge, but row is measured from the +first sample row currently in memory. Either of the first two indexings can +be precomputed by copying the relevant pointer. + + +Since most image-processing applications prefer to work on images in which +the components of a pixel are stored together, the data passed to or from the +surrounding application uses the traditional convention: a single pixel is +represented by N consecutive JSAMPLE values, and an image row is an array of +(# of color components)*(image width) JSAMPLEs. One or more rows of data can +be represented by a pointer of type JSAMPARRAY in this scheme. This scheme is +converted to component-wise storage inside the JPEG library. (Applications +that want to skip JPEG preprocessing or postprocessing will have to contend +with component-wise storage.) + + +Arrays of DCT-coefficient values use the following data structure: + + typedef short JCOEF; a 16-bit signed integer + typedef JCOEF JBLOCK[DCTSIZE2]; an 8x8 block of coefficients + typedef JBLOCK *JBLOCKROW; ptr to one horizontal row of 8x8 blocks + typedef JBLOCKROW *JBLOCKARRAY; ptr to a list of such rows + typedef JBLOCKARRAY *JBLOCKIMAGE; ptr to a list of color component arrays + +The underlying type is at least a 16-bit signed integer; while "short" is big +enough on all machines of interest, on some machines it is preferable to use +"int" for speed reasons, despite the storage cost. Coefficients are grouped +into 8x8 blocks (but we always use #defines DCTSIZE and DCTSIZE2 rather than +"8" and "64"). + +The contents of a coefficient block may be in either "natural" or zigzagged +order, and may be true values or divided by the quantization coefficients, +depending on where the block is in the processing pipeline. In the current +library, coefficient blocks are kept in natural order everywhere; the entropy +codecs zigzag or dezigzag the data as it is written or read. The blocks +contain quantized coefficients everywhere outside the DCT/IDCT subsystems. +(This latter decision may need to be revisited to support variable +quantization a la JPEG Part 3.) + +Notice that the allocation unit is now a row of 8x8 blocks, corresponding to +eight rows of samples. Otherwise the structure is much the same as for +samples, and for the same reasons. + +On machines where malloc() can't handle a request bigger than 64Kb, this data +structure limits us to rows of less than 512 JBLOCKs, or a picture width of +4000+ pixels. This seems an acceptable restriction. + + +On 80x86 machines, the bottom-level pointer types (JSAMPROW and JBLOCKROW) +must be declared as "far" pointers, but the upper levels can be "near" +(implying that the pointer lists are allocated in the DS segment). +We use a #define symbol FAR, which expands to the "far" keyword when +compiling on 80x86 machines and to nothing elsewhere. + + +*** Suspendable processing *** + +In some applications it is desirable to use the JPEG library as an +incremental, memory-to-memory filter. In this situation the data source or +destination may be a limited-size buffer, and we can't rely on being able to +empty or refill the buffer at arbitrary times. Instead the application would +like to have control return from the library at buffer overflow/underrun, and +then resume compression or decompression at a later time. + +This scenario is supported for simple cases. (For anything more complex, we +recommend that the application "bite the bullet" and develop real multitasking +capability.) The libjpeg.doc file goes into more detail about the usage and +limitations of this capability; here we address the implications for library +structure. + +The essence of the problem is that the entropy codec (coder or decoder) must +be prepared to stop at arbitrary times. In turn, the controllers that call +the entropy codec must be able to stop before having produced or consumed all +the data that they normally would handle in one call. That part is reasonably +straightforward: we make the controller call interfaces include "progress +counters" which indicate the number of data chunks successfully processed, and +we require callers to test the counter rather than just assume all of the data +was processed. + +Rather than trying to restart at an arbitrary point, the current Huffman +codecs are designed to restart at the beginning of the current MCU after a +suspension due to buffer overflow/underrun. At the start of each call, the +codec's internal state is loaded from permanent storage (in the JPEG object +structures) into local variables. On successful completion of the MCU, the +permanent state is updated. (This copying is not very expensive, and may even +lead to *improved* performance if the local variables can be registerized.) +If a suspension occurs, the codec simply returns without updating the state, +thus effectively reverting to the start of the MCU. Note that this implies +leaving some data unprocessed in the source/destination buffer (ie, the +compressed partial MCU). The data source/destination module interfaces are +specified so as to make this possible. This also implies that the data buffer +must be large enough to hold a worst-case compressed MCU; a couple thousand +bytes should be enough. + +In a successive-approximation AC refinement scan, the progressive Huffman +decoder has to be able to undo assignments of newly nonzero coefficients if it +suspends before the MCU is complete, since decoding requires distinguishing +previously-zero and previously-nonzero coefficients. This is a bit tedious +but probably won't have much effect on performance. Other variants of Huffman +decoding need not worry about this, since they will just store the same values +again if forced to repeat the MCU. + +This approach would probably not work for an arithmetic codec, since its +modifiable state is quite large and couldn't be copied cheaply. Instead it +would have to suspend and resume exactly at the point of the buffer end. + +The JPEG marker reader is designed to cope with suspension at an arbitrary +point. It does so by backing up to the start of the marker parameter segment, +so the data buffer must be big enough to hold the largest marker of interest. +Again, a couple KB should be adequate. (A special "skip" convention is used +to bypass COM and APPn markers, so these can be larger than the buffer size +without causing problems; otherwise a 64K buffer would be needed in the worst +case.) + +The JPEG marker writer currently does *not* cope with suspension. I feel that +this is not necessary; it is much easier simply to require the application to +ensure there is enough buffer space before starting. (An empty 2K buffer is +more than sufficient for the header markers; and ensuring there are a dozen or +two bytes available before calling jpeg_finish_compress() will suffice for the +trailer.) This would not work for writing multi-scan JPEG files, but +we simply do not intend to support that capability with suspension. + + +*** Memory manager services *** + +The JPEG library's memory manager controls allocation and deallocation of +memory, and it manages large "virtual" data arrays on machines where the +operating system does not provide virtual memory. Note that the same +memory manager serves both compression and decompression operations. + +In all cases, allocated objects are tied to a particular compression or +decompression master record, and they will be released when that master +record is destroyed. + +The memory manager does not provide explicit deallocation of objects. +Instead, objects are created in "pools" of free storage, and a whole pool +can be freed at once. This approach helps prevent storage-leak bugs, and +it speeds up operations whenever malloc/free are slow (as they often are). +The pools can be regarded as lifetime identifiers for objects. Two +pools/lifetimes are defined: + * JPOOL_PERMANENT lasts until master record is destroyed + * JPOOL_IMAGE lasts until done with image (JPEG datastream) +Permanent lifetime is used for parameters and tables that should be carried +across from one datastream to another; this includes all application-visible +parameters. Image lifetime is used for everything else. (A third lifetime, +JPOOL_PASS = one processing pass, was originally planned. However it was +dropped as not being worthwhile. The actual usage patterns are such that the +peak memory usage would be about the same anyway; and having per-pass storage +substantially complicates the virtual memory allocation rules --- see below.) + +The memory manager deals with three kinds of object: +1. "Small" objects. Typically these require no more than 10K-20K total. +2. "Large" objects. These may require tens to hundreds of K depending on + image size. Semantically they behave the same as small objects, but we + distinguish them for two reasons: + * On MS-DOS machines, large objects are referenced by FAR pointers, + small objects by NEAR pointers. + * Pool allocation heuristics may differ for large and small objects. + Note that individual "large" objects cannot exceed the size allowed by + type size_t, which may be 64K or less on some machines. +3. "Virtual" objects. These are large 2-D arrays of JSAMPLEs or JBLOCKs + (typically large enough for the entire image being processed). The + memory manager provides stripwise access to these arrays. On machines + without virtual memory, the rest of the array may be swapped out to a + temporary file. + +(Note: JSAMPARRAY and JBLOCKARRAY data structures are a combination of large +objects for the data proper and small objects for the row pointers. For +convenience and speed, the memory manager provides single routines to create +these structures. Similarly, virtual arrays include a small control block +and a JSAMPARRAY or JBLOCKARRAY working buffer, all created with one call.) + +In the present implementation, virtual arrays are only permitted to have image +lifespan. (Permanent lifespan would not be reasonable, and pass lifespan is +not very useful since a virtual array's raison d'etre is to store data for +multiple passes through the image.) We also expect that only "small" objects +will be given permanent lifespan, though this restriction is not required by +the memory manager. + +In a non-virtual-memory machine, some performance benefit can be gained by +making the in-memory buffers for virtual arrays be as large as possible. +(For small images, the buffers might fit entirely in memory, so blind +swapping would be very wasteful.) The memory manager will adjust the height +of the buffers to fit within a prespecified maximum memory usage. In order +to do this in a reasonably optimal fashion, the manager needs to allocate all +of the virtual arrays at once. Therefore, there isn't a one-step allocation +routine for virtual arrays; instead, there is a "request" routine that simply +allocates the control block, and a "realize" routine (called just once) that +determines space allocation and creates all of the actual buffers. The +realize routine must allow for space occupied by non-virtual large objects. +(We don't bother to factor in the space needed for small objects, on the +grounds that it isn't worth the trouble.) + +To support all this, we establish the following protocol for doing business +with the memory manager: + 1. Modules must request virtual arrays (which may have only image lifespan) + during the initial setup phase, i.e., in their jinit_xxx routines. + 2. All "large" objects (including JSAMPARRAYs and JBLOCKARRAYs) must also be + allocated during initial setup. + 3. realize_virt_arrays will be called at the completion of initial setup. + The above conventions ensure that sufficient information is available + for it to choose a good size for virtual array buffers. +Small objects of any lifespan may be allocated at any time. We expect that +the total space used for small objects will be small enough to be negligible +in the realize_virt_arrays computation. + +In a virtual-memory machine, we simply pretend that the available space is +infinite, thus causing realize_virt_arrays to decide that it can allocate all +the virtual arrays as full-size in-memory buffers. The overhead of the +virtual-array access protocol is very small when no swapping occurs. + +A virtual array can be specified to be "pre-zeroed"; when this flag is set, +never-yet-written sections of the array are set to zero before being made +available to the caller. If this flag is not set, never-written sections +of the array contain garbage. (This feature exists primarily because the +equivalent logic would otherwise be needed in jdcoefct.c for progressive +JPEG mode; we may as well make it available for possible other uses.) + +The first write pass on a virtual array is required to occur in top-to-bottom +order; read passes, as well as any write passes after the first one, may +access the array in any order. This restriction exists partly to simplify +the virtual array control logic, and partly because some file systems may not +support seeking beyond the current end-of-file in a temporary file. The main +implication of this restriction is that rearrangement of rows (such as +converting top-to-bottom data order to bottom-to-top) must be handled while +reading data out of the virtual array, not while putting it in. + + +*** Memory manager internal structure *** + +To isolate system dependencies as much as possible, we have broken the +memory manager into two parts. There is a reasonably system-independent +"front end" (jmemmgr.c) and a "back end" that contains only the code +likely to change across systems. All of the memory management methods +outlined above are implemented by the front end. The back end provides +the following routines for use by the front end (none of these routines +are known to the rest of the JPEG code): + +jpeg_mem_init, jpeg_mem_term system-dependent initialization/shutdown + +jpeg_get_small, jpeg_free_small interface to malloc and free library routines + (or their equivalents) + +jpeg_get_large, jpeg_free_large interface to FAR malloc/free in MSDOS machines; + else usually the same as + jpeg_get_small/jpeg_free_small + +jpeg_mem_available estimate available memory + +jpeg_open_backing_store create a backing-store object + +read_backing_store, manipulate a backing-store object +write_backing_store, +close_backing_store + +On some systems there will be more than one type of backing-store object +(specifically, in MS-DOS a backing store file might be an area of extended +memory as well as a disk file). jpeg_open_backing_store is responsible for +choosing how to implement a given object. The read/write/close routines +are method pointers in the structure that describes a given object; this +lets them be different for different object types. + +It may be necessary to ensure that backing store objects are explicitly +released upon abnormal program termination. For example, MS-DOS won't free +extended memory by itself. To support this, we will expect the main program +or surrounding application to arrange to call self_destruct (typically via +jpeg_destroy) upon abnormal termination. This may require a SIGINT signal +handler or equivalent. We don't want to have the back end module install its +own signal handler, because that would pre-empt the surrounding application's +ability to control signal handling. + +The IJG distribution includes several memory manager back end implementations. +Usually the same back end should be suitable for all applications on a given +system, but it is possible for an application to supply its own back end at +need. + + +*** Implications of DNL marker *** + +Some JPEG files may use a DNL marker to postpone definition of the image +height (this would be useful for a fax-like scanner's output, for instance). +In these files the SOF marker claims the image height is 0, and you only +find out the true image height at the end of the first scan. + +We could read these files as follows: +1. Upon seeing zero image height, replace it by 65535 (the maximum allowed). +2. When the DNL is found, update the image height in the global image + descriptor. +This implies that control modules must avoid making copies of the image +height, and must re-test for termination after each MCU row. This would +be easy enough to do. + +In cases where image-size data structures are allocated, this approach will +result in very inefficient use of virtual memory or much-larger-than-necessary +temporary files. This seems acceptable for something that probably won't be a +mainstream usage. People might have to forgo use of memory-hogging options +(such as two-pass color quantization or noninterleaved JPEG files) if they +want efficient conversion of such files. (One could improve efficiency by +demanding a user-supplied upper bound for the height, less than 65536; in most +cases it could be much less.) + +The standard also permits the SOF marker to overestimate the image height, +with a DNL to give the true, smaller height at the end of the first scan. +This would solve the space problems if the overestimate wasn't too great. +However, it implies that you don't even know whether DNL will be used. + +This leads to a couple of very serious objections: +1. Testing for a DNL marker must occur in the inner loop of the decompressor's + Huffman decoder; this implies a speed penalty whether the feature is used + or not. +2. There is no way to hide the last-minute change in image height from an + application using the decoder. Thus *every* application using the IJG + library would suffer a complexity penalty whether it cared about DNL or + not. +We currently do not support DNL because of these problems. + +A different approach is to insist that DNL-using files be preprocessed by a +separate program that reads ahead to the DNL, then goes back and fixes the SOF +marker. This is a much simpler solution and is probably far more efficient. +Even if one wants piped input, buffering the first scan of the JPEG file needs +a lot smaller temp file than is implied by the maximum-height method. For +this approach we'd simply treat DNL as a no-op in the decompressor (at most, +check that it matches the SOF image height). + +We will not worry about making the compressor capable of outputting DNL. +Something similar to the first scheme above could be applied if anyone ever +wants to make that work. diff --git a/mk4/modimage/jpeg-6b/transupp.c b/mk4/modimage/jpeg-6b/transupp.c new file mode 100644 index 0000000..e5ec564 --- /dev/null +++ b/mk4/modimage/jpeg-6b/transupp.c @@ -0,0 +1,928 @@ +/* + * transupp.c + * + * Copyright (C) 1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains image transformation routines and other utility code + * used by the jpegtran sample application. These are NOT part of the core + * JPEG library. But we keep these routines separate from jpegtran.c to + * ease the task of maintaining jpegtran-like programs that have other user + * interfaces. + */ + +/* Although this file really shouldn't have access to the library internals, + * it's helpful to let it call jround_up() and jcopy_block_row(). + */ +#define JPEG_INTERNALS + +#include "jinclude.h" +#include "jpeglib.h" +#include "transupp.h" /* My own external interface */ + + +#if TRANSFORMS_SUPPORTED + +/* + * Lossless image transformation routines. These routines work on DCT + * coefficient arrays and thus do not require any lossy decompression + * or recompression of the image. + * Thanks to Guido Vollbeding for the initial design and code of this feature. + * + * Horizontal flipping is done in-place, using a single top-to-bottom + * pass through the virtual source array. It will thus be much the + * fastest option for images larger than main memory. + * + * The other routines require a set of destination virtual arrays, so they + * need twice as much memory as jpegtran normally does. The destination + * arrays are always written in normal scan order (top to bottom) because + * the virtual array manager expects this. The source arrays will be scanned + * in the corresponding order, which means multiple passes through the source + * arrays for most of the transforms. That could result in much thrashing + * if the image is larger than main memory. + * + * Some notes about the operating environment of the individual transform + * routines: + * 1. Both the source and destination virtual arrays are allocated from the + * source JPEG object, and therefore should be manipulated by calling the + * source's memory manager. + * 2. The destination's component count should be used. It may be smaller + * than the source's when forcing to grayscale. + * 3. Likewise the destination's sampling factors should be used. When + * forcing to grayscale the destination's sampling factors will be all 1, + * and we may as well take that as the effective iMCU size. + * 4. When "trim" is in effect, the destination's dimensions will be the + * trimmed values but the source's will be untrimmed. + * 5. All the routines assume that the source and destination buffers are + * padded out to a full iMCU boundary. This is true, although for the + * source buffer it is an undocumented property of jdcoefct.c. + * Notes 2,3,4 boil down to this: generally we should use the destination's + * dimensions and ignore the source's. + */ + + +LOCAL(void) +do_flip_h (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + jvirt_barray_ptr *src_coef_arrays) +/* Horizontal flip; done in-place, so no separate dest array is required */ +{ + JDIMENSION MCU_cols, comp_width, blk_x, blk_y; + int ci, k, offset_y; + JBLOCKARRAY buffer; + JCOEFPTR ptr1, ptr2; + JCOEF temp1, temp2; + jpeg_component_info *compptr; + + /* Horizontal mirroring of DCT blocks is accomplished by swapping + * pairs of blocks in-place. Within a DCT block, we perform horizontal + * mirroring by changing the signs of odd-numbered columns. + * Partial iMCUs at the right edge are left untouched. + */ + MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + comp_width = MCU_cols * compptr->h_samp_factor; + for (blk_y = 0; blk_y < compptr->height_in_blocks; + blk_y += compptr->v_samp_factor) { + buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], blk_y, + (JDIMENSION) compptr->v_samp_factor, TRUE); + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + for (blk_x = 0; blk_x * 2 < comp_width; blk_x++) { + ptr1 = buffer[offset_y][blk_x]; + ptr2 = buffer[offset_y][comp_width - blk_x - 1]; + /* this unrolled loop doesn't need to know which row it's on... */ + for (k = 0; k < DCTSIZE2; k += 2) { + temp1 = *ptr1; /* swap even column */ + temp2 = *ptr2; + *ptr1++ = temp2; + *ptr2++ = temp1; + temp1 = *ptr1; /* swap odd column with sign change */ + temp2 = *ptr2; + *ptr1++ = -temp2; + *ptr2++ = -temp1; + } + } + } + } + } +} + + +LOCAL(void) +do_flip_v (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays) +/* Vertical flip */ +{ + JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y; + int ci, i, j, offset_y; + JBLOCKARRAY src_buffer, dst_buffer; + JBLOCKROW src_row_ptr, dst_row_ptr; + JCOEFPTR src_ptr, dst_ptr; + jpeg_component_info *compptr; + + /* We output into a separate array because we can't touch different + * rows of the source virtual array simultaneously. Otherwise, this + * is a pretty straightforward analog of horizontal flip. + * Within a DCT block, vertical mirroring is done by changing the signs + * of odd-numbered rows. + * Partial iMCUs at the bottom edge are copied verbatim. + */ + MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE); + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + comp_height = MCU_rows * compptr->v_samp_factor; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; + dst_blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, + (JDIMENSION) compptr->v_samp_factor, TRUE); + if (dst_blk_y < comp_height) { + /* Row is within the mirrorable area. */ + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], + comp_height - dst_blk_y - (JDIMENSION) compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } else { + /* Bottom-edge blocks will be copied verbatim. */ + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_y, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + if (dst_blk_y < comp_height) { + /* Row is within the mirrorable area. */ + dst_row_ptr = dst_buffer[offset_y]; + src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1]; + for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; + dst_blk_x++) { + dst_ptr = dst_row_ptr[dst_blk_x]; + src_ptr = src_row_ptr[dst_blk_x]; + for (i = 0; i < DCTSIZE; i += 2) { + /* copy even row */ + for (j = 0; j < DCTSIZE; j++) + *dst_ptr++ = *src_ptr++; + /* copy odd row with sign change */ + for (j = 0; j < DCTSIZE; j++) + *dst_ptr++ = - *src_ptr++; + } + } + } else { + /* Just copy row verbatim. */ + jcopy_block_row(src_buffer[offset_y], dst_buffer[offset_y], + compptr->width_in_blocks); + } + } + } + } +} + + +LOCAL(void) +do_transpose (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays) +/* Transpose source into destination */ +{ + JDIMENSION dst_blk_x, dst_blk_y; + int ci, i, j, offset_x, offset_y; + JBLOCKARRAY src_buffer, dst_buffer; + JCOEFPTR src_ptr, dst_ptr; + jpeg_component_info *compptr; + + /* Transposing pixels within a block just requires transposing the + * DCT coefficients. + * Partial iMCUs at the edges require no special treatment; we simply + * process all the available DCT blocks for every component. + */ + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; + dst_blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, + (JDIMENSION) compptr->v_samp_factor, TRUE); + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; + dst_blk_x += compptr->h_samp_factor) { + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x, + (JDIMENSION) compptr->h_samp_factor, FALSE); + for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { + src_ptr = src_buffer[offset_x][dst_blk_y + offset_y]; + dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; + for (i = 0; i < DCTSIZE; i++) + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; + } + } + } + } + } +} + + +LOCAL(void) +do_rot_90 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays) +/* 90 degree rotation is equivalent to + * 1. Transposing the image; + * 2. Horizontal mirroring. + * These two steps are merged into a single processing routine. + */ +{ + JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y; + int ci, i, j, offset_x, offset_y; + JBLOCKARRAY src_buffer, dst_buffer; + JCOEFPTR src_ptr, dst_ptr; + jpeg_component_info *compptr; + + /* Because of the horizontal mirror step, we can't process partial iMCUs + * at the (output) right edge properly. They just get transposed and + * not mirrored. + */ + MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + comp_width = MCU_cols * compptr->h_samp_factor; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; + dst_blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, + (JDIMENSION) compptr->v_samp_factor, TRUE); + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; + dst_blk_x += compptr->h_samp_factor) { + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x, + (JDIMENSION) compptr->h_samp_factor, FALSE); + for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { + src_ptr = src_buffer[offset_x][dst_blk_y + offset_y]; + if (dst_blk_x < comp_width) { + /* Block is within the mirrorable area. */ + dst_ptr = dst_buffer[offset_y] + [comp_width - dst_blk_x - offset_x - 1]; + for (i = 0; i < DCTSIZE; i++) { + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; + i++; + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; + } + } else { + /* Edge blocks are transposed but not mirrored. */ + dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; + for (i = 0; i < DCTSIZE; i++) + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; + } + } + } + } + } + } +} + + +LOCAL(void) +do_rot_270 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays) +/* 270 degree rotation is equivalent to + * 1. Horizontal mirroring; + * 2. Transposing the image. + * These two steps are merged into a single processing routine. + */ +{ + JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y; + int ci, i, j, offset_x, offset_y; + JBLOCKARRAY src_buffer, dst_buffer; + JCOEFPTR src_ptr, dst_ptr; + jpeg_component_info *compptr; + + /* Because of the horizontal mirror step, we can't process partial iMCUs + * at the (output) bottom edge properly. They just get transposed and + * not mirrored. + */ + MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE); + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + comp_height = MCU_rows * compptr->v_samp_factor; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; + dst_blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, + (JDIMENSION) compptr->v_samp_factor, TRUE); + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; + dst_blk_x += compptr->h_samp_factor) { + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x, + (JDIMENSION) compptr->h_samp_factor, FALSE); + for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { + dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; + if (dst_blk_y < comp_height) { + /* Block is within the mirrorable area. */ + src_ptr = src_buffer[offset_x] + [comp_height - dst_blk_y - offset_y - 1]; + for (i = 0; i < DCTSIZE; i++) { + for (j = 0; j < DCTSIZE; j++) { + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; + j++; + dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; + } + } + } else { + /* Edge blocks are transposed but not mirrored. */ + src_ptr = src_buffer[offset_x][dst_blk_y + offset_y]; + for (i = 0; i < DCTSIZE; i++) + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; + } + } + } + } + } + } +} + + +LOCAL(void) +do_rot_180 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays) +/* 180 degree rotation is equivalent to + * 1. Vertical mirroring; + * 2. Horizontal mirroring. + * These two steps are merged into a single processing routine. + */ +{ + JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y; + int ci, i, j, offset_y; + JBLOCKARRAY src_buffer, dst_buffer; + JBLOCKROW src_row_ptr, dst_row_ptr; + JCOEFPTR src_ptr, dst_ptr; + jpeg_component_info *compptr; + + MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); + MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE); + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + comp_width = MCU_cols * compptr->h_samp_factor; + comp_height = MCU_rows * compptr->v_samp_factor; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; + dst_blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, + (JDIMENSION) compptr->v_samp_factor, TRUE); + if (dst_blk_y < comp_height) { + /* Row is within the vertically mirrorable area. */ + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], + comp_height - dst_blk_y - (JDIMENSION) compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } else { + /* Bottom-edge rows are only mirrored horizontally. */ + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_y, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + if (dst_blk_y < comp_height) { + /* Row is within the mirrorable area. */ + dst_row_ptr = dst_buffer[offset_y]; + src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1]; + /* Process the blocks that can be mirrored both ways. */ + for (dst_blk_x = 0; dst_blk_x < comp_width; dst_blk_x++) { + dst_ptr = dst_row_ptr[dst_blk_x]; + src_ptr = src_row_ptr[comp_width - dst_blk_x - 1]; + for (i = 0; i < DCTSIZE; i += 2) { + /* For even row, negate every odd column. */ + for (j = 0; j < DCTSIZE; j += 2) { + *dst_ptr++ = *src_ptr++; + *dst_ptr++ = - *src_ptr++; + } + /* For odd row, negate every even column. */ + for (j = 0; j < DCTSIZE; j += 2) { + *dst_ptr++ = - *src_ptr++; + *dst_ptr++ = *src_ptr++; + } + } + } + /* Any remaining right-edge blocks are only mirrored vertically. */ + for (; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { + dst_ptr = dst_row_ptr[dst_blk_x]; + src_ptr = src_row_ptr[dst_blk_x]; + for (i = 0; i < DCTSIZE; i += 2) { + for (j = 0; j < DCTSIZE; j++) + *dst_ptr++ = *src_ptr++; + for (j = 0; j < DCTSIZE; j++) + *dst_ptr++ = - *src_ptr++; + } + } + } else { + /* Remaining rows are just mirrored horizontally. */ + dst_row_ptr = dst_buffer[offset_y]; + src_row_ptr = src_buffer[offset_y]; + /* Process the blocks that can be mirrored. */ + for (dst_blk_x = 0; dst_blk_x < comp_width; dst_blk_x++) { + dst_ptr = dst_row_ptr[dst_blk_x]; + src_ptr = src_row_ptr[comp_width - dst_blk_x - 1]; + for (i = 0; i < DCTSIZE2; i += 2) { + *dst_ptr++ = *src_ptr++; + *dst_ptr++ = - *src_ptr++; + } + } + /* Any remaining right-edge blocks are only copied. */ + for (; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { + dst_ptr = dst_row_ptr[dst_blk_x]; + src_ptr = src_row_ptr[dst_blk_x]; + for (i = 0; i < DCTSIZE2; i++) + *dst_ptr++ = *src_ptr++; + } + } + } + } + } +} + + +LOCAL(void) +do_transverse (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays) +/* Transverse transpose is equivalent to + * 1. 180 degree rotation; + * 2. Transposition; + * or + * 1. Horizontal mirroring; + * 2. Transposition; + * 3. Horizontal mirroring. + * These steps are merged into a single processing routine. + */ +{ + JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y; + int ci, i, j, offset_x, offset_y; + JBLOCKARRAY src_buffer, dst_buffer; + JCOEFPTR src_ptr, dst_ptr; + jpeg_component_info *compptr; + + MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); + MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE); + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + comp_width = MCU_cols * compptr->h_samp_factor; + comp_height = MCU_rows * compptr->v_samp_factor; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; + dst_blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, + (JDIMENSION) compptr->v_samp_factor, TRUE); + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; + dst_blk_x += compptr->h_samp_factor) { + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x, + (JDIMENSION) compptr->h_samp_factor, FALSE); + for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { + if (dst_blk_y < comp_height) { + src_ptr = src_buffer[offset_x] + [comp_height - dst_blk_y - offset_y - 1]; + if (dst_blk_x < comp_width) { + /* Block is within the mirrorable area. */ + dst_ptr = dst_buffer[offset_y] + [comp_width - dst_blk_x - offset_x - 1]; + for (i = 0; i < DCTSIZE; i++) { + for (j = 0; j < DCTSIZE; j++) { + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; + j++; + dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; + } + i++; + for (j = 0; j < DCTSIZE; j++) { + dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; + j++; + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; + } + } + } else { + /* Right-edge blocks are mirrored in y only */ + dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; + for (i = 0; i < DCTSIZE; i++) { + for (j = 0; j < DCTSIZE; j++) { + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; + j++; + dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; + } + } + } + } else { + src_ptr = src_buffer[offset_x][dst_blk_y + offset_y]; + if (dst_blk_x < comp_width) { + /* Bottom-edge blocks are mirrored in x only */ + dst_ptr = dst_buffer[offset_y] + [comp_width - dst_blk_x - offset_x - 1]; + for (i = 0; i < DCTSIZE; i++) { + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; + i++; + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; + } + } else { + /* At lower right corner, just transpose, no mirroring */ + dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; + for (i = 0; i < DCTSIZE; i++) + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; + } + } + } + } + } + } + } +} + + +/* Request any required workspace. + * + * We allocate the workspace virtual arrays from the source decompression + * object, so that all the arrays (both the original data and the workspace) + * will be taken into account while making memory management decisions. + * Hence, this routine must be called after jpeg_read_header (which reads + * the image dimensions) and before jpeg_read_coefficients (which realizes + * the source's virtual arrays). + */ + +GLOBAL(void) +jtransform_request_workspace (j_decompress_ptr srcinfo, + jpeg_transform_info *info) +{ + jvirt_barray_ptr *coef_arrays = NULL; + jpeg_component_info *compptr; + int ci; + + if (info->force_grayscale && + srcinfo->jpeg_color_space == JCS_YCbCr && + srcinfo->num_components == 3) { + /* We'll only process the first component */ + info->num_components = 1; + } else { + /* Process all the components */ + info->num_components = srcinfo->num_components; + } + + switch (info->transform) { + case JXFORM_NONE: + case JXFORM_FLIP_H: + /* Don't need a workspace array */ + break; + case JXFORM_FLIP_V: + case JXFORM_ROT_180: + /* Need workspace arrays having same dimensions as source image. + * Note that we allocate arrays padded out to the next iMCU boundary, + * so that transform routines need not worry about missing edge blocks. + */ + coef_arrays = (jvirt_barray_ptr *) + (*srcinfo->mem->alloc_small) ((j_common_ptr) srcinfo, JPOOL_IMAGE, + SIZEOF(jvirt_barray_ptr) * info->num_components); + for (ci = 0; ci < info->num_components; ci++) { + compptr = srcinfo->comp_info + ci; + coef_arrays[ci] = (*srcinfo->mem->request_virt_barray) + ((j_common_ptr) srcinfo, JPOOL_IMAGE, FALSE, + (JDIMENSION) jround_up((long) compptr->width_in_blocks, + (long) compptr->h_samp_factor), + (JDIMENSION) jround_up((long) compptr->height_in_blocks, + (long) compptr->v_samp_factor), + (JDIMENSION) compptr->v_samp_factor); + } + break; + case JXFORM_TRANSPOSE: + case JXFORM_TRANSVERSE: + case JXFORM_ROT_90: + case JXFORM_ROT_270: + /* Need workspace arrays having transposed dimensions. + * Note that we allocate arrays padded out to the next iMCU boundary, + * so that transform routines need not worry about missing edge blocks. + */ + coef_arrays = (jvirt_barray_ptr *) + (*srcinfo->mem->alloc_small) ((j_common_ptr) srcinfo, JPOOL_IMAGE, + SIZEOF(jvirt_barray_ptr) * info->num_components); + for (ci = 0; ci < info->num_components; ci++) { + compptr = srcinfo->comp_info + ci; + coef_arrays[ci] = (*srcinfo->mem->request_virt_barray) + ((j_common_ptr) srcinfo, JPOOL_IMAGE, FALSE, + (JDIMENSION) jround_up((long) compptr->height_in_blocks, + (long) compptr->v_samp_factor), + (JDIMENSION) jround_up((long) compptr->width_in_blocks, + (long) compptr->h_samp_factor), + (JDIMENSION) compptr->h_samp_factor); + } + break; + } + info->workspace_coef_arrays = coef_arrays; +} + + +/* Transpose destination image parameters */ + +LOCAL(void) +transpose_critical_parameters (j_compress_ptr dstinfo) +{ + int tblno, i, j, ci, itemp; + jpeg_component_info *compptr; + JQUANT_TBL *qtblptr; + JDIMENSION dtemp; + UINT16 qtemp; + + /* Transpose basic image dimensions */ + dtemp = dstinfo->image_width; + dstinfo->image_width = dstinfo->image_height; + dstinfo->image_height = dtemp; + + /* Transpose sampling factors */ + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + itemp = compptr->h_samp_factor; + compptr->h_samp_factor = compptr->v_samp_factor; + compptr->v_samp_factor = itemp; + } + + /* Transpose quantization tables */ + for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) { + qtblptr = dstinfo->quant_tbl_ptrs[tblno]; + if (qtblptr != NULL) { + for (i = 0; i < DCTSIZE; i++) { + for (j = 0; j < i; j++) { + qtemp = qtblptr->quantval[i*DCTSIZE+j]; + qtblptr->quantval[i*DCTSIZE+j] = qtblptr->quantval[j*DCTSIZE+i]; + qtblptr->quantval[j*DCTSIZE+i] = qtemp; + } + } + } + } +} + + +/* Trim off any partial iMCUs on the indicated destination edge */ + +LOCAL(void) +trim_right_edge (j_compress_ptr dstinfo) +{ + int ci, max_h_samp_factor; + JDIMENSION MCU_cols; + + /* We have to compute max_h_samp_factor ourselves, + * because it hasn't been set yet in the destination + * (and we don't want to use the source's value). + */ + max_h_samp_factor = 1; + for (ci = 0; ci < dstinfo->num_components; ci++) { + int h_samp_factor = dstinfo->comp_info[ci].h_samp_factor; + max_h_samp_factor = MAX(max_h_samp_factor, h_samp_factor); + } + MCU_cols = dstinfo->image_width / (max_h_samp_factor * DCTSIZE); + if (MCU_cols > 0) /* can't trim to 0 pixels */ + dstinfo->image_width = MCU_cols * (max_h_samp_factor * DCTSIZE); +} + +LOCAL(void) +trim_bottom_edge (j_compress_ptr dstinfo) +{ + int ci, max_v_samp_factor; + JDIMENSION MCU_rows; + + /* We have to compute max_v_samp_factor ourselves, + * because it hasn't been set yet in the destination + * (and we don't want to use the source's value). + */ + max_v_samp_factor = 1; + for (ci = 0; ci < dstinfo->num_components; ci++) { + int v_samp_factor = dstinfo->comp_info[ci].v_samp_factor; + max_v_samp_factor = MAX(max_v_samp_factor, v_samp_factor); + } + MCU_rows = dstinfo->image_height / (max_v_samp_factor * DCTSIZE); + if (MCU_rows > 0) /* can't trim to 0 pixels */ + dstinfo->image_height = MCU_rows * (max_v_samp_factor * DCTSIZE); +} + + +/* Adjust output image parameters as needed. + * + * This must be called after jpeg_copy_critical_parameters() + * and before jpeg_write_coefficients(). + * + * The return value is the set of virtual coefficient arrays to be written + * (either the ones allocated by jtransform_request_workspace, or the + * original source data arrays). The caller will need to pass this value + * to jpeg_write_coefficients(). + */ + +GLOBAL(jvirt_barray_ptr *) +jtransform_adjust_parameters (j_decompress_ptr srcinfo, + j_compress_ptr dstinfo, + jvirt_barray_ptr *src_coef_arrays, + jpeg_transform_info *info) +{ + /* If force-to-grayscale is requested, adjust destination parameters */ + if (info->force_grayscale) { + /* We use jpeg_set_colorspace to make sure subsidiary settings get fixed + * properly. Among other things, the target h_samp_factor & v_samp_factor + * will get set to 1, which typically won't match the source. + * In fact we do this even if the source is already grayscale; that + * provides an easy way of coercing a grayscale JPEG with funny sampling + * factors to the customary 1,1. (Some decoders fail on other factors.) + */ + if ((dstinfo->jpeg_color_space == JCS_YCbCr && + dstinfo->num_components == 3) || + (dstinfo->jpeg_color_space == JCS_GRAYSCALE && + dstinfo->num_components == 1)) { + /* We have to preserve the source's quantization table number. */ + int sv_quant_tbl_no = dstinfo->comp_info[0].quant_tbl_no; + jpeg_set_colorspace(dstinfo, JCS_GRAYSCALE); + dstinfo->comp_info[0].quant_tbl_no = sv_quant_tbl_no; + } else { + /* Sorry, can't do it */ + ERREXIT(dstinfo, JERR_CONVERSION_NOTIMPL); + } + } + + /* Correct the destination's image dimensions etc if necessary */ + switch (info->transform) { + case JXFORM_NONE: + /* Nothing to do */ + break; + case JXFORM_FLIP_H: + if (info->trim) + trim_right_edge(dstinfo); + break; + case JXFORM_FLIP_V: + if (info->trim) + trim_bottom_edge(dstinfo); + break; + case JXFORM_TRANSPOSE: + transpose_critical_parameters(dstinfo); + /* transpose does NOT have to trim anything */ + break; + case JXFORM_TRANSVERSE: + transpose_critical_parameters(dstinfo); + if (info->trim) { + trim_right_edge(dstinfo); + trim_bottom_edge(dstinfo); + } + break; + case JXFORM_ROT_90: + transpose_critical_parameters(dstinfo); + if (info->trim) + trim_right_edge(dstinfo); + break; + case JXFORM_ROT_180: + if (info->trim) { + trim_right_edge(dstinfo); + trim_bottom_edge(dstinfo); + } + break; + case JXFORM_ROT_270: + transpose_critical_parameters(dstinfo); + if (info->trim) + trim_bottom_edge(dstinfo); + break; + } + + /* Return the appropriate output data set */ + if (info->workspace_coef_arrays != NULL) + return info->workspace_coef_arrays; + return src_coef_arrays; +} + + +/* Execute the actual transformation, if any. + * + * This must be called *after* jpeg_write_coefficients, because it depends + * on jpeg_write_coefficients to have computed subsidiary values such as + * the per-component width and height fields in the destination object. + * + * Note that some transformations will modify the source data arrays! + */ + +GLOBAL(void) +jtransform_execute_transformation (j_decompress_ptr srcinfo, + j_compress_ptr dstinfo, + jvirt_barray_ptr *src_coef_arrays, + jpeg_transform_info *info) +{ + jvirt_barray_ptr *dst_coef_arrays = info->workspace_coef_arrays; + + switch (info->transform) { + case JXFORM_NONE: + break; + case JXFORM_FLIP_H: + do_flip_h(srcinfo, dstinfo, src_coef_arrays); + break; + case JXFORM_FLIP_V: + do_flip_v(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); + break; + case JXFORM_TRANSPOSE: + do_transpose(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); + break; + case JXFORM_TRANSVERSE: + do_transverse(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); + break; + case JXFORM_ROT_90: + do_rot_90(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); + break; + case JXFORM_ROT_180: + do_rot_180(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); + break; + case JXFORM_ROT_270: + do_rot_270(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); + break; + } +} + +#endif /* TRANSFORMS_SUPPORTED */ + + +/* Setup decompression object to save desired markers in memory. + * This must be called before jpeg_read_header() to have the desired effect. + */ + +GLOBAL(void) +jcopy_markers_setup (j_decompress_ptr srcinfo, JCOPY_OPTION option) +{ +#ifdef SAVE_MARKERS_SUPPORTED + int m; + + /* Save comments except under NONE option */ + if (option != JCOPYOPT_NONE) { + jpeg_save_markers(srcinfo, JPEG_COM, 0xFFFF); + } + /* Save all types of APPn markers iff ALL option */ + if (option == JCOPYOPT_ALL) { + for (m = 0; m < 16; m++) + jpeg_save_markers(srcinfo, JPEG_APP0 + m, 0xFFFF); + } +#endif /* SAVE_MARKERS_SUPPORTED */ +} + +/* Copy markers saved in the given source object to the destination object. + * This should be called just after jpeg_start_compress() or + * jpeg_write_coefficients(). + * Note that those routines will have written the SOI, and also the + * JFIF APP0 or Adobe APP14 markers if selected. + */ + +GLOBAL(void) +jcopy_markers_execute (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + JCOPY_OPTION option) +{ + jpeg_saved_marker_ptr marker; + + /* In the current implementation, we don't actually need to examine the + * option flag here; we just copy everything that got saved. + * But to avoid confusion, we do not output JFIF and Adobe APP14 markers + * if the encoder library already wrote one. + */ + for (marker = srcinfo->marker_list; marker != NULL; marker = marker->next) { + if (dstinfo->write_JFIF_header && + marker->marker == JPEG_APP0 && + marker->data_length >= 5 && + GETJOCTET(marker->data[0]) == 0x4A && + GETJOCTET(marker->data[1]) == 0x46 && + GETJOCTET(marker->data[2]) == 0x49 && + GETJOCTET(marker->data[3]) == 0x46 && + GETJOCTET(marker->data[4]) == 0) + continue; /* reject duplicate JFIF */ + if (dstinfo->write_Adobe_marker && + marker->marker == JPEG_APP0+14 && + marker->data_length >= 5 && + GETJOCTET(marker->data[0]) == 0x41 && + GETJOCTET(marker->data[1]) == 0x64 && + GETJOCTET(marker->data[2]) == 0x6F && + GETJOCTET(marker->data[3]) == 0x62 && + GETJOCTET(marker->data[4]) == 0x65) + continue; /* reject duplicate Adobe */ +#ifdef NEED_FAR_POINTERS + /* We could use jpeg_write_marker if the data weren't FAR... */ + { + unsigned int i; + jpeg_write_m_header(dstinfo, marker->marker, marker->data_length); + for (i = 0; i < marker->data_length; i++) + jpeg_write_m_byte(dstinfo, marker->data[i]); + } +#else + jpeg_write_marker(dstinfo, marker->marker, + marker->data, marker->data_length); +#endif + } +} diff --git a/mk4/modimage/jpeg-6b/transupp.h b/mk4/modimage/jpeg-6b/transupp.h new file mode 100644 index 0000000..5c2d32a --- /dev/null +++ b/mk4/modimage/jpeg-6b/transupp.h @@ -0,0 +1,135 @@ +/* + * transupp.h + * + * Copyright (C) 1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains declarations for image transformation routines and + * other utility code used by the jpegtran sample application. These are + * NOT part of the core JPEG library. But we keep these routines separate + * from jpegtran.c to ease the task of maintaining jpegtran-like programs + * that have other user interfaces. + * + * NOTE: all the routines declared here have very specific requirements + * about when they are to be executed during the reading and writing of the + * source and destination files. See the comments in transupp.c, or see + * jpegtran.c for an example of correct usage. + */ + +/* If you happen not to want the image transform support, disable it here */ +#ifndef TRANSFORMS_SUPPORTED +#define TRANSFORMS_SUPPORTED 1 /* 0 disables transform code */ +#endif + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jtransform_request_workspace jTrRequest +#define jtransform_adjust_parameters jTrAdjust +#define jtransform_execute_transformation jTrExec +#define jcopy_markers_setup jCMrkSetup +#define jcopy_markers_execute jCMrkExec +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* + * Codes for supported types of image transformations. + */ + +typedef enum { + JXFORM_NONE, /* no transformation */ + JXFORM_FLIP_H, /* horizontal flip */ + JXFORM_FLIP_V, /* vertical flip */ + JXFORM_TRANSPOSE, /* transpose across UL-to-LR axis */ + JXFORM_TRANSVERSE, /* transpose across UR-to-LL axis */ + JXFORM_ROT_90, /* 90-degree clockwise rotation */ + JXFORM_ROT_180, /* 180-degree rotation */ + JXFORM_ROT_270 /* 270-degree clockwise (or 90 ccw) */ +} JXFORM_CODE; + +/* + * Although rotating and flipping data expressed as DCT coefficients is not + * hard, there is an asymmetry in the JPEG format specification for images + * whose dimensions aren't multiples of the iMCU size. The right and bottom + * image edges are padded out to the next iMCU boundary with junk data; but + * no padding is possible at the top and left edges. If we were to flip + * the whole image including the pad data, then pad garbage would become + * visible at the top and/or left, and real pixels would disappear into the + * pad margins --- perhaps permanently, since encoders & decoders may not + * bother to preserve DCT blocks that appear to be completely outside the + * nominal image area. So, we have to exclude any partial iMCUs from the + * basic transformation. + * + * Transpose is the only transformation that can handle partial iMCUs at the + * right and bottom edges completely cleanly. flip_h can flip partial iMCUs + * at the bottom, but leaves any partial iMCUs at the right edge untouched. + * Similarly flip_v leaves any partial iMCUs at the bottom edge untouched. + * The other transforms are defined as combinations of these basic transforms + * and process edge blocks in a way that preserves the equivalence. + * + * The "trim" option causes untransformable partial iMCUs to be dropped; + * this is not strictly lossless, but it usually gives the best-looking + * result for odd-size images. Note that when this option is active, + * the expected mathematical equivalences between the transforms may not hold. + * (For example, -rot 270 -trim trims only the bottom edge, but -rot 90 -trim + * followed by -rot 180 -trim trims both edges.) + * + * We also offer a "force to grayscale" option, which simply discards the + * chrominance channels of a YCbCr image. This is lossless in the sense that + * the luminance channel is preserved exactly. It's not the same kind of + * thing as the rotate/flip transformations, but it's convenient to handle it + * as part of this package, mainly because the transformation routines have to + * be aware of the option to know how many components to work on. + */ + +typedef struct { + /* Options: set by caller */ + JXFORM_CODE transform; /* image transform operator */ + boolean trim; /* if TRUE, trim partial MCUs as needed */ + boolean force_grayscale; /* if TRUE, convert color image to grayscale */ + + /* Internal workspace: caller should not touch these */ + int num_components; /* # of components in workspace */ + jvirt_barray_ptr * workspace_coef_arrays; /* workspace for transformations */ +} jpeg_transform_info; + + +#if TRANSFORMS_SUPPORTED + +/* Request any required workspace */ +EXTERN(void) jtransform_request_workspace + JPP((j_decompress_ptr srcinfo, jpeg_transform_info *info)); +/* Adjust output image parameters */ +EXTERN(jvirt_barray_ptr *) jtransform_adjust_parameters + JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + jvirt_barray_ptr *src_coef_arrays, + jpeg_transform_info *info)); +/* Execute the actual transformation, if any */ +EXTERN(void) jtransform_execute_transformation + JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + jvirt_barray_ptr *src_coef_arrays, + jpeg_transform_info *info)); + +#endif /* TRANSFORMS_SUPPORTED */ + + +/* + * Support for copying optional markers from source to destination file. + */ + +typedef enum { + JCOPYOPT_NONE, /* copy no optional markers */ + JCOPYOPT_COMMENTS, /* copy only comment (COM) markers */ + JCOPYOPT_ALL /* copy all optional markers */ +} JCOPY_OPTION; + +#define JCOPYOPT_DEFAULT JCOPYOPT_COMMENTS /* recommended default */ + +/* Setup decompression object to save desired markers in memory */ +EXTERN(void) jcopy_markers_setup + JPP((j_decompress_ptr srcinfo, JCOPY_OPTION option)); +/* Copy markers saved in the given source object to the destination object */ +EXTERN(void) jcopy_markers_execute + JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + JCOPY_OPTION option)); diff --git a/mk4/modimage/jpeg-6b/usage.doc b/mk4/modimage/jpeg-6b/usage.doc new file mode 100644 index 0000000..8c4970a --- /dev/null +++ b/mk4/modimage/jpeg-6b/usage.doc @@ -0,0 +1,562 @@ +USAGE instructions for the Independent JPEG Group's JPEG software +================================================================= + +This file describes usage of the JPEG conversion programs cjpeg and djpeg, +as well as the utility programs jpegtran, rdjpgcom and wrjpgcom. (See +the other documentation files if you wish to use the JPEG library within +your own programs.) + +If you are on a Unix machine you may prefer to read the Unix-style manual +pages in files cjpeg.1, djpeg.1, jpegtran.1, rdjpgcom.1, wrjpgcom.1. + + +INTRODUCTION + +These programs implement JPEG image compression and decompression. JPEG +(pronounced "jay-peg") is a standardized compression method for full-color +and gray-scale images. JPEG is designed to handle "real-world" scenes, +for example scanned photographs. Cartoons, line drawings, and other +non-realistic images are not JPEG's strong suit; on that sort of material +you may get poor image quality and/or little compression. + +JPEG is lossy, meaning that the output image is not necessarily identical to +the input image. Hence you should not use JPEG if you have to have identical +output bits. However, on typical real-world images, very good compression +levels can be obtained with no visible change, and amazingly high compression +is possible if you can tolerate a low-quality image. You can trade off image +quality against file size by adjusting the compressor's "quality" setting. + + +GENERAL USAGE + +We provide two programs, cjpeg to compress an image file into JPEG format, +and djpeg to decompress a JPEG file back into a conventional image format. + +On Unix-like systems, you say: + cjpeg [switches] [imagefile] >jpegfile +or + djpeg [switches] [jpegfile] >imagefile +The programs read the specified input file, or standard input if none is +named. They always write to standard output (with trace/error messages to +standard error). These conventions are handy for piping images between +programs. + +On most non-Unix systems, you say: + cjpeg [switches] imagefile jpegfile +or + djpeg [switches] jpegfile imagefile +i.e., both the input and output files are named on the command line. This +style is a little more foolproof, and it loses no functionality if you don't +have pipes. (You can get this style on Unix too, if you prefer, by defining +TWO_FILE_COMMANDLINE when you compile the programs; see install.doc.) + +You can also say: + cjpeg [switches] -outfile jpegfile imagefile +or + djpeg [switches] -outfile imagefile jpegfile +This syntax works on all systems, so it is useful for scripts. + +The currently supported image file formats are: PPM (PBMPLUS color format), +PGM (PBMPLUS gray-scale format), BMP, Targa, and RLE (Utah Raster Toolkit +format). (RLE is supported only if the URT library is available.) +cjpeg recognizes the input image format automatically, with the exception +of some Targa-format files. You have to tell djpeg which format to generate. + +JPEG files are in the defacto standard JFIF file format. There are other, +less widely used JPEG-based file formats, but we don't support them. + +All switch names may be abbreviated; for example, -grayscale may be written +-gray or -gr. Most of the "basic" switches can be abbreviated to as little as +one letter. Upper and lower case are equivalent (-BMP is the same as -bmp). +British spellings are also accepted (e.g., -greyscale), though for brevity +these are not mentioned below. + + +CJPEG DETAILS + +The basic command line switches for cjpeg are: + + -quality N Scale quantization tables to adjust image quality. + Quality is 0 (worst) to 100 (best); default is 75. + (See below for more info.) + + -grayscale Create monochrome JPEG file from color input. + Be sure to use this switch when compressing a grayscale + BMP file, because cjpeg isn't bright enough to notice + whether a BMP file uses only shades of gray. By + saying -grayscale, you'll get a smaller JPEG file that + takes less time to process. + + -optimize Perform optimization of entropy encoding parameters. + Without this, default encoding parameters are used. + -optimize usually makes the JPEG file a little smaller, + but cjpeg runs somewhat slower and needs much more + memory. Image quality and speed of decompression are + unaffected by -optimize. + + -progressive Create progressive JPEG file (see below). + + -targa Input file is Targa format. Targa files that contain + an "identification" field will not be automatically + recognized by cjpeg; for such files you must specify + -targa to make cjpeg treat the input as Targa format. + For most Targa files, you won't need this switch. + +The -quality switch lets you trade off compressed file size against quality of +the reconstructed image: the higher the quality setting, the larger the JPEG +file, and the closer the output image will be to the original input. Normally +you want to use the lowest quality setting (smallest file) that decompresses +into something visually indistinguishable from the original image. For this +purpose the quality setting should be between 50 and 95; the default of 75 is +often about right. If you see defects at -quality 75, then go up 5 or 10 +counts at a time until you are happy with the output image. (The optimal +setting will vary from one image to another.) + +-quality 100 will generate a quantization table of all 1's, minimizing loss +in the quantization step (but there is still information loss in subsampling, +as well as roundoff error). This setting is mainly of interest for +experimental purposes. Quality values above about 95 are NOT recommended for +normal use; the compressed file size goes up dramatically for hardly any gain +in output image quality. + +In the other direction, quality values below 50 will produce very small files +of low image quality. Settings around 5 to 10 might be useful in preparing an +index of a large image library, for example. Try -quality 2 (or so) for some +amusing Cubist effects. (Note: quality values below about 25 generate 2-byte +quantization tables, which are considered optional in the JPEG standard. +cjpeg emits a warning message when you give such a quality value, because some +other JPEG programs may be unable to decode the resulting file. Use -baseline +if you need to ensure compatibility at low quality values.) + +The -progressive switch creates a "progressive JPEG" file. In this type of +JPEG file, the data is stored in multiple scans of increasing quality. If the +file is being transmitted over a slow communications link, the decoder can use +the first scan to display a low-quality image very quickly, and can then +improve the display with each subsequent scan. The final image is exactly +equivalent to a standard JPEG file of the same quality setting, and the total +file size is about the same --- often a little smaller. CAUTION: progressive +JPEG is not yet widely implemented, so many decoders will be unable to view a +progressive JPEG file at all. + +Switches for advanced users: + + -dct int Use integer DCT method (default). + -dct fast Use fast integer DCT (less accurate). + -dct float Use floating-point DCT method. + The float method is very slightly more accurate than + the int method, but is much slower unless your machine + has very fast floating-point hardware. Also note that + results of the floating-point method may vary slightly + across machines, while the integer methods should give + the same results everywhere. The fast integer method + is much less accurate than the other two. + + -restart N Emit a JPEG restart marker every N MCU rows, or every + N MCU blocks if "B" is attached to the number. + -restart 0 (the default) means no restart markers. + + -smooth N Smooth the input image to eliminate dithering noise. + N, ranging from 1 to 100, indicates the strength of + smoothing. 0 (the default) means no smoothing. + + -maxmemory N Set limit for amount of memory to use in processing + large images. Value is in thousands of bytes, or + millions of bytes if "M" is attached to the number. + For example, -max 4m selects 4000000 bytes. If more + space is needed, temporary files will be used. + + -verbose Enable debug printout. More -v's give more printout. + or -debug Also, version information is printed at startup. + +The -restart option inserts extra markers that allow a JPEG decoder to +resynchronize after a transmission error. Without restart markers, any damage +to a compressed file will usually ruin the image from the point of the error +to the end of the image; with restart markers, the damage is usually confined +to the portion of the image up to the next restart marker. Of course, the +restart markers occupy extra space. We recommend -restart 1 for images that +will be transmitted across unreliable networks such as Usenet. + +The -smooth option filters the input to eliminate fine-scale noise. This is +often useful when converting dithered images to JPEG: a moderate smoothing +factor of 10 to 50 gets rid of dithering patterns in the input file, resulting +in a smaller JPEG file and a better-looking image. Too large a smoothing +factor will visibly blur the image, however. + +Switches for wizards: + + -baseline Force baseline-compatible quantization tables to be + generated. This clamps quantization values to 8 bits + even at low quality settings. (This switch is poorly + named, since it does not ensure that the output is + actually baseline JPEG. For example, you can use + -baseline and -progressive together.) + + -qtables file Use the quantization tables given in the specified + text file. + + -qslots N[,...] Select which quantization table to use for each color + component. + + -sample HxV[,...] Set JPEG sampling factors for each color component. + + -scans file Use the scan script given in the specified text file. + +The "wizard" switches are intended for experimentation with JPEG. If you +don't know what you are doing, DON'T USE THEM. These switches are documented +further in the file wizard.doc. + + +DJPEG DETAILS + +The basic command line switches for djpeg are: + + -colors N Reduce image to at most N colors. This reduces the + or -quantize N number of colors used in the output image, so that it + can be displayed on a colormapped display or stored in + a colormapped file format. For example, if you have + an 8-bit display, you'd need to reduce to 256 or fewer + colors. (-colors is the recommended name, -quantize + is provided only for backwards compatibility.) + + -fast Select recommended processing options for fast, low + quality output. (The default options are chosen for + highest quality output.) Currently, this is equivalent + to "-dct fast -nosmooth -onepass -dither ordered". + + -grayscale Force gray-scale output even if JPEG file is color. + Useful for viewing on monochrome displays; also, + djpeg runs noticeably faster in this mode. + + -scale M/N Scale the output image by a factor M/N. Currently + the scale factor must be 1/1, 1/2, 1/4, or 1/8. + Scaling is handy if the image is larger than your + screen; also, djpeg runs much faster when scaling + down the output. + + -bmp Select BMP output format (Windows flavor). 8-bit + colormapped format is emitted if -colors or -grayscale + is specified, or if the JPEG file is gray-scale; + otherwise, 24-bit full-color format is emitted. + + -gif Select GIF output format. Since GIF does not support + more than 256 colors, -colors 256 is assumed (unless + you specify a smaller number of colors). If you + specify -fast, the default number of colors is 216. + + -os2 Select BMP output format (OS/2 1.x flavor). 8-bit + colormapped format is emitted if -colors or -grayscale + is specified, or if the JPEG file is gray-scale; + otherwise, 24-bit full-color format is emitted. + + -pnm Select PBMPLUS (PPM/PGM) output format (this is the + default format). PGM is emitted if the JPEG file is + gray-scale or if -grayscale is specified; otherwise + PPM is emitted. + + -rle Select RLE output format. (Requires URT library.) + + -targa Select Targa output format. Gray-scale format is + emitted if the JPEG file is gray-scale or if + -grayscale is specified; otherwise, colormapped format + is emitted if -colors is specified; otherwise, 24-bit + full-color format is emitted. + +Switches for advanced users: + + -dct int Use integer DCT method (default). + -dct fast Use fast integer DCT (less accurate). + -dct float Use floating-point DCT method. + The float method is very slightly more accurate than + the int method, but is much slower unless your machine + has very fast floating-point hardware. Also note that + results of the floating-point method may vary slightly + across machines, while the integer methods should give + the same results everywhere. The fast integer method + is much less accurate than the other two. + + -dither fs Use Floyd-Steinberg dithering in color quantization. + -dither ordered Use ordered dithering in color quantization. + -dither none Do not use dithering in color quantization. + By default, Floyd-Steinberg dithering is applied when + quantizing colors; this is slow but usually produces + the best results. Ordered dither is a compromise + between speed and quality; no dithering is fast but + usually looks awful. Note that these switches have + no effect unless color quantization is being done. + Ordered dither is only available in -onepass mode. + + -map FILE Quantize to the colors used in the specified image + file. This is useful for producing multiple files + with identical color maps, or for forcing a predefined + set of colors to be used. The FILE must be a GIF + or PPM file. This option overrides -colors and + -onepass. + + -nosmooth Use a faster, lower-quality upsampling routine. + + -onepass Use one-pass instead of two-pass color quantization. + The one-pass method is faster and needs less memory, + but it produces a lower-quality image. -onepass is + ignored unless you also say -colors N. Also, + the one-pass method is always used for gray-scale + output (the two-pass method is no improvement then). + + -maxmemory N Set limit for amount of memory to use in processing + large images. Value is in thousands of bytes, or + millions of bytes if "M" is attached to the number. + For example, -max 4m selects 4000000 bytes. If more + space is needed, temporary files will be used. + + -verbose Enable debug printout. More -v's give more printout. + or -debug Also, version information is printed at startup. + + +HINTS FOR CJPEG + +Color GIF files are not the ideal input for JPEG; JPEG is really intended for +compressing full-color (24-bit) images. In particular, don't try to convert +cartoons, line drawings, and other images that have only a few distinct +colors. GIF works great on these, JPEG does not. If you want to convert a +GIF to JPEG, you should experiment with cjpeg's -quality and -smooth options +to get a satisfactory conversion. -smooth 10 or so is often helpful. + +Avoid running an image through a series of JPEG compression/decompression +cycles. Image quality loss will accumulate; after ten or so cycles the image +may be noticeably worse than it was after one cycle. It's best to use a +lossless format while manipulating an image, then convert to JPEG format when +you are ready to file the image away. + +The -optimize option to cjpeg is worth using when you are making a "final" +version for posting or archiving. It's also a win when you are using low +quality settings to make very small JPEG files; the percentage improvement +is often a lot more than it is on larger files. (At present, -optimize +mode is always selected when generating progressive JPEG files.) + +GIF input files are no longer supported, to avoid the Unisys LZW patent. +Use a Unisys-licensed program if you need to read a GIF file. (Conversion +of GIF files to JPEG is usually a bad idea anyway.) + + +HINTS FOR DJPEG + +To get a quick preview of an image, use the -grayscale and/or -scale switches. +"-grayscale -scale 1/8" is the fastest case. + +Several options are available that trade off image quality to gain speed. +"-fast" turns on the recommended settings. + +"-dct fast" and/or "-nosmooth" gain speed at a small sacrifice in quality. +When producing a color-quantized image, "-onepass -dither ordered" is fast but +much lower quality than the default behavior. "-dither none" may give +acceptable results in two-pass mode, but is seldom tolerable in one-pass mode. + +If you are fortunate enough to have very fast floating point hardware, +"-dct float" may be even faster than "-dct fast". But on most machines +"-dct float" is slower than "-dct int"; in this case it is not worth using, +because its theoretical accuracy advantage is too small to be significant +in practice. + +Two-pass color quantization requires a good deal of memory; on MS-DOS machines +it may run out of memory even with -maxmemory 0. In that case you can still +decompress, with some loss of image quality, by specifying -onepass for +one-pass quantization. + +To avoid the Unisys LZW patent, djpeg produces uncompressed GIF files. These +are larger than they should be, but are readable by standard GIF decoders. + + +HINTS FOR BOTH PROGRAMS + +If more space is needed than will fit in the available main memory (as +determined by -maxmemory), temporary files will be used. (MS-DOS versions +will try to get extended or expanded memory first.) The temporary files are +often rather large: in typical cases they occupy three bytes per pixel, for +example 3*800*600 = 1.44Mb for an 800x600 image. If you don't have enough +free disk space, leave out -progressive and -optimize (for cjpeg) or specify +-onepass (for djpeg). + +On MS-DOS, the temporary files are created in the directory named by the TMP +or TEMP environment variable, or in the current directory if neither of those +exist. Amiga implementations put the temp files in the directory named by +JPEGTMP:, so be sure to assign JPEGTMP: to a disk partition with adequate free +space. + +The default memory usage limit (-maxmemory) is set when the software is +compiled. If you get an "insufficient memory" error, try specifying a smaller +-maxmemory value, even -maxmemory 0 to use the absolute minimum space. You +may want to recompile with a smaller default value if this happens often. + +On machines that have "environment" variables, you can define the environment +variable JPEGMEM to set the default memory limit. The value is specified as +described for the -maxmemory switch. JPEGMEM overrides the default value +specified when the program was compiled, and itself is overridden by an +explicit -maxmemory switch. + +On MS-DOS machines, -maxmemory is the amount of main (conventional) memory to +use. (Extended or expanded memory is also used if available.) Most +DOS-specific versions of this software do their own memory space estimation +and do not need you to specify -maxmemory. + + +JPEGTRAN + +jpegtran performs various useful transformations of JPEG files. +It can translate the coded representation from one variant of JPEG to another, +for example from baseline JPEG to progressive JPEG or vice versa. It can also +perform some rearrangements of the image data, for example turning an image +from landscape to portrait format by rotation. + +jpegtran works by rearranging the compressed data (DCT coefficients), without +ever fully decoding the image. Therefore, its transformations are lossless: +there is no image degradation at all, which would not be true if you used +djpeg followed by cjpeg to accomplish the same conversion. But by the same +token, jpegtran cannot perform lossy operations such as changing the image +quality. + +jpegtran uses a command line syntax similar to cjpeg or djpeg. +On Unix-like systems, you say: + jpegtran [switches] [inputfile] >outputfile +On most non-Unix systems, you say: + jpegtran [switches] inputfile outputfile +where both the input and output files are JPEG files. + +To specify the coded JPEG representation used in the output file, +jpegtran accepts a subset of the switches recognized by cjpeg: + -optimize Perform optimization of entropy encoding parameters. + -progressive Create progressive JPEG file. + -restart N Emit a JPEG restart marker every N MCU rows, or every + N MCU blocks if "B" is attached to the number. + -scans file Use the scan script given in the specified text file. +See the previous discussion of cjpeg for more details about these switches. +If you specify none of these switches, you get a plain baseline-JPEG output +file. The quality setting and so forth are determined by the input file. + +The image can be losslessly transformed by giving one of these switches: + -flip horizontal Mirror image horizontally (left-right). + -flip vertical Mirror image vertically (top-bottom). + -rotate 90 Rotate image 90 degrees clockwise. + -rotate 180 Rotate image 180 degrees. + -rotate 270 Rotate image 270 degrees clockwise (or 90 ccw). + -transpose Transpose image (across UL-to-LR axis). + -transverse Transverse transpose (across UR-to-LL axis). + +The transpose transformation has no restrictions regarding image dimensions. +The other transformations operate rather oddly if the image dimensions are not +a multiple of the iMCU size (usually 8 or 16 pixels), because they can only +transform complete blocks of DCT coefficient data in the desired way. + +jpegtran's default behavior when transforming an odd-size image is designed +to preserve exact reversibility and mathematical consistency of the +transformation set. As stated, transpose is able to flip the entire image +area. Horizontal mirroring leaves any partial iMCU column at the right edge +untouched, but is able to flip all rows of the image. Similarly, vertical +mirroring leaves any partial iMCU row at the bottom edge untouched, but is +able to flip all columns. The other transforms can be built up as sequences +of transpose and flip operations; for consistency, their actions on edge +pixels are defined to be the same as the end result of the corresponding +transpose-and-flip sequence. + +For practical use, you may prefer to discard any untransformable edge pixels +rather than having a strange-looking strip along the right and/or bottom edges +of a transformed image. To do this, add the -trim switch: + -trim Drop non-transformable edge blocks. +Obviously, a transformation with -trim is not reversible, so strictly speaking +jpegtran with this switch is not lossless. Also, the expected mathematical +equivalences between the transformations no longer hold. For example, +"-rot 270 -trim" trims only the bottom edge, but "-rot 90 -trim" followed by +"-rot 180 -trim" trims both edges. + +Another not-strictly-lossless transformation switch is: + -grayscale Force grayscale output. +This option discards the chrominance channels if the input image is YCbCr +(ie, a standard color JPEG), resulting in a grayscale JPEG file. The +luminance channel is preserved exactly, so this is a better method of reducing +to grayscale than decompression, conversion, and recompression. This switch +is particularly handy for fixing a monochrome picture that was mistakenly +encoded as a color JPEG. (In such a case, the space savings from getting rid +of the near-empty chroma channels won't be large; but the decoding time for +a grayscale JPEG is substantially less than that for a color JPEG.) + +jpegtran also recognizes these switches that control what to do with "extra" +markers, such as comment blocks: + -copy none Copy no extra markers from source file. This setting + suppresses all comments and other excess baggage + present in the source file. + -copy comments Copy only comment markers. This setting copies + comments from the source file, but discards + any other inessential data. + -copy all Copy all extra markers. This setting preserves + miscellaneous markers found in the source file, such + as JFIF thumbnails and Photoshop settings. In some + files these extra markers can be sizable. +The default behavior is -copy comments. (Note: in IJG releases v6 and v6a, +jpegtran always did the equivalent of -copy none.) + +Additional switches recognized by jpegtran are: + -outfile filename + -maxmemory N + -verbose + -debug +These work the same as in cjpeg or djpeg. + + +THE COMMENT UTILITIES + +The JPEG standard allows "comment" (COM) blocks to occur within a JPEG file. +Although the standard doesn't actually define what COM blocks are for, they +are widely used to hold user-supplied text strings. This lets you add +annotations, titles, index terms, etc to your JPEG files, and later retrieve +them as text. COM blocks do not interfere with the image stored in the JPEG +file. The maximum size of a COM block is 64K, but you can have as many of +them as you like in one JPEG file. + +We provide two utility programs to display COM block contents and add COM +blocks to a JPEG file. + +rdjpgcom searches a JPEG file and prints the contents of any COM blocks on +standard output. The command line syntax is + rdjpgcom [-verbose] [inputfilename] +The switch "-verbose" (or just "-v") causes rdjpgcom to also display the JPEG +image dimensions. If you omit the input file name from the command line, +the JPEG file is read from standard input. (This may not work on some +operating systems, if binary data can't be read from stdin.) + +wrjpgcom adds a COM block, containing text you provide, to a JPEG file. +Ordinarily, the COM block is added after any existing COM blocks, but you +can delete the old COM blocks if you wish. wrjpgcom produces a new JPEG +file; it does not modify the input file. DO NOT try to overwrite the input +file by directing wrjpgcom's output back into it; on most systems this will +just destroy your file. + +The command line syntax for wrjpgcom is similar to cjpeg's. On Unix-like +systems, it is + wrjpgcom [switches] [inputfilename] +The output file is written to standard output. The input file comes from +the named file, or from standard input if no input file is named. + +On most non-Unix systems, the syntax is + wrjpgcom [switches] inputfilename outputfilename +where both input and output file names must be given explicitly. + +wrjpgcom understands three switches: + -replace Delete any existing COM blocks from the file. + -comment "Comment text" Supply new COM text on command line. + -cfile name Read text for new COM block from named file. +(Switch names can be abbreviated.) If you have only one line of comment text +to add, you can provide it on the command line with -comment. The comment +text must be surrounded with quotes so that it is treated as a single +argument. Longer comments can be read from a text file. + +If you give neither -comment nor -cfile, then wrjpgcom will read the comment +text from standard input. (In this case an input image file name MUST be +supplied, so that the source JPEG file comes from somewhere else.) You can +enter multiple lines, up to 64KB worth. Type an end-of-file indicator +(usually control-D or control-Z) to terminate the comment text entry. + +wrjpgcom will not add a COM block if the provided comment string is empty. +Therefore -replace -comment "" can be used to delete all COM blocks from a +file. + +These utility programs do not depend on the IJG JPEG library. In +particular, the source code for rdjpgcom is intended as an illustration of +the minimum amount of code required to parse a JPEG file header correctly. diff --git a/mk4/modimage/jpeg-6b/wizard.doc b/mk4/modimage/jpeg-6b/wizard.doc new file mode 100644 index 0000000..54170b2 --- /dev/null +++ b/mk4/modimage/jpeg-6b/wizard.doc @@ -0,0 +1,211 @@ +Advanced usage instructions for the Independent JPEG Group's JPEG software +========================================================================== + +This file describes cjpeg's "switches for wizards". + +The "wizard" switches are intended for experimentation with JPEG by persons +who are reasonably knowledgeable about the JPEG standard. If you don't know +what you are doing, DON'T USE THESE SWITCHES. You'll likely produce files +with worse image quality and/or poorer compression than you'd get from the +default settings. Furthermore, these switches must be used with caution +when making files intended for general use, because not all JPEG decoders +will support unusual JPEG parameter settings. + + +Quantization Table Adjustment +----------------------------- + +Ordinarily, cjpeg starts with a default set of tables (the same ones given +as examples in the JPEG standard) and scales them up or down according to +the -quality setting. The details of the scaling algorithm can be found in +jcparam.c. At very low quality settings, some quantization table entries +can get scaled up to values exceeding 255. Although 2-byte quantization +values are supported by the IJG software, this feature is not in baseline +JPEG and is not supported by all implementations. If you need to ensure +wide compatibility of low-quality files, you can constrain the scaled +quantization values to no more than 255 by giving the -baseline switch. +Note that use of -baseline will result in poorer quality for the same file +size, since more bits than necessary are expended on higher AC coefficients. + +You can substitute a different set of quantization values by using the +-qtables switch: + + -qtables file Use the quantization tables given in the named file. + +The specified file should be a text file containing decimal quantization +values. The file should contain one to four tables, each of 64 elements. +The tables are implicitly numbered 0,1,etc. in order of appearance. Table +entries appear in normal array order (NOT in the zigzag order in which they +will be stored in the JPEG file). + +Quantization table files are free format, in that arbitrary whitespace can +appear between numbers. Also, comments can be included: a comment starts +with '#' and extends to the end of the line. Here is an example file that +duplicates the default quantization tables: + + # Quantization tables given in JPEG spec, section K.1 + + # This is table 0 (the luminance table): + 16 11 10 16 24 40 51 61 + 12 12 14 19 26 58 60 55 + 14 13 16 24 40 57 69 56 + 14 17 22 29 51 87 80 62 + 18 22 37 56 68 109 103 77 + 24 35 55 64 81 104 113 92 + 49 64 78 87 103 121 120 101 + 72 92 95 98 112 100 103 99 + + # This is table 1 (the chrominance table): + 17 18 24 47 99 99 99 99 + 18 21 26 66 99 99 99 99 + 24 26 56 99 99 99 99 99 + 47 66 99 99 99 99 99 99 + 99 99 99 99 99 99 99 99 + 99 99 99 99 99 99 99 99 + 99 99 99 99 99 99 99 99 + 99 99 99 99 99 99 99 99 + +If the -qtables switch is used without -quality, then the specified tables +are used exactly as-is. If both -qtables and -quality are used, then the +tables taken from the file are scaled in the same fashion that the default +tables would be scaled for that quality setting. If -baseline appears, then +the quantization values are constrained to the range 1-255. + +By default, cjpeg will use quantization table 0 for luminance components and +table 1 for chrominance components. To override this choice, use the -qslots +switch: + + -qslots N[,...] Select which quantization table to use for + each color component. + +The -qslots switch specifies a quantization table number for each color +component, in the order in which the components appear in the JPEG SOF marker. +For example, to create a separate table for each of Y,Cb,Cr, you could +provide a -qtables file that defines three quantization tables and say +"-qslots 0,1,2". If -qslots gives fewer table numbers than there are color +components, then the last table number is repeated as necessary. + + +Sampling Factor Adjustment +-------------------------- + +By default, cjpeg uses 2:1 horizontal and vertical downsampling when +compressing YCbCr data, and no downsampling for all other color spaces. +You can override this default with the -sample switch: + + -sample HxV[,...] Set JPEG sampling factors for each color + component. + +The -sample switch specifies the JPEG sampling factors for each color +component, in the order in which they appear in the JPEG SOF marker. +If you specify fewer HxV pairs than there are components, the remaining +components are set to 1x1 sampling. For example, the default YCbCr setting +is equivalent to "-sample 2x2,1x1,1x1", which can be abbreviated to +"-sample 2x2". + +There are still some JPEG decoders in existence that support only 2x1 +sampling (also called 4:2:2 sampling). Compatibility with such decoders can +be achieved by specifying "-sample 2x1". This is not recommended unless +really necessary, since it increases file size and encoding/decoding time +with very little quality gain. + + +Multiple Scan / Progression Control +----------------------------------- + +By default, cjpeg emits a single-scan sequential JPEG file. The +-progressive switch generates a progressive JPEG file using a default series +of progression parameters. You can create multiple-scan sequential JPEG +files or progressive JPEG files with custom progression parameters by using +the -scans switch: + + -scans file Use the scan sequence given in the named file. + +The specified file should be a text file containing a "scan script". +The script specifies the contents and ordering of the scans to be emitted. +Each entry in the script defines one scan. A scan definition specifies +the components to be included in the scan, and for progressive JPEG it also +specifies the progression parameters Ss,Se,Ah,Al for the scan. Scan +definitions are separated by semicolons (';'). A semicolon after the last +scan definition is optional. + +Each scan definition contains one to four component indexes, optionally +followed by a colon (':') and the four progressive-JPEG parameters. The +component indexes denote which color component(s) are to be transmitted in +the scan. Components are numbered in the order in which they appear in the +JPEG SOF marker, with the first component being numbered 0. (Note that these +indexes are not the "component ID" codes assigned to the components, just +positional indexes.) + +The progression parameters for each scan are: + Ss Zigzag index of first coefficient included in scan + Se Zigzag index of last coefficient included in scan + Ah Zero for first scan of a coefficient, else Al of prior scan + Al Successive approximation low bit position for scan +If the progression parameters are omitted, the values 0,63,0,0 are used, +producing a sequential JPEG file. cjpeg automatically determines whether +the script represents a progressive or sequential file, by observing whether +Ss and Se values other than 0 and 63 appear. (The -progressive switch is +not needed to specify this; in fact, it is ignored when -scans appears.) +The scan script must meet the JPEG restrictions on progression sequences. +(cjpeg checks that the spec's requirements are obeyed.) + +Scan script files are free format, in that arbitrary whitespace can appear +between numbers and around punctuation. Also, comments can be included: a +comment starts with '#' and extends to the end of the line. For additional +legibility, commas or dashes can be placed between values. (Actually, any +single punctuation character other than ':' or ';' can be inserted.) For +example, the following two scan definitions are equivalent: + 0 1 2: 0 63 0 0; + 0,1,2 : 0-63, 0,0 ; + +Here is an example of a scan script that generates a partially interleaved +sequential JPEG file: + + 0; # Y only in first scan + 1 2; # Cb and Cr in second scan + +Here is an example of a progressive scan script using only spectral selection +(no successive approximation): + + # Interleaved DC scan for Y,Cb,Cr: + 0,1,2: 0-0, 0, 0 ; + # AC scans: + 0: 1-2, 0, 0 ; # First two Y AC coefficients + 0: 3-5, 0, 0 ; # Three more + 1: 1-63, 0, 0 ; # All AC coefficients for Cb + 2: 1-63, 0, 0 ; # All AC coefficients for Cr + 0: 6-9, 0, 0 ; # More Y coefficients + 0: 10-63, 0, 0 ; # Remaining Y coefficients + +Here is an example of a successive-approximation script. This is equivalent +to the default script used by "cjpeg -progressive" for YCbCr images: + + # Initial DC scan for Y,Cb,Cr (lowest bit not sent) + 0,1,2: 0-0, 0, 1 ; + # First AC scan: send first 5 Y AC coefficients, minus 2 lowest bits: + 0: 1-5, 0, 2 ; + # Send all Cr,Cb AC coefficients, minus lowest bit: + # (chroma data is usually too small to be worth subdividing further; + # but note we send Cr first since eye is least sensitive to Cb) + 2: 1-63, 0, 1 ; + 1: 1-63, 0, 1 ; + # Send remaining Y AC coefficients, minus 2 lowest bits: + 0: 6-63, 0, 2 ; + # Send next-to-lowest bit of all Y AC coefficients: + 0: 1-63, 2, 1 ; + # At this point we've sent all but the lowest bit of all coefficients. + # Send lowest bit of DC coefficients + 0,1,2: 0-0, 1, 0 ; + # Send lowest bit of AC coefficients + 2: 1-63, 1, 0 ; + 1: 1-63, 1, 0 ; + # Y AC lowest bit scan is last; it's usually the largest scan + 0: 1-63, 1, 0 ; + +It may be worth pointing out that this script is tuned for quality settings +of around 50 to 75. For lower quality settings, you'd probably want to use +a script with fewer stages of successive approximation (otherwise the +initial scans will be really bad). For higher quality settings, you might +want to use more stages of successive approximation (so that the initial +scans are not too large). diff --git a/mk4/modimage/jpeg-6b/wrbmp.c b/mk4/modimage/jpeg-6b/wrbmp.c new file mode 100644 index 0000000..3283b0f --- /dev/null +++ b/mk4/modimage/jpeg-6b/wrbmp.c @@ -0,0 +1,442 @@ +/* + * wrbmp.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to write output images in Microsoft "BMP" + * format (MS Windows 3.x and OS/2 1.x flavors). + * Either 8-bit colormapped or 24-bit full-color format can be written. + * No compression is supported. + * + * These routines may need modification for non-Unix environments or + * specialized applications. As they stand, they assume output to + * an ordinary stdio stream. + * + * This code contributed by James Arthur Boucher. + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ + +#ifdef BMP_SUPPORTED + + +/* + * To support 12-bit JPEG data, we'd have to scale output down to 8 bits. + * This is not yet implemented. + */ + +#if BITS_IN_JSAMPLE != 8 + Sorry, this code only copes with 8-bit JSAMPLEs. /* deliberate syntax err */ +#endif + +/* + * Since BMP stores scanlines bottom-to-top, we have to invert the image + * from JPEG's top-to-bottom order. To do this, we save the outgoing data + * in a virtual array during put_pixel_row calls, then actually emit the + * BMP file during finish_output. The virtual array contains one JSAMPLE per + * pixel if the output is grayscale or colormapped, three if it is full color. + */ + +/* Private version of data destination object */ + +typedef struct { + struct djpeg_dest_struct pub; /* public fields */ + + boolean is_os2; /* saves the OS2 format request flag */ + + jvirt_sarray_ptr whole_image; /* needed to reverse row order */ + JDIMENSION data_width; /* JSAMPLEs per row */ + JDIMENSION row_width; /* physical width of one row in the BMP file */ + int pad_bytes; /* number of padding bytes needed per row */ + JDIMENSION cur_output_row; /* next row# to write to virtual array */ +} bmp_dest_struct; + +typedef bmp_dest_struct * bmp_dest_ptr; + + +/* Forward declarations */ +LOCAL(void) write_colormap + JPP((j_decompress_ptr cinfo, bmp_dest_ptr dest, + int map_colors, int map_entry_size)); + + +/* + * Write some pixel data. + * In this module rows_supplied will always be 1. + */ + +METHODDEF(void) +put_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied) +/* This version is for writing 24-bit pixels */ +{ + bmp_dest_ptr dest = (bmp_dest_ptr) dinfo; + JSAMPARRAY image_ptr; + register JSAMPROW inptr, outptr; + register JDIMENSION col; + int pad; + + /* Access next row in virtual array */ + image_ptr = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, dest->whole_image, + dest->cur_output_row, (JDIMENSION) 1, TRUE); + dest->cur_output_row++; + + /* Transfer data. Note destination values must be in BGR order + * (even though Microsoft's own documents say the opposite). + */ + inptr = dest->pub.buffer[0]; + outptr = image_ptr[0]; + for (col = cinfo->output_width; col > 0; col--) { + outptr[2] = *inptr++; /* can omit GETJSAMPLE() safely */ + outptr[1] = *inptr++; + outptr[0] = *inptr++; + outptr += 3; + } + + /* Zero out the pad bytes. */ + pad = dest->pad_bytes; + while (--pad >= 0) + *outptr++ = 0; +} + +METHODDEF(void) +put_gray_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied) +/* This version is for grayscale OR quantized color output */ +{ + bmp_dest_ptr dest = (bmp_dest_ptr) dinfo; + JSAMPARRAY image_ptr; + register JSAMPROW inptr, outptr; + register JDIMENSION col; + int pad; + + /* Access next row in virtual array */ + image_ptr = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, dest->whole_image, + dest->cur_output_row, (JDIMENSION) 1, TRUE); + dest->cur_output_row++; + + /* Transfer data. */ + inptr = dest->pub.buffer[0]; + outptr = image_ptr[0]; + for (col = cinfo->output_width; col > 0; col--) { + *outptr++ = *inptr++; /* can omit GETJSAMPLE() safely */ + } + + /* Zero out the pad bytes. */ + pad = dest->pad_bytes; + while (--pad >= 0) + *outptr++ = 0; +} + + +/* + * Startup: normally writes the file header. + * In this module we may as well postpone everything until finish_output. + */ + +METHODDEF(void) +start_output_bmp (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo) +{ + /* no work here */ +} + + +/* + * Finish up at the end of the file. + * + * Here is where we really output the BMP file. + * + * First, routines to write the Windows and OS/2 variants of the file header. + */ + +LOCAL(void) +write_bmp_header (j_decompress_ptr cinfo, bmp_dest_ptr dest) +/* Write a Windows-style BMP file header, including colormap if needed */ +{ + char bmpfileheader[14]; + char bmpinfoheader[40]; +#define PUT_2B(array,offset,value) \ + (array[offset] = (char) ((value) & 0xFF), \ + array[offset+1] = (char) (((value) >> 8) & 0xFF)) +#define PUT_4B(array,offset,value) \ + (array[offset] = (char) ((value) & 0xFF), \ + array[offset+1] = (char) (((value) >> 8) & 0xFF), \ + array[offset+2] = (char) (((value) >> 16) & 0xFF), \ + array[offset+3] = (char) (((value) >> 24) & 0xFF)) + INT32 headersize, bfSize; + int bits_per_pixel, cmap_entries; + + /* Compute colormap size and total file size */ + if (cinfo->out_color_space == JCS_RGB) { + if (cinfo->quantize_colors) { + /* Colormapped RGB */ + bits_per_pixel = 8; + cmap_entries = 256; + } else { + /* Unquantized, full color RGB */ + bits_per_pixel = 24; + cmap_entries = 0; + } + } else { + /* Grayscale output. We need to fake a 256-entry colormap. */ + bits_per_pixel = 8; + cmap_entries = 256; + } + /* File size */ + headersize = 14 + 40 + cmap_entries * 4; /* Header and colormap */ + bfSize = headersize + (INT32) dest->row_width * (INT32) cinfo->output_height; + + /* Set unused fields of header to 0 */ + MEMZERO(bmpfileheader, SIZEOF(bmpfileheader)); + MEMZERO(bmpinfoheader, SIZEOF(bmpinfoheader)); + + /* Fill the file header */ + bmpfileheader[0] = 0x42; /* first 2 bytes are ASCII 'B', 'M' */ + bmpfileheader[1] = 0x4D; + PUT_4B(bmpfileheader, 2, bfSize); /* bfSize */ + /* we leave bfReserved1 & bfReserved2 = 0 */ + PUT_4B(bmpfileheader, 10, headersize); /* bfOffBits */ + + /* Fill the info header (Microsoft calls this a BITMAPINFOHEADER) */ + PUT_2B(bmpinfoheader, 0, 40); /* biSize */ + PUT_4B(bmpinfoheader, 4, cinfo->output_width); /* biWidth */ + PUT_4B(bmpinfoheader, 8, cinfo->output_height); /* biHeight */ + PUT_2B(bmpinfoheader, 12, 1); /* biPlanes - must be 1 */ + PUT_2B(bmpinfoheader, 14, bits_per_pixel); /* biBitCount */ + /* we leave biCompression = 0, for none */ + /* we leave biSizeImage = 0; this is correct for uncompressed data */ + if (cinfo->density_unit == 2) { /* if have density in dots/cm, then */ + PUT_4B(bmpinfoheader, 24, (INT32) (cinfo->X_density*100)); /* XPels/M */ + PUT_4B(bmpinfoheader, 28, (INT32) (cinfo->Y_density*100)); /* XPels/M */ + } + PUT_2B(bmpinfoheader, 32, cmap_entries); /* biClrUsed */ + /* we leave biClrImportant = 0 */ + + if (JFWRITE(dest->pub.output_file, bmpfileheader, 14) != (size_t) 14) + ERREXIT(cinfo, JERR_FILE_WRITE); + if (JFWRITE(dest->pub.output_file, bmpinfoheader, 40) != (size_t) 40) + ERREXIT(cinfo, JERR_FILE_WRITE); + + if (cmap_entries > 0) + write_colormap(cinfo, dest, cmap_entries, 4); +} + + +LOCAL(void) +write_os2_header (j_decompress_ptr cinfo, bmp_dest_ptr dest) +/* Write an OS2-style BMP file header, including colormap if needed */ +{ + char bmpfileheader[14]; + char bmpcoreheader[12]; + INT32 headersize, bfSize; + int bits_per_pixel, cmap_entries; + + /* Compute colormap size and total file size */ + if (cinfo->out_color_space == JCS_RGB) { + if (cinfo->quantize_colors) { + /* Colormapped RGB */ + bits_per_pixel = 8; + cmap_entries = 256; + } else { + /* Unquantized, full color RGB */ + bits_per_pixel = 24; + cmap_entries = 0; + } + } else { + /* Grayscale output. We need to fake a 256-entry colormap. */ + bits_per_pixel = 8; + cmap_entries = 256; + } + /* File size */ + headersize = 14 + 12 + cmap_entries * 3; /* Header and colormap */ + bfSize = headersize + (INT32) dest->row_width * (INT32) cinfo->output_height; + + /* Set unused fields of header to 0 */ + MEMZERO(bmpfileheader, SIZEOF(bmpfileheader)); + MEMZERO(bmpcoreheader, SIZEOF(bmpcoreheader)); + + /* Fill the file header */ + bmpfileheader[0] = 0x42; /* first 2 bytes are ASCII 'B', 'M' */ + bmpfileheader[1] = 0x4D; + PUT_4B(bmpfileheader, 2, bfSize); /* bfSize */ + /* we leave bfReserved1 & bfReserved2 = 0 */ + PUT_4B(bmpfileheader, 10, headersize); /* bfOffBits */ + + /* Fill the info header (Microsoft calls this a BITMAPCOREHEADER) */ + PUT_2B(bmpcoreheader, 0, 12); /* bcSize */ + PUT_2B(bmpcoreheader, 4, cinfo->output_width); /* bcWidth */ + PUT_2B(bmpcoreheader, 6, cinfo->output_height); /* bcHeight */ + PUT_2B(bmpcoreheader, 8, 1); /* bcPlanes - must be 1 */ + PUT_2B(bmpcoreheader, 10, bits_per_pixel); /* bcBitCount */ + + if (JFWRITE(dest->pub.output_file, bmpfileheader, 14) != (size_t) 14) + ERREXIT(cinfo, JERR_FILE_WRITE); + if (JFWRITE(dest->pub.output_file, bmpcoreheader, 12) != (size_t) 12) + ERREXIT(cinfo, JERR_FILE_WRITE); + + if (cmap_entries > 0) + write_colormap(cinfo, dest, cmap_entries, 3); +} + + +/* + * Write the colormap. + * Windows uses BGR0 map entries; OS/2 uses BGR entries. + */ + +LOCAL(void) +write_colormap (j_decompress_ptr cinfo, bmp_dest_ptr dest, + int map_colors, int map_entry_size) +{ + JSAMPARRAY colormap = cinfo->colormap; + int num_colors = cinfo->actual_number_of_colors; + FILE * outfile = dest->pub.output_file; + int i; + + if (colormap != NULL) { + if (cinfo->out_color_components == 3) { + /* Normal case with RGB colormap */ + for (i = 0; i < num_colors; i++) { + putc(GETJSAMPLE(colormap[2][i]), outfile); + putc(GETJSAMPLE(colormap[1][i]), outfile); + putc(GETJSAMPLE(colormap[0][i]), outfile); + if (map_entry_size == 4) + putc(0, outfile); + } + } else { + /* Grayscale colormap (only happens with grayscale quantization) */ + for (i = 0; i < num_colors; i++) { + putc(GETJSAMPLE(colormap[0][i]), outfile); + putc(GETJSAMPLE(colormap[0][i]), outfile); + putc(GETJSAMPLE(colormap[0][i]), outfile); + if (map_entry_size == 4) + putc(0, outfile); + } + } + } else { + /* If no colormap, must be grayscale data. Generate a linear "map". */ + for (i = 0; i < 256; i++) { + putc(i, outfile); + putc(i, outfile); + putc(i, outfile); + if (map_entry_size == 4) + putc(0, outfile); + } + } + /* Pad colormap with zeros to ensure specified number of colormap entries */ + if (i > map_colors) + ERREXIT1(cinfo, JERR_TOO_MANY_COLORS, i); + for (; i < map_colors; i++) { + putc(0, outfile); + putc(0, outfile); + putc(0, outfile); + if (map_entry_size == 4) + putc(0, outfile); + } +} + + +METHODDEF(void) +finish_output_bmp (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo) +{ + bmp_dest_ptr dest = (bmp_dest_ptr) dinfo; + register FILE * outfile = dest->pub.output_file; + JSAMPARRAY image_ptr; + register JSAMPROW data_ptr; + JDIMENSION row; + register JDIMENSION col; + cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress; + + /* Write the header and colormap */ + if (dest->is_os2) + write_os2_header(cinfo, dest); + else + write_bmp_header(cinfo, dest); + + /* Write the file body from our virtual array */ + for (row = cinfo->output_height; row > 0; row--) { + if (progress != NULL) { + progress->pub.pass_counter = (long) (cinfo->output_height - row); + progress->pub.pass_limit = (long) cinfo->output_height; + (*progress->pub.progress_monitor) ((j_common_ptr) cinfo); + } + image_ptr = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, dest->whole_image, row-1, (JDIMENSION) 1, FALSE); + data_ptr = image_ptr[0]; + for (col = dest->row_width; col > 0; col--) { + putc(GETJSAMPLE(*data_ptr), outfile); + data_ptr++; + } + } + if (progress != NULL) + progress->completed_extra_passes++; + + /* Make sure we wrote the output file OK */ + fflush(outfile); + if (ferror(outfile)) + ERREXIT(cinfo, JERR_FILE_WRITE); +} + + +/* + * The module selection routine for BMP format output. + */ + +GLOBAL(djpeg_dest_ptr) +jinit_write_bmp (j_decompress_ptr cinfo, boolean is_os2) +{ + bmp_dest_ptr dest; + JDIMENSION row_width; + + /* Create module interface object, fill in method pointers */ + dest = (bmp_dest_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(bmp_dest_struct)); + dest->pub.start_output = start_output_bmp; + dest->pub.finish_output = finish_output_bmp; + dest->is_os2 = is_os2; + + if (cinfo->out_color_space == JCS_GRAYSCALE) { + dest->pub.put_pixel_rows = put_gray_rows; + } else if (cinfo->out_color_space == JCS_RGB) { + if (cinfo->quantize_colors) + dest->pub.put_pixel_rows = put_gray_rows; + else + dest->pub.put_pixel_rows = put_pixel_rows; + } else { + ERREXIT(cinfo, JERR_BMP_COLORSPACE); + } + + /* Calculate output image dimensions so we can allocate space */ + jpeg_calc_output_dimensions(cinfo); + + /* Determine width of rows in the BMP file (padded to 4-byte boundary). */ + row_width = cinfo->output_width * cinfo->output_components; + dest->data_width = row_width; + while ((row_width & 3) != 0) row_width++; + dest->row_width = row_width; + dest->pad_bytes = (int) (row_width - dest->data_width); + + /* Allocate space for inversion array, prepare for write pass */ + dest->whole_image = (*cinfo->mem->request_virt_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, + row_width, cinfo->output_height, (JDIMENSION) 1); + dest->cur_output_row = 0; + if (cinfo->progress != NULL) { + cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress; + progress->total_extra_passes++; /* count file input as separate pass */ + } + + /* Create decompressor output buffer. */ + dest->pub.buffer = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, row_width, (JDIMENSION) 1); + dest->pub.buffer_height = 1; + + return (djpeg_dest_ptr) dest; +} + +#endif /* BMP_SUPPORTED */ diff --git a/mk4/modimage/jpeg-6b/wrgif.c b/mk4/modimage/jpeg-6b/wrgif.c new file mode 100644 index 0000000..5fe8328 --- /dev/null +++ b/mk4/modimage/jpeg-6b/wrgif.c @@ -0,0 +1,399 @@ +/* + * wrgif.c + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to write output images in GIF format. + * + ************************************************************************** + * NOTE: to avoid entanglements with Unisys' patent on LZW compression, * + * this code has been modified to output "uncompressed GIF" files. * + * There is no trace of the LZW algorithm in this file. * + ************************************************************************** + * + * These routines may need modification for non-Unix environments or + * specialized applications. As they stand, they assume output to + * an ordinary stdio stream. + */ + +/* + * This code is loosely based on ppmtogif from the PBMPLUS distribution + * of Feb. 1991. That file contains the following copyright notice: + * Based on GIFENCODE by David Rowley . + * Lempel-Ziv compression based on "compress" by Spencer W. Thomas et al. + * Copyright (C) 1989 by Jef Poskanzer. + * 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. This software is provided "as is" without express or + * implied warranty. + * + * We are also required to state that + * "The Graphics Interchange Format(c) is the Copyright property of + * CompuServe Incorporated. GIF(sm) is a Service Mark property of + * CompuServe Incorporated." + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ + +#ifdef GIF_SUPPORTED + + +/* Private version of data destination object */ + +typedef struct { + struct djpeg_dest_struct pub; /* public fields */ + + j_decompress_ptr cinfo; /* back link saves passing separate parm */ + + /* State for packing variable-width codes into a bitstream */ + int n_bits; /* current number of bits/code */ + int maxcode; /* maximum code, given n_bits */ + INT32 cur_accum; /* holds bits not yet output */ + int cur_bits; /* # of bits in cur_accum */ + + /* State for GIF code assignment */ + int ClearCode; /* clear code (doesn't change) */ + int EOFCode; /* EOF code (ditto) */ + int code_counter; /* counts output symbols */ + + /* GIF data packet construction buffer */ + int bytesinpkt; /* # of bytes in current packet */ + char packetbuf[256]; /* workspace for accumulating packet */ + +} gif_dest_struct; + +typedef gif_dest_struct * gif_dest_ptr; + +/* Largest value that will fit in N bits */ +#define MAXCODE(n_bits) ((1 << (n_bits)) - 1) + + +/* + * Routines to package finished data bytes into GIF data blocks. + * A data block consists of a count byte (1..255) and that many data bytes. + */ + +LOCAL(void) +flush_packet (gif_dest_ptr dinfo) +/* flush any accumulated data */ +{ + if (dinfo->bytesinpkt > 0) { /* never write zero-length packet */ + dinfo->packetbuf[0] = (char) dinfo->bytesinpkt++; + if (JFWRITE(dinfo->pub.output_file, dinfo->packetbuf, dinfo->bytesinpkt) + != (size_t) dinfo->bytesinpkt) + ERREXIT(dinfo->cinfo, JERR_FILE_WRITE); + dinfo->bytesinpkt = 0; + } +} + + +/* Add a character to current packet; flush to disk if necessary */ +#define CHAR_OUT(dinfo,c) \ + { (dinfo)->packetbuf[++(dinfo)->bytesinpkt] = (char) (c); \ + if ((dinfo)->bytesinpkt >= 255) \ + flush_packet(dinfo); \ + } + + +/* Routine to convert variable-width codes into a byte stream */ + +LOCAL(void) +output (gif_dest_ptr dinfo, int code) +/* Emit a code of n_bits bits */ +/* Uses cur_accum and cur_bits to reblock into 8-bit bytes */ +{ + dinfo->cur_accum |= ((INT32) code) << dinfo->cur_bits; + dinfo->cur_bits += dinfo->n_bits; + + while (dinfo->cur_bits >= 8) { + CHAR_OUT(dinfo, dinfo->cur_accum & 0xFF); + dinfo->cur_accum >>= 8; + dinfo->cur_bits -= 8; + } +} + + +/* The pseudo-compression algorithm. + * + * In this module we simply output each pixel value as a separate symbol; + * thus, no compression occurs. In fact, there is expansion of one bit per + * pixel, because we use a symbol width one bit wider than the pixel width. + * + * GIF ordinarily uses variable-width symbols, and the decoder will expect + * to ratchet up the symbol width after a fixed number of symbols. + * To simplify the logic and keep the expansion penalty down, we emit a + * GIF Clear code to reset the decoder just before the width would ratchet up. + * Thus, all the symbols in the output file will have the same bit width. + * Note that emitting the Clear codes at the right times is a mere matter of + * counting output symbols and is in no way dependent on the LZW patent. + * + * With a small basic pixel width (low color count), Clear codes will be + * needed very frequently, causing the file to expand even more. So this + * simplistic approach wouldn't work too well on bilevel images, for example. + * But for output of JPEG conversions the pixel width will usually be 8 bits + * (129 to 256 colors), so the overhead added by Clear symbols is only about + * one symbol in every 256. + */ + +LOCAL(void) +compress_init (gif_dest_ptr dinfo, int i_bits) +/* Initialize pseudo-compressor */ +{ + /* init all the state variables */ + dinfo->n_bits = i_bits; + dinfo->maxcode = MAXCODE(dinfo->n_bits); + dinfo->ClearCode = (1 << (i_bits - 1)); + dinfo->EOFCode = dinfo->ClearCode + 1; + dinfo->code_counter = dinfo->ClearCode + 2; + /* init output buffering vars */ + dinfo->bytesinpkt = 0; + dinfo->cur_accum = 0; + dinfo->cur_bits = 0; + /* GIF specifies an initial Clear code */ + output(dinfo, dinfo->ClearCode); +} + + +LOCAL(void) +compress_pixel (gif_dest_ptr dinfo, int c) +/* Accept and "compress" one pixel value. + * The given value must be less than n_bits wide. + */ +{ + /* Output the given pixel value as a symbol. */ + output(dinfo, c); + /* Issue Clear codes often enough to keep the reader from ratcheting up + * its symbol size. + */ + if (dinfo->code_counter < dinfo->maxcode) { + dinfo->code_counter++; + } else { + output(dinfo, dinfo->ClearCode); + dinfo->code_counter = dinfo->ClearCode + 2; /* reset the counter */ + } +} + + +LOCAL(void) +compress_term (gif_dest_ptr dinfo) +/* Clean up at end */ +{ + /* Send an EOF code */ + output(dinfo, dinfo->EOFCode); + /* Flush the bit-packing buffer */ + if (dinfo->cur_bits > 0) { + CHAR_OUT(dinfo, dinfo->cur_accum & 0xFF); + } + /* Flush the packet buffer */ + flush_packet(dinfo); +} + + +/* GIF header construction */ + + +LOCAL(void) +put_word (gif_dest_ptr dinfo, unsigned int w) +/* Emit a 16-bit word, LSB first */ +{ + putc(w & 0xFF, dinfo->pub.output_file); + putc((w >> 8) & 0xFF, dinfo->pub.output_file); +} + + +LOCAL(void) +put_3bytes (gif_dest_ptr dinfo, int val) +/* Emit 3 copies of same byte value --- handy subr for colormap construction */ +{ + putc(val, dinfo->pub.output_file); + putc(val, dinfo->pub.output_file); + putc(val, dinfo->pub.output_file); +} + + +LOCAL(void) +emit_header (gif_dest_ptr dinfo, int num_colors, JSAMPARRAY colormap) +/* Output the GIF file header, including color map */ +/* If colormap==NULL, synthesize a gray-scale colormap */ +{ + int BitsPerPixel, ColorMapSize, InitCodeSize, FlagByte; + int cshift = dinfo->cinfo->data_precision - 8; + int i; + + if (num_colors > 256) + ERREXIT1(dinfo->cinfo, JERR_TOO_MANY_COLORS, num_colors); + /* Compute bits/pixel and related values */ + BitsPerPixel = 1; + while (num_colors > (1 << BitsPerPixel)) + BitsPerPixel++; + ColorMapSize = 1 << BitsPerPixel; + if (BitsPerPixel <= 1) + InitCodeSize = 2; + else + InitCodeSize = BitsPerPixel; + /* + * Write the GIF header. + * Note that we generate a plain GIF87 header for maximum compatibility. + */ + putc('G', dinfo->pub.output_file); + putc('I', dinfo->pub.output_file); + putc('F', dinfo->pub.output_file); + putc('8', dinfo->pub.output_file); + putc('7', dinfo->pub.output_file); + putc('a', dinfo->pub.output_file); + /* Write the Logical Screen Descriptor */ + put_word(dinfo, (unsigned int) dinfo->cinfo->output_width); + put_word(dinfo, (unsigned int) dinfo->cinfo->output_height); + FlagByte = 0x80; /* Yes, there is a global color table */ + FlagByte |= (BitsPerPixel-1) << 4; /* color resolution */ + FlagByte |= (BitsPerPixel-1); /* size of global color table */ + putc(FlagByte, dinfo->pub.output_file); + putc(0, dinfo->pub.output_file); /* Background color index */ + putc(0, dinfo->pub.output_file); /* Reserved (aspect ratio in GIF89) */ + /* Write the Global Color Map */ + /* If the color map is more than 8 bits precision, */ + /* we reduce it to 8 bits by shifting */ + for (i=0; i < ColorMapSize; i++) { + if (i < num_colors) { + if (colormap != NULL) { + if (dinfo->cinfo->out_color_space == JCS_RGB) { + /* Normal case: RGB color map */ + putc(GETJSAMPLE(colormap[0][i]) >> cshift, dinfo->pub.output_file); + putc(GETJSAMPLE(colormap[1][i]) >> cshift, dinfo->pub.output_file); + putc(GETJSAMPLE(colormap[2][i]) >> cshift, dinfo->pub.output_file); + } else { + /* Grayscale "color map": possible if quantizing grayscale image */ + put_3bytes(dinfo, GETJSAMPLE(colormap[0][i]) >> cshift); + } + } else { + /* Create a gray-scale map of num_colors values, range 0..255 */ + put_3bytes(dinfo, (i * 255 + (num_colors-1)/2) / (num_colors-1)); + } + } else { + /* fill out the map to a power of 2 */ + put_3bytes(dinfo, 0); + } + } + /* Write image separator and Image Descriptor */ + putc(',', dinfo->pub.output_file); /* separator */ + put_word(dinfo, 0); /* left/top offset */ + put_word(dinfo, 0); + put_word(dinfo, (unsigned int) dinfo->cinfo->output_width); /* image size */ + put_word(dinfo, (unsigned int) dinfo->cinfo->output_height); + /* flag byte: not interlaced, no local color map */ + putc(0x00, dinfo->pub.output_file); + /* Write Initial Code Size byte */ + putc(InitCodeSize, dinfo->pub.output_file); + + /* Initialize for "compression" of image data */ + compress_init(dinfo, InitCodeSize+1); +} + + +/* + * Startup: write the file header. + */ + +METHODDEF(void) +start_output_gif (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo) +{ + gif_dest_ptr dest = (gif_dest_ptr) dinfo; + + if (cinfo->quantize_colors) + emit_header(dest, cinfo->actual_number_of_colors, cinfo->colormap); + else + emit_header(dest, 256, (JSAMPARRAY) NULL); +} + + +/* + * Write some pixel data. + * In this module rows_supplied will always be 1. + */ + +METHODDEF(void) +put_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied) +{ + gif_dest_ptr dest = (gif_dest_ptr) dinfo; + register JSAMPROW ptr; + register JDIMENSION col; + + ptr = dest->pub.buffer[0]; + for (col = cinfo->output_width; col > 0; col--) { + compress_pixel(dest, GETJSAMPLE(*ptr++)); + } +} + + +/* + * Finish up at the end of the file. + */ + +METHODDEF(void) +finish_output_gif (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo) +{ + gif_dest_ptr dest = (gif_dest_ptr) dinfo; + + /* Flush "compression" mechanism */ + compress_term(dest); + /* Write a zero-length data block to end the series */ + putc(0, dest->pub.output_file); + /* Write the GIF terminator mark */ + putc(';', dest->pub.output_file); + /* Make sure we wrote the output file OK */ + fflush(dest->pub.output_file); + if (ferror(dest->pub.output_file)) + ERREXIT(cinfo, JERR_FILE_WRITE); +} + + +/* + * The module selection routine for GIF format output. + */ + +GLOBAL(djpeg_dest_ptr) +jinit_write_gif (j_decompress_ptr cinfo) +{ + gif_dest_ptr dest; + + /* Create module interface object, fill in method pointers */ + dest = (gif_dest_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(gif_dest_struct)); + dest->cinfo = cinfo; /* make back link for subroutines */ + dest->pub.start_output = start_output_gif; + dest->pub.put_pixel_rows = put_pixel_rows; + dest->pub.finish_output = finish_output_gif; + + if (cinfo->out_color_space != JCS_GRAYSCALE && + cinfo->out_color_space != JCS_RGB) + ERREXIT(cinfo, JERR_GIF_COLORSPACE); + + /* Force quantization if color or if > 8 bits input */ + if (cinfo->out_color_space != JCS_GRAYSCALE || cinfo->data_precision > 8) { + /* Force quantization to at most 256 colors */ + cinfo->quantize_colors = TRUE; + if (cinfo->desired_number_of_colors > 256) + cinfo->desired_number_of_colors = 256; + } + + /* Calculate output image dimensions so we can allocate space */ + jpeg_calc_output_dimensions(cinfo); + + if (cinfo->output_components != 1) /* safety check: just one component? */ + ERREXIT(cinfo, JERR_GIF_BUG); + + /* Create decompressor output buffer. */ + dest->pub.buffer = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, cinfo->output_width, (JDIMENSION) 1); + dest->pub.buffer_height = 1; + + return (djpeg_dest_ptr) dest; +} + +#endif /* GIF_SUPPORTED */ diff --git a/mk4/modimage/jpeg-6b/wrjpgcom.1 b/mk4/modimage/jpeg-6b/wrjpgcom.1 new file mode 100644 index 0000000..d419a99 --- /dev/null +++ b/mk4/modimage/jpeg-6b/wrjpgcom.1 @@ -0,0 +1,103 @@ +.TH WRJPGCOM 1 "15 June 1995" +.SH NAME +wrjpgcom \- insert text comments into a JPEG file +.SH SYNOPSIS +.B wrjpgcom +[ +.B \-replace +] +[ +.BI \-comment " text" +] +[ +.BI \-cfile " name" +] +[ +.I filename +] +.LP +.SH DESCRIPTION +.LP +.B wrjpgcom +reads the named JPEG/JFIF file, or the standard input if no file is named, +and generates a new JPEG/JFIF file on standard output. A comment block is +added to the file. +.PP +The JPEG standard allows "comment" (COM) blocks to occur within a JPEG file. +Although the standard doesn't actually define what COM blocks are for, they +are widely used to hold user-supplied text strings. This lets you add +annotations, titles, index terms, etc to your JPEG files, and later retrieve +them as text. COM blocks do not interfere with the image stored in the JPEG +file. The maximum size of a COM block is 64K, but you can have as many of +them as you like in one JPEG file. +.PP +.B wrjpgcom +adds a COM block, containing text you provide, to a JPEG file. +Ordinarily, the COM block is added after any existing COM blocks; but you +can delete the old COM blocks if you wish. +.SH OPTIONS +Switch names may be abbreviated, and are not case sensitive. +.TP +.B \-replace +Delete any existing COM blocks from the file. +.TP +.BI \-comment " text" +Supply text for new COM block on command line. +.TP +.BI \-cfile " name" +Read text for new COM block from named file. +.PP +If you have only one line of comment text to add, you can provide it on the +command line with +.BR \-comment . +The comment text must be surrounded with quotes so that it is treated as a +single argument. Longer comments can be read from a text file. +.PP +If you give neither +.B \-comment +nor +.BR \-cfile , +then +.B wrjpgcom +will read the comment text from standard input. (In this case an input image +file name MUST be supplied, so that the source JPEG file comes from somewhere +else.) You can enter multiple lines, up to 64KB worth. Type an end-of-file +indicator (usually control-D) to terminate the comment text entry. +.PP +.B wrjpgcom +will not add a COM block if the provided comment string is empty. Therefore +\fB\-replace \-comment ""\fR can be used to delete all COM blocks from a file. +.SH EXAMPLES +.LP +Add a short comment to in.jpg, producing out.jpg: +.IP +.B wrjpgcom \-c +\fI"View of my back yard" in.jpg +.B > +.I out.jpg +.PP +Attach a long comment previously stored in comment.txt: +.IP +.B wrjpgcom +.I in.jpg +.B < +.I comment.txt +.B > +.I out.jpg +.PP +or equivalently +.IP +.B wrjpgcom +.B -cfile +.I comment.txt +.B < +.I in.jpg +.B > +.I out.jpg +.SH SEE ALSO +.BR cjpeg (1), +.BR djpeg (1), +.BR jpegtran (1), +.BR rdjpgcom (1) +.SH AUTHOR +Independent JPEG Group diff --git a/mk4/modimage/jpeg-6b/wrjpgcom.c b/mk4/modimage/jpeg-6b/wrjpgcom.c new file mode 100644 index 0000000..8c04b05 --- /dev/null +++ b/mk4/modimage/jpeg-6b/wrjpgcom.c @@ -0,0 +1,583 @@ +/* + * wrjpgcom.c + * + * Copyright (C) 1994-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a very simple stand-alone application that inserts + * user-supplied text as a COM (comment) marker in a JFIF file. + * This may be useful as an example of the minimum logic needed to parse + * JPEG markers. + */ + +#define JPEG_CJPEG_DJPEG /* to get the command-line config symbols */ +#include "jinclude.h" /* get auto-config symbols, */ + +#ifndef HAVE_STDLIB_H /* should declare malloc() */ +extern void * malloc (); +#endif +#include /* to declare isupper(), tolower() */ +#ifdef USE_SETMODE +#include /* to declare setmode()'s parameter macros */ +/* If you have setmode() but not , just delete this line: */ +#include /* to declare setmode() */ +#endif + +#ifdef USE_CCOMMAND /* command-line reader for Macintosh */ +#ifdef __MWERKS__ +#include /* Metrowerks needs this */ +#include /* ... and this */ +#endif +#ifdef THINK_C +#include /* Think declares it here */ +#endif +#endif + +#ifdef DONT_USE_B_MODE /* define mode parameters for fopen() */ +#define READ_BINARY "r" +#define WRITE_BINARY "w" +#else +#ifdef VMS /* VMS is very nonstandard */ +#define READ_BINARY "rb", "ctx=stm" +#define WRITE_BINARY "wb", "ctx=stm" +#else /* standard ANSI-compliant case */ +#define READ_BINARY "rb" +#define WRITE_BINARY "wb" +#endif +#endif + +#ifndef EXIT_FAILURE /* define exit() codes if not provided */ +#define EXIT_FAILURE 1 +#endif +#ifndef EXIT_SUCCESS +#ifdef VMS +#define EXIT_SUCCESS 1 /* VMS is very nonstandard */ +#else +#define EXIT_SUCCESS 0 +#endif +#endif + +/* Reduce this value if your malloc() can't allocate blocks up to 64K. + * On DOS, compiling in large model is usually a better solution. + */ + +#ifndef MAX_COM_LENGTH +#define MAX_COM_LENGTH 65000L /* must be <= 65533 in any case */ +#endif + + +/* + * These macros are used to read the input file and write the output file. + * To reuse this code in another application, you might need to change these. + */ + +static FILE * infile; /* input JPEG file */ + +/* Return next input byte, or EOF if no more */ +#define NEXTBYTE() getc(infile) + +static FILE * outfile; /* output JPEG file */ + +/* Emit an output byte */ +#define PUTBYTE(x) putc((x), outfile) + + +/* Error exit handler */ +#define ERREXIT(msg) (fprintf(stderr, "%s\n", msg), exit(EXIT_FAILURE)) + + +/* Read one byte, testing for EOF */ +static int +read_1_byte (void) +{ + int c; + + c = NEXTBYTE(); + if (c == EOF) + ERREXIT("Premature EOF in JPEG file"); + return c; +} + +/* Read 2 bytes, convert to unsigned int */ +/* All 2-byte quantities in JPEG markers are MSB first */ +static unsigned int +read_2_bytes (void) +{ + int c1, c2; + + c1 = NEXTBYTE(); + if (c1 == EOF) + ERREXIT("Premature EOF in JPEG file"); + c2 = NEXTBYTE(); + if (c2 == EOF) + ERREXIT("Premature EOF in JPEG file"); + return (((unsigned int) c1) << 8) + ((unsigned int) c2); +} + + +/* Routines to write data to output file */ + +static void +write_1_byte (int c) +{ + PUTBYTE(c); +} + +static void +write_2_bytes (unsigned int val) +{ + PUTBYTE((val >> 8) & 0xFF); + PUTBYTE(val & 0xFF); +} + +static void +write_marker (int marker) +{ + PUTBYTE(0xFF); + PUTBYTE(marker); +} + +static void +copy_rest_of_file (void) +{ + int c; + + while ((c = NEXTBYTE()) != EOF) + PUTBYTE(c); +} + + +/* + * JPEG markers consist of one or more 0xFF bytes, followed by a marker + * code byte (which is not an FF). Here are the marker codes of interest + * in this program. (See jdmarker.c for a more complete list.) + */ + +#define M_SOF0 0xC0 /* Start Of Frame N */ +#define M_SOF1 0xC1 /* N indicates which compression process */ +#define M_SOF2 0xC2 /* Only SOF0-SOF2 are now in common use */ +#define M_SOF3 0xC3 +#define M_SOF5 0xC5 /* NB: codes C4 and CC are NOT SOF markers */ +#define M_SOF6 0xC6 +#define M_SOF7 0xC7 +#define M_SOF9 0xC9 +#define M_SOF10 0xCA +#define M_SOF11 0xCB +#define M_SOF13 0xCD +#define M_SOF14 0xCE +#define M_SOF15 0xCF +#define M_SOI 0xD8 /* Start Of Image (beginning of datastream) */ +#define M_EOI 0xD9 /* End Of Image (end of datastream) */ +#define M_SOS 0xDA /* Start Of Scan (begins compressed data) */ +#define M_COM 0xFE /* COMment */ + + +/* + * Find the next JPEG marker and return its marker code. + * We expect at least one FF byte, possibly more if the compressor used FFs + * to pad the file. (Padding FFs will NOT be replicated in the output file.) + * There could also be non-FF garbage between markers. The treatment of such + * garbage is unspecified; we choose to skip over it but emit a warning msg. + * NB: this routine must not be used after seeing SOS marker, since it will + * not deal correctly with FF/00 sequences in the compressed image data... + */ + +static int +next_marker (void) +{ + int c; + int discarded_bytes = 0; + + /* Find 0xFF byte; count and skip any non-FFs. */ + c = read_1_byte(); + while (c != 0xFF) { + discarded_bytes++; + c = read_1_byte(); + } + /* Get marker code byte, swallowing any duplicate FF bytes. Extra FFs + * are legal as pad bytes, so don't count them in discarded_bytes. + */ + do { + c = read_1_byte(); + } while (c == 0xFF); + + if (discarded_bytes != 0) { + fprintf(stderr, "Warning: garbage data found in JPEG file\n"); + } + + return c; +} + + +/* + * Read the initial marker, which should be SOI. + * For a JFIF file, the first two bytes of the file should be literally + * 0xFF M_SOI. To be more general, we could use next_marker, but if the + * input file weren't actually JPEG at all, next_marker might read the whole + * file and then return a misleading error message... + */ + +static int +first_marker (void) +{ + int c1, c2; + + c1 = NEXTBYTE(); + c2 = NEXTBYTE(); + if (c1 != 0xFF || c2 != M_SOI) + ERREXIT("Not a JPEG file"); + return c2; +} + + +/* + * Most types of marker are followed by a variable-length parameter segment. + * This routine skips over the parameters for any marker we don't otherwise + * want to process. + * Note that we MUST skip the parameter segment explicitly in order not to + * be fooled by 0xFF bytes that might appear within the parameter segment; + * such bytes do NOT introduce new markers. + */ + +static void +copy_variable (void) +/* Copy an unknown or uninteresting variable-length marker */ +{ + unsigned int length; + + /* Get the marker parameter length count */ + length = read_2_bytes(); + write_2_bytes(length); + /* Length includes itself, so must be at least 2 */ + if (length < 2) + ERREXIT("Erroneous JPEG marker length"); + length -= 2; + /* Skip over the remaining bytes */ + while (length > 0) { + write_1_byte(read_1_byte()); + length--; + } +} + +static void +skip_variable (void) +/* Skip over an unknown or uninteresting variable-length marker */ +{ + unsigned int length; + + /* Get the marker parameter length count */ + length = read_2_bytes(); + /* Length includes itself, so must be at least 2 */ + if (length < 2) + ERREXIT("Erroneous JPEG marker length"); + length -= 2; + /* Skip over the remaining bytes */ + while (length > 0) { + (void) read_1_byte(); + length--; + } +} + + +/* + * Parse the marker stream until SOFn or EOI is seen; + * copy data to output, but discard COM markers unless keep_COM is true. + */ + +static int +scan_JPEG_header (int keep_COM) +{ + int marker; + + /* Expect SOI at start of file */ + if (first_marker() != M_SOI) + ERREXIT("Expected SOI marker first"); + write_marker(M_SOI); + + /* Scan miscellaneous markers until we reach SOFn. */ + for (;;) { + marker = next_marker(); + switch (marker) { + /* Note that marker codes 0xC4, 0xC8, 0xCC are not, and must not be, + * treated as SOFn. C4 in particular is actually DHT. + */ + case M_SOF0: /* Baseline */ + case M_SOF1: /* Extended sequential, Huffman */ + case M_SOF2: /* Progressive, Huffman */ + case M_SOF3: /* Lossless, Huffman */ + case M_SOF5: /* Differential sequential, Huffman */ + case M_SOF6: /* Differential progressive, Huffman */ + case M_SOF7: /* Differential lossless, Huffman */ + case M_SOF9: /* Extended sequential, arithmetic */ + case M_SOF10: /* Progressive, arithmetic */ + case M_SOF11: /* Lossless, arithmetic */ + case M_SOF13: /* Differential sequential, arithmetic */ + case M_SOF14: /* Differential progressive, arithmetic */ + case M_SOF15: /* Differential lossless, arithmetic */ + return marker; + + case M_SOS: /* should not see compressed data before SOF */ + ERREXIT("SOS without prior SOFn"); + break; + + case M_EOI: /* in case it's a tables-only JPEG stream */ + return marker; + + case M_COM: /* Existing COM: conditionally discard */ + if (keep_COM) { + write_marker(marker); + copy_variable(); + } else { + skip_variable(); + } + break; + + default: /* Anything else just gets copied */ + write_marker(marker); + copy_variable(); /* we assume it has a parameter count... */ + break; + } + } /* end loop */ +} + + +/* Command line parsing code */ + +static const char * progname; /* program name for error messages */ + + +static void +usage (void) +/* complain about bad command line */ +{ + fprintf(stderr, "wrjpgcom inserts a textual comment in a JPEG file.\n"); + fprintf(stderr, "You can add to or replace any existing comment(s).\n"); + + fprintf(stderr, "Usage: %s [switches] ", progname); +#ifdef TWO_FILE_COMMANDLINE + fprintf(stderr, "inputfile outputfile\n"); +#else + fprintf(stderr, "[inputfile]\n"); +#endif + + fprintf(stderr, "Switches (names may be abbreviated):\n"); + fprintf(stderr, " -replace Delete any existing comments\n"); + fprintf(stderr, " -comment \"text\" Insert comment with given text\n"); + fprintf(stderr, " -cfile name Read comment from named file\n"); + fprintf(stderr, "Notice that you must put quotes around the comment text\n"); + fprintf(stderr, "when you use -comment.\n"); + fprintf(stderr, "If you do not give either -comment or -cfile on the command line,\n"); + fprintf(stderr, "then the comment text is read from standard input.\n"); + fprintf(stderr, "It can be multiple lines, up to %u characters total.\n", + (unsigned int) MAX_COM_LENGTH); +#ifndef TWO_FILE_COMMANDLINE + fprintf(stderr, "You must specify an input JPEG file name when supplying\n"); + fprintf(stderr, "comment text from standard input.\n"); +#endif + + exit(EXIT_FAILURE); +} + + +static int +keymatch (char * arg, const char * keyword, int minchars) +/* Case-insensitive matching of (possibly abbreviated) keyword switches. */ +/* keyword is the constant keyword (must be lower case already), */ +/* minchars is length of minimum legal abbreviation. */ +{ + register int ca, ck; + register int nmatched = 0; + + while ((ca = *arg++) != '\0') { + if ((ck = *keyword++) == '\0') + return 0; /* arg longer than keyword, no good */ + if (isupper(ca)) /* force arg to lcase (assume ck is already) */ + ca = tolower(ca); + if (ca != ck) + return 0; /* no good */ + nmatched++; /* count matched characters */ + } + /* reached end of argument; fail if it's too short for unique abbrev */ + if (nmatched < minchars) + return 0; + return 1; /* A-OK */ +} + + +/* + * The main program. + */ + +int +main (int argc, char **argv) +{ + int argn; + char * arg; + int keep_COM = 1; + char * comment_arg = NULL; + FILE * comment_file = NULL; + unsigned int comment_length = 0; + int marker; + + /* On Mac, fetch a command line. */ +#ifdef USE_CCOMMAND + argc = ccommand(&argv); +#endif + + progname = argv[0]; + if (progname == NULL || progname[0] == 0) + progname = "wrjpgcom"; /* in case C library doesn't provide it */ + + /* Parse switches, if any */ + for (argn = 1; argn < argc; argn++) { + arg = argv[argn]; + if (arg[0] != '-') + break; /* not switch, must be file name */ + arg++; /* advance over '-' */ + if (keymatch(arg, "replace", 1)) { + keep_COM = 0; + } else if (keymatch(arg, "cfile", 2)) { + if (++argn >= argc) usage(); + if ((comment_file = fopen(argv[argn], "r")) == NULL) { + fprintf(stderr, "%s: can't open %s\n", progname, argv[argn]); + exit(EXIT_FAILURE); + } + } else if (keymatch(arg, "comment", 1)) { + if (++argn >= argc) usage(); + comment_arg = argv[argn]; + /* If the comment text starts with '"', then we are probably running + * under MS-DOG and must parse out the quoted string ourselves. Sigh. + */ + if (comment_arg[0] == '"') { + comment_arg = (char *) malloc((size_t) MAX_COM_LENGTH); + if (comment_arg == NULL) + ERREXIT("Insufficient memory"); + strcpy(comment_arg, argv[argn]+1); + for (;;) { + comment_length = (unsigned int) strlen(comment_arg); + if (comment_length > 0 && comment_arg[comment_length-1] == '"') { + comment_arg[comment_length-1] = '\0'; /* zap terminating quote */ + break; + } + if (++argn >= argc) + ERREXIT("Missing ending quote mark"); + strcat(comment_arg, " "); + strcat(comment_arg, argv[argn]); + } + } + comment_length = (unsigned int) strlen(comment_arg); + } else + usage(); + } + + /* Cannot use both -comment and -cfile. */ + if (comment_arg != NULL && comment_file != NULL) + usage(); + /* If there is neither -comment nor -cfile, we will read the comment text + * from stdin; in this case there MUST be an input JPEG file name. + */ + if (comment_arg == NULL && comment_file == NULL && argn >= argc) + usage(); + + /* Open the input file. */ + if (argn < argc) { + if ((infile = fopen(argv[argn], READ_BINARY)) == NULL) { + fprintf(stderr, "%s: can't open %s\n", progname, argv[argn]); + exit(EXIT_FAILURE); + } + } else { + /* default input file is stdin */ +#ifdef USE_SETMODE /* need to hack file mode? */ + setmode(fileno(stdin), O_BINARY); +#endif +#ifdef USE_FDOPEN /* need to re-open in binary mode? */ + if ((infile = fdopen(fileno(stdin), READ_BINARY)) == NULL) { + fprintf(stderr, "%s: can't open stdin\n", progname); + exit(EXIT_FAILURE); + } +#else + infile = stdin; +#endif + } + + /* Open the output file. */ +#ifdef TWO_FILE_COMMANDLINE + /* Must have explicit output file name */ + if (argn != argc-2) { + fprintf(stderr, "%s: must name one input and one output file\n", + progname); + usage(); + } + if ((outfile = fopen(argv[argn+1], WRITE_BINARY)) == NULL) { + fprintf(stderr, "%s: can't open %s\n", progname, argv[argn+1]); + exit(EXIT_FAILURE); + } +#else + /* Unix style: expect zero or one file name */ + if (argn < argc-1) { + fprintf(stderr, "%s: only one input file\n", progname); + usage(); + } + /* default output file is stdout */ +#ifdef USE_SETMODE /* need to hack file mode? */ + setmode(fileno(stdout), O_BINARY); +#endif +#ifdef USE_FDOPEN /* need to re-open in binary mode? */ + if ((outfile = fdopen(fileno(stdout), WRITE_BINARY)) == NULL) { + fprintf(stderr, "%s: can't open stdout\n", progname); + exit(EXIT_FAILURE); + } +#else + outfile = stdout; +#endif +#endif /* TWO_FILE_COMMANDLINE */ + + /* Collect comment text from comment_file or stdin, if necessary */ + if (comment_arg == NULL) { + FILE * src_file; + int c; + + comment_arg = (char *) malloc((size_t) MAX_COM_LENGTH); + if (comment_arg == NULL) + ERREXIT("Insufficient memory"); + comment_length = 0; + src_file = (comment_file != NULL ? comment_file : stdin); + while ((c = getc(src_file)) != EOF) { + if (comment_length >= (unsigned int) MAX_COM_LENGTH) { + fprintf(stderr, "Comment text may not exceed %u bytes\n", + (unsigned int) MAX_COM_LENGTH); + exit(EXIT_FAILURE); + } + comment_arg[comment_length++] = (char) c; + } + if (comment_file != NULL) + fclose(comment_file); + } + + /* Copy JPEG headers until SOFn marker; + * we will insert the new comment marker just before SOFn. + * This (a) causes the new comment to appear after, rather than before, + * existing comments; and (b) ensures that comments come after any JFIF + * or JFXX markers, as required by the JFIF specification. + */ + marker = scan_JPEG_header(keep_COM); + /* Insert the new COM marker, but only if nonempty text has been supplied */ + if (comment_length > 0) { + write_marker(M_COM); + write_2_bytes(comment_length + 2); + while (comment_length > 0) { + write_1_byte(*comment_arg++); + comment_length--; + } + } + /* Duplicate the remainder of the source file. + * Note that any COM markers occuring after SOF will not be touched. + */ + write_marker(marker); + copy_rest_of_file(); + + /* All done. */ + exit(EXIT_SUCCESS); + return 0; /* suppress no-return-value warnings */ +} diff --git a/mk4/modimage/jpeg-6b/wrppm.c b/mk4/modimage/jpeg-6b/wrppm.c new file mode 100644 index 0000000..6c6d908 --- /dev/null +++ b/mk4/modimage/jpeg-6b/wrppm.c @@ -0,0 +1,268 @@ +/* + * wrppm.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to write output images in PPM/PGM format. + * The extended 2-byte-per-sample raw PPM/PGM formats are supported. + * The PBMPLUS library is NOT required to compile this software + * (but it is highly useful as a set of PPM image manipulation programs). + * + * These routines may need modification for non-Unix environments or + * specialized applications. As they stand, they assume output to + * an ordinary stdio stream. + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ + +#ifdef PPM_SUPPORTED + + +/* + * For 12-bit JPEG data, we either downscale the values to 8 bits + * (to write standard byte-per-sample PPM/PGM files), or output + * nonstandard word-per-sample PPM/PGM files. Downscaling is done + * if PPM_NORAWWORD is defined (this can be done in the Makefile + * or in jconfig.h). + * (When the core library supports data precision reduction, a cleaner + * implementation will be to ask for that instead.) + */ + +#if BITS_IN_JSAMPLE == 8 +#define PUTPPMSAMPLE(ptr,v) *ptr++ = (char) (v) +#define BYTESPERSAMPLE 1 +#define PPM_MAXVAL 255 +#else +#ifdef PPM_NORAWWORD +#define PUTPPMSAMPLE(ptr,v) *ptr++ = (char) ((v) >> (BITS_IN_JSAMPLE-8)) +#define BYTESPERSAMPLE 1 +#define PPM_MAXVAL 255 +#else +/* The word-per-sample format always puts the LSB first. */ +#define PUTPPMSAMPLE(ptr,v) \ + { register int val_ = v; \ + *ptr++ = (char) (val_ & 0xFF); \ + *ptr++ = (char) ((val_ >> 8) & 0xFF); \ + } +#define BYTESPERSAMPLE 2 +#define PPM_MAXVAL ((1<pub.output_file, dest->iobuffer, dest->buffer_width); +} + + +/* + * This code is used when we have to copy the data and apply a pixel + * format translation. Typically this only happens in 12-bit mode. + */ + +METHODDEF(void) +copy_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied) +{ + ppm_dest_ptr dest = (ppm_dest_ptr) dinfo; + register char * bufferptr; + register JSAMPROW ptr; + register JDIMENSION col; + + ptr = dest->pub.buffer[0]; + bufferptr = dest->iobuffer; + for (col = dest->samples_per_row; col > 0; col--) { + PUTPPMSAMPLE(bufferptr, GETJSAMPLE(*ptr++)); + } + (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width); +} + + +/* + * Write some pixel data when color quantization is in effect. + * We have to demap the color index values to straight data. + */ + +METHODDEF(void) +put_demapped_rgb (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied) +{ + ppm_dest_ptr dest = (ppm_dest_ptr) dinfo; + register char * bufferptr; + register int pixval; + register JSAMPROW ptr; + register JSAMPROW color_map0 = cinfo->colormap[0]; + register JSAMPROW color_map1 = cinfo->colormap[1]; + register JSAMPROW color_map2 = cinfo->colormap[2]; + register JDIMENSION col; + + ptr = dest->pub.buffer[0]; + bufferptr = dest->iobuffer; + for (col = cinfo->output_width; col > 0; col--) { + pixval = GETJSAMPLE(*ptr++); + PUTPPMSAMPLE(bufferptr, GETJSAMPLE(color_map0[pixval])); + PUTPPMSAMPLE(bufferptr, GETJSAMPLE(color_map1[pixval])); + PUTPPMSAMPLE(bufferptr, GETJSAMPLE(color_map2[pixval])); + } + (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width); +} + + +METHODDEF(void) +put_demapped_gray (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied) +{ + ppm_dest_ptr dest = (ppm_dest_ptr) dinfo; + register char * bufferptr; + register JSAMPROW ptr; + register JSAMPROW color_map = cinfo->colormap[0]; + register JDIMENSION col; + + ptr = dest->pub.buffer[0]; + bufferptr = dest->iobuffer; + for (col = cinfo->output_width; col > 0; col--) { + PUTPPMSAMPLE(bufferptr, GETJSAMPLE(color_map[GETJSAMPLE(*ptr++)])); + } + (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width); +} + + +/* + * Startup: write the file header. + */ + +METHODDEF(void) +start_output_ppm (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo) +{ + ppm_dest_ptr dest = (ppm_dest_ptr) dinfo; + + /* Emit file header */ + switch (cinfo->out_color_space) { + case JCS_GRAYSCALE: + /* emit header for raw PGM format */ + fprintf(dest->pub.output_file, "P5\n%ld %ld\n%d\n", + (long) cinfo->output_width, (long) cinfo->output_height, + PPM_MAXVAL); + break; + case JCS_RGB: + /* emit header for raw PPM format */ + fprintf(dest->pub.output_file, "P6\n%ld %ld\n%d\n", + (long) cinfo->output_width, (long) cinfo->output_height, + PPM_MAXVAL); + break; + default: + ERREXIT(cinfo, JERR_PPM_COLORSPACE); + } +} + + +/* + * Finish up at the end of the file. + */ + +METHODDEF(void) +finish_output_ppm (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo) +{ + /* Make sure we wrote the output file OK */ + fflush(dinfo->output_file); + if (ferror(dinfo->output_file)) + ERREXIT(cinfo, JERR_FILE_WRITE); +} + + +/* + * The module selection routine for PPM format output. + */ + +GLOBAL(djpeg_dest_ptr) +jinit_write_ppm (j_decompress_ptr cinfo) +{ + ppm_dest_ptr dest; + + /* Create module interface object, fill in method pointers */ + dest = (ppm_dest_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(ppm_dest_struct)); + dest->pub.start_output = start_output_ppm; + dest->pub.finish_output = finish_output_ppm; + + /* Calculate output image dimensions so we can allocate space */ + jpeg_calc_output_dimensions(cinfo); + + /* Create physical I/O buffer. Note we make this near on a PC. */ + dest->samples_per_row = cinfo->output_width * cinfo->out_color_components; + dest->buffer_width = dest->samples_per_row * (BYTESPERSAMPLE * SIZEOF(char)); + dest->iobuffer = (char *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, dest->buffer_width); + + if (cinfo->quantize_colors || BITS_IN_JSAMPLE != 8 || + SIZEOF(JSAMPLE) != SIZEOF(char)) { + /* When quantizing, we need an output buffer for colormap indexes + * that's separate from the physical I/O buffer. We also need a + * separate buffer if pixel format translation must take place. + */ + dest->pub.buffer = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + cinfo->output_width * cinfo->output_components, (JDIMENSION) 1); + dest->pub.buffer_height = 1; + if (! cinfo->quantize_colors) + dest->pub.put_pixel_rows = copy_pixel_rows; + else if (cinfo->out_color_space == JCS_GRAYSCALE) + dest->pub.put_pixel_rows = put_demapped_gray; + else + dest->pub.put_pixel_rows = put_demapped_rgb; + } else { + /* We will fwrite() directly from decompressor output buffer. */ + /* Synthesize a JSAMPARRAY pointer structure */ + /* Cast here implies near->far pointer conversion on PCs */ + dest->pixrow = (JSAMPROW) dest->iobuffer; + dest->pub.buffer = & dest->pixrow; + dest->pub.buffer_height = 1; + dest->pub.put_pixel_rows = put_pixel_rows; + } + + return (djpeg_dest_ptr) dest; +} + +#endif /* PPM_SUPPORTED */ diff --git a/mk4/modimage/jpeg-6b/wrrle.c b/mk4/modimage/jpeg-6b/wrrle.c new file mode 100644 index 0000000..a4e7337 --- /dev/null +++ b/mk4/modimage/jpeg-6b/wrrle.c @@ -0,0 +1,305 @@ +/* + * wrrle.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to write output images in RLE format. + * The Utah Raster Toolkit library is required (version 3.1 or later). + * + * These routines may need modification for non-Unix environments or + * specialized applications. As they stand, they assume output to + * an ordinary stdio stream. + * + * Based on code contributed by Mike Lijewski, + * with updates from Robert Hutchinson. + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ + +#ifdef RLE_SUPPORTED + +/* rle.h is provided by the Utah Raster Toolkit. */ + +#include + +/* + * We assume that JSAMPLE has the same representation as rle_pixel, + * to wit, "unsigned char". Hence we can't cope with 12- or 16-bit samples. + */ + +#if BITS_IN_JSAMPLE != 8 + Sorry, this code only copes with 8-bit JSAMPLEs. /* deliberate syntax err */ +#endif + + +/* + * Since RLE stores scanlines bottom-to-top, we have to invert the image + * from JPEG's top-to-bottom order. To do this, we save the outgoing data + * in a virtual array during put_pixel_row calls, then actually emit the + * RLE file during finish_output. + */ + + +/* + * For now, if we emit an RLE color map then it is always 256 entries long, + * though not all of the entries need be used. + */ + +#define CMAPBITS 8 +#define CMAPLENGTH (1<<(CMAPBITS)) + +typedef struct { + struct djpeg_dest_struct pub; /* public fields */ + + jvirt_sarray_ptr image; /* virtual array to store the output image */ + rle_map *colormap; /* RLE-style color map, or NULL if none */ + rle_pixel **rle_row; /* To pass rows to rle_putrow() */ + +} rle_dest_struct; + +typedef rle_dest_struct * rle_dest_ptr; + +/* Forward declarations */ +METHODDEF(void) rle_put_pixel_rows + JPP((j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied)); + + +/* + * Write the file header. + * + * In this module it's easier to wait till finish_output to write anything. + */ + +METHODDEF(void) +start_output_rle (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo) +{ + rle_dest_ptr dest = (rle_dest_ptr) dinfo; + size_t cmapsize; + int i, ci; +#ifdef PROGRESS_REPORT + cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress; +#endif + + /* + * Make sure the image can be stored in RLE format. + * + * - RLE stores image dimensions as *signed* 16 bit integers. JPEG + * uses unsigned, so we have to check the width. + * + * - Colorspace is expected to be grayscale or RGB. + * + * - The number of channels (components) is expected to be 1 (grayscale/ + * pseudocolor) or 3 (truecolor/directcolor). + * (could be 2 or 4 if using an alpha channel, but we aren't) + */ + + if (cinfo->output_width > 32767 || cinfo->output_height > 32767) + ERREXIT2(cinfo, JERR_RLE_DIMENSIONS, cinfo->output_width, + cinfo->output_height); + + if (cinfo->out_color_space != JCS_GRAYSCALE && + cinfo->out_color_space != JCS_RGB) + ERREXIT(cinfo, JERR_RLE_COLORSPACE); + + if (cinfo->output_components != 1 && cinfo->output_components != 3) + ERREXIT1(cinfo, JERR_RLE_TOOMANYCHANNELS, cinfo->num_components); + + /* Convert colormap, if any, to RLE format. */ + + dest->colormap = NULL; + + if (cinfo->quantize_colors) { + /* Allocate storage for RLE-style cmap, zero any extra entries */ + cmapsize = cinfo->out_color_components * CMAPLENGTH * SIZEOF(rle_map); + dest->colormap = (rle_map *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, cmapsize); + MEMZERO(dest->colormap, cmapsize); + + /* Save away data in RLE format --- note 8-bit left shift! */ + /* Shifting would need adjustment for JSAMPLEs wider than 8 bits. */ + for (ci = 0; ci < cinfo->out_color_components; ci++) { + for (i = 0; i < cinfo->actual_number_of_colors; i++) { + dest->colormap[ci * CMAPLENGTH + i] = + GETJSAMPLE(cinfo->colormap[ci][i]) << 8; + } + } + } + + /* Set the output buffer to the first row */ + dest->pub.buffer = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, dest->image, (JDIMENSION) 0, (JDIMENSION) 1, TRUE); + dest->pub.buffer_height = 1; + + dest->pub.put_pixel_rows = rle_put_pixel_rows; + +#ifdef PROGRESS_REPORT + if (progress != NULL) { + progress->total_extra_passes++; /* count file writing as separate pass */ + } +#endif +} + + +/* + * Write some pixel data. + * + * This routine just saves the data away in a virtual array. + */ + +METHODDEF(void) +rle_put_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied) +{ + rle_dest_ptr dest = (rle_dest_ptr) dinfo; + + if (cinfo->output_scanline < cinfo->output_height) { + dest->pub.buffer = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, dest->image, + cinfo->output_scanline, (JDIMENSION) 1, TRUE); + } +} + +/* + * Finish up at the end of the file. + * + * Here is where we really output the RLE file. + */ + +METHODDEF(void) +finish_output_rle (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo) +{ + rle_dest_ptr dest = (rle_dest_ptr) dinfo; + rle_hdr header; /* Output file information */ + rle_pixel **rle_row, *red, *green, *blue; + JSAMPROW output_row; + char cmapcomment[80]; + int row, col; + int ci; +#ifdef PROGRESS_REPORT + cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress; +#endif + + /* Initialize the header info */ + header = *rle_hdr_init(NULL); + header.rle_file = dest->pub.output_file; + header.xmin = 0; + header.xmax = cinfo->output_width - 1; + header.ymin = 0; + header.ymax = cinfo->output_height - 1; + header.alpha = 0; + header.ncolors = cinfo->output_components; + for (ci = 0; ci < cinfo->output_components; ci++) { + RLE_SET_BIT(header, ci); + } + if (cinfo->quantize_colors) { + header.ncmap = cinfo->out_color_components; + header.cmaplen = CMAPBITS; + header.cmap = dest->colormap; + /* Add a comment to the output image with the true colormap length. */ + sprintf(cmapcomment, "color_map_length=%d", cinfo->actual_number_of_colors); + rle_putcom(cmapcomment, &header); + } + + /* Emit the RLE header and color map (if any) */ + rle_put_setup(&header); + + /* Now output the RLE data from our virtual array. + * We assume here that (a) rle_pixel is represented the same as JSAMPLE, + * and (b) we are not on a machine where FAR pointers differ from regular. + */ + +#ifdef PROGRESS_REPORT + if (progress != NULL) { + progress->pub.pass_limit = cinfo->output_height; + progress->pub.pass_counter = 0; + (*progress->pub.progress_monitor) ((j_common_ptr) cinfo); + } +#endif + + if (cinfo->output_components == 1) { + for (row = cinfo->output_height-1; row >= 0; row--) { + rle_row = (rle_pixel **) (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, dest->image, + (JDIMENSION) row, (JDIMENSION) 1, FALSE); + rle_putrow(rle_row, (int) cinfo->output_width, &header); +#ifdef PROGRESS_REPORT + if (progress != NULL) { + progress->pub.pass_counter++; + (*progress->pub.progress_monitor) ((j_common_ptr) cinfo); + } +#endif + } + } else { + for (row = cinfo->output_height-1; row >= 0; row--) { + rle_row = (rle_pixel **) dest->rle_row; + output_row = * (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, dest->image, + (JDIMENSION) row, (JDIMENSION) 1, FALSE); + red = rle_row[0]; + green = rle_row[1]; + blue = rle_row[2]; + for (col = cinfo->output_width; col > 0; col--) { + *red++ = GETJSAMPLE(*output_row++); + *green++ = GETJSAMPLE(*output_row++); + *blue++ = GETJSAMPLE(*output_row++); + } + rle_putrow(rle_row, (int) cinfo->output_width, &header); +#ifdef PROGRESS_REPORT + if (progress != NULL) { + progress->pub.pass_counter++; + (*progress->pub.progress_monitor) ((j_common_ptr) cinfo); + } +#endif + } + } + +#ifdef PROGRESS_REPORT + if (progress != NULL) + progress->completed_extra_passes++; +#endif + + /* Emit file trailer */ + rle_puteof(&header); + fflush(dest->pub.output_file); + if (ferror(dest->pub.output_file)) + ERREXIT(cinfo, JERR_FILE_WRITE); +} + + +/* + * The module selection routine for RLE format output. + */ + +GLOBAL(djpeg_dest_ptr) +jinit_write_rle (j_decompress_ptr cinfo) +{ + rle_dest_ptr dest; + + /* Create module interface object, fill in method pointers */ + dest = (rle_dest_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(rle_dest_struct)); + dest->pub.start_output = start_output_rle; + dest->pub.finish_output = finish_output_rle; + + /* Calculate output image dimensions so we can allocate space */ + jpeg_calc_output_dimensions(cinfo); + + /* Allocate a work array for output to the RLE library. */ + dest->rle_row = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + cinfo->output_width, (JDIMENSION) cinfo->output_components); + + /* Allocate a virtual array to hold the image. */ + dest->image = (*cinfo->mem->request_virt_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, + (JDIMENSION) (cinfo->output_width * cinfo->output_components), + cinfo->output_height, (JDIMENSION) 1); + + return (djpeg_dest_ptr) dest; +} + +#endif /* RLE_SUPPORTED */ diff --git a/mk4/modimage/jpeg-6b/wrtarga.c b/mk4/modimage/jpeg-6b/wrtarga.c new file mode 100644 index 0000000..cf104d2 --- /dev/null +++ b/mk4/modimage/jpeg-6b/wrtarga.c @@ -0,0 +1,253 @@ +/* + * wrtarga.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to write output images in Targa format. + * + * These routines may need modification for non-Unix environments or + * specialized applications. As they stand, they assume output to + * an ordinary stdio stream. + * + * Based on code contributed by Lee Daniel Crocker. + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ + +#ifdef TARGA_SUPPORTED + + +/* + * To support 12-bit JPEG data, we'd have to scale output down to 8 bits. + * This is not yet implemented. + */ + +#if BITS_IN_JSAMPLE != 8 + Sorry, this code only copes with 8-bit JSAMPLEs. /* deliberate syntax err */ +#endif + +/* + * The output buffer needs to be writable by fwrite(). On PCs, we must + * allocate the buffer in near data space, because we are assuming small-data + * memory model, wherein fwrite() can't reach far memory. If you need to + * process very wide images on a PC, you might have to compile in large-memory + * model, or else replace fwrite() with a putc() loop --- which will be much + * slower. + */ + + +/* Private version of data destination object */ + +typedef struct { + struct djpeg_dest_struct pub; /* public fields */ + + char *iobuffer; /* physical I/O buffer */ + JDIMENSION buffer_width; /* width of one row */ +} tga_dest_struct; + +typedef tga_dest_struct * tga_dest_ptr; + + +LOCAL(void) +write_header (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, int num_colors) +/* Create and write a Targa header */ +{ + char targaheader[18]; + + /* Set unused fields of header to 0 */ + MEMZERO(targaheader, SIZEOF(targaheader)); + + if (num_colors > 0) { + targaheader[1] = 1; /* color map type 1 */ + targaheader[5] = (char) (num_colors & 0xFF); + targaheader[6] = (char) (num_colors >> 8); + targaheader[7] = 24; /* 24 bits per cmap entry */ + } + + targaheader[12] = (char) (cinfo->output_width & 0xFF); + targaheader[13] = (char) (cinfo->output_width >> 8); + targaheader[14] = (char) (cinfo->output_height & 0xFF); + targaheader[15] = (char) (cinfo->output_height >> 8); + targaheader[17] = 0x20; /* Top-down, non-interlaced */ + + if (cinfo->out_color_space == JCS_GRAYSCALE) { + targaheader[2] = 3; /* image type = uncompressed gray-scale */ + targaheader[16] = 8; /* bits per pixel */ + } else { /* must be RGB */ + if (num_colors > 0) { + targaheader[2] = 1; /* image type = colormapped RGB */ + targaheader[16] = 8; + } else { + targaheader[2] = 2; /* image type = uncompressed RGB */ + targaheader[16] = 24; + } + } + + if (JFWRITE(dinfo->output_file, targaheader, 18) != (size_t) 18) + ERREXIT(cinfo, JERR_FILE_WRITE); +} + + +/* + * Write some pixel data. + * In this module rows_supplied will always be 1. + */ + +METHODDEF(void) +put_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied) +/* used for unquantized full-color output */ +{ + tga_dest_ptr dest = (tga_dest_ptr) dinfo; + register JSAMPROW inptr; + register char * outptr; + register JDIMENSION col; + + inptr = dest->pub.buffer[0]; + outptr = dest->iobuffer; + for (col = cinfo->output_width; col > 0; col--) { + outptr[0] = (char) GETJSAMPLE(inptr[2]); /* RGB to BGR order */ + outptr[1] = (char) GETJSAMPLE(inptr[1]); + outptr[2] = (char) GETJSAMPLE(inptr[0]); + inptr += 3, outptr += 3; + } + (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width); +} + +METHODDEF(void) +put_gray_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied) +/* used for grayscale OR quantized color output */ +{ + tga_dest_ptr dest = (tga_dest_ptr) dinfo; + register JSAMPROW inptr; + register char * outptr; + register JDIMENSION col; + + inptr = dest->pub.buffer[0]; + outptr = dest->iobuffer; + for (col = cinfo->output_width; col > 0; col--) { + *outptr++ = (char) GETJSAMPLE(*inptr++); + } + (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width); +} + + +/* + * Write some demapped pixel data when color quantization is in effect. + * For Targa, this is only applied to grayscale data. + */ + +METHODDEF(void) +put_demapped_gray (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied) +{ + tga_dest_ptr dest = (tga_dest_ptr) dinfo; + register JSAMPROW inptr; + register char * outptr; + register JSAMPROW color_map0 = cinfo->colormap[0]; + register JDIMENSION col; + + inptr = dest->pub.buffer[0]; + outptr = dest->iobuffer; + for (col = cinfo->output_width; col > 0; col--) { + *outptr++ = (char) GETJSAMPLE(color_map0[GETJSAMPLE(*inptr++)]); + } + (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width); +} + + +/* + * Startup: write the file header. + */ + +METHODDEF(void) +start_output_tga (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo) +{ + tga_dest_ptr dest = (tga_dest_ptr) dinfo; + int num_colors, i; + FILE *outfile; + + if (cinfo->out_color_space == JCS_GRAYSCALE) { + /* Targa doesn't have a mapped grayscale format, so we will */ + /* demap quantized gray output. Never emit a colormap. */ + write_header(cinfo, dinfo, 0); + if (cinfo->quantize_colors) + dest->pub.put_pixel_rows = put_demapped_gray; + else + dest->pub.put_pixel_rows = put_gray_rows; + } else if (cinfo->out_color_space == JCS_RGB) { + if (cinfo->quantize_colors) { + /* We only support 8-bit colormap indexes, so only 256 colors */ + num_colors = cinfo->actual_number_of_colors; + if (num_colors > 256) + ERREXIT1(cinfo, JERR_TOO_MANY_COLORS, num_colors); + write_header(cinfo, dinfo, num_colors); + /* Write the colormap. Note Targa uses BGR byte order */ + outfile = dest->pub.output_file; + for (i = 0; i < num_colors; i++) { + putc(GETJSAMPLE(cinfo->colormap[2][i]), outfile); + putc(GETJSAMPLE(cinfo->colormap[1][i]), outfile); + putc(GETJSAMPLE(cinfo->colormap[0][i]), outfile); + } + dest->pub.put_pixel_rows = put_gray_rows; + } else { + write_header(cinfo, dinfo, 0); + dest->pub.put_pixel_rows = put_pixel_rows; + } + } else { + ERREXIT(cinfo, JERR_TGA_COLORSPACE); + } +} + + +/* + * Finish up at the end of the file. + */ + +METHODDEF(void) +finish_output_tga (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo) +{ + /* Make sure we wrote the output file OK */ + fflush(dinfo->output_file); + if (ferror(dinfo->output_file)) + ERREXIT(cinfo, JERR_FILE_WRITE); +} + + +/* + * The module selection routine for Targa format output. + */ + +GLOBAL(djpeg_dest_ptr) +jinit_write_targa (j_decompress_ptr cinfo) +{ + tga_dest_ptr dest; + + /* Create module interface object, fill in method pointers */ + dest = (tga_dest_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(tga_dest_struct)); + dest->pub.start_output = start_output_tga; + dest->pub.finish_output = finish_output_tga; + + /* Calculate output image dimensions so we can allocate space */ + jpeg_calc_output_dimensions(cinfo); + + /* Create I/O buffer. Note we make this near on a PC. */ + dest->buffer_width = cinfo->output_width * cinfo->output_components; + dest->iobuffer = (char *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (size_t) (dest->buffer_width * SIZEOF(char))); + + /* Create decompressor output buffer. */ + dest->pub.buffer = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, dest->buffer_width, (JDIMENSION) 1); + dest->pub.buffer_height = 1; + + return (djpeg_dest_ptr) dest; +} + +#endif /* TARGA_SUPPORTED */ diff --git a/mk4/modimage/jpegint.h b/mk4/modimage/jpegint.h new file mode 100644 index 0000000..95b00d4 --- /dev/null +++ b/mk4/modimage/jpegint.h @@ -0,0 +1,392 @@ +/* + * jpegint.h + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file provides common declarations for the various JPEG modules. + * These declarations are considered internal to the JPEG library; most + * applications using the library shouldn't need to include this file. + */ + + +/* Declarations for both compression & decompression */ + +typedef enum { /* Operating modes for buffer controllers */ + JBUF_PASS_THRU, /* Plain stripwise operation */ + /* Remaining modes require a full-image buffer to have been created */ + JBUF_SAVE_SOURCE, /* Run source subobject only, save output */ + JBUF_CRANK_DEST, /* Run dest subobject only, using saved data */ + JBUF_SAVE_AND_PASS /* Run both subobjects, save output */ +} J_BUF_MODE; + +/* Values of global_state field (jdapi.c has some dependencies on ordering!) */ +#define CSTATE_START 100 /* after create_compress */ +#define CSTATE_SCANNING 101 /* start_compress done, write_scanlines OK */ +#define CSTATE_RAW_OK 102 /* start_compress done, write_raw_data OK */ +#define CSTATE_WRCOEFS 103 /* jpeg_write_coefficients done */ +#define DSTATE_START 200 /* after create_decompress */ +#define DSTATE_INHEADER 201 /* reading header markers, no SOS yet */ +#define DSTATE_READY 202 /* found SOS, ready for start_decompress */ +#define DSTATE_PRELOAD 203 /* reading multiscan file in start_decompress*/ +#define DSTATE_PRESCAN 204 /* performing dummy pass for 2-pass quant */ +#define DSTATE_SCANNING 205 /* start_decompress done, read_scanlines OK */ +#define DSTATE_RAW_OK 206 /* start_decompress done, read_raw_data OK */ +#define DSTATE_BUFIMAGE 207 /* expecting jpeg_start_output */ +#define DSTATE_BUFPOST 208 /* looking for SOS/EOI in jpeg_finish_output */ +#define DSTATE_RDCOEFS 209 /* reading file in jpeg_read_coefficients */ +#define DSTATE_STOPPING 210 /* looking for EOI in jpeg_finish_decompress */ + + +/* Declarations for compression modules */ + +/* Master control module */ +struct jpeg_comp_master { + JMETHOD(void, prepare_for_pass, (j_compress_ptr cinfo)); + JMETHOD(void, pass_startup, (j_compress_ptr cinfo)); + JMETHOD(void, finish_pass, (j_compress_ptr cinfo)); + + /* State variables made visible to other modules */ + boolean call_pass_startup; /* True if pass_startup must be called */ + boolean is_last_pass; /* True during last pass */ +}; + +/* Main buffer control (downsampled-data buffer) */ +struct jpeg_c_main_controller { + JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(void, process_data, (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail)); +}; + +/* Compression preprocessing (downsampling input buffer control) */ +struct jpeg_c_prep_controller { + JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(void, pre_process_data, (j_compress_ptr cinfo, + JSAMPARRAY input_buf, + JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail, + JSAMPIMAGE output_buf, + JDIMENSION *out_row_group_ctr, + JDIMENSION out_row_groups_avail)); +}; + +/* Coefficient buffer control */ +struct jpeg_c_coef_controller { + JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(boolean, compress_data, (j_compress_ptr cinfo, + JSAMPIMAGE input_buf)); +}; + +/* Colorspace conversion */ +struct jpeg_color_converter { + JMETHOD(void, start_pass, (j_compress_ptr cinfo)); + JMETHOD(void, color_convert, (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows)); +}; + +/* Downsampling */ +struct jpeg_downsampler { + JMETHOD(void, start_pass, (j_compress_ptr cinfo)); + JMETHOD(void, downsample, (j_compress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION in_row_index, + JSAMPIMAGE output_buf, + JDIMENSION out_row_group_index)); + + boolean need_context_rows; /* TRUE if need rows above & below */ +}; + +/* Forward DCT (also controls coefficient quantization) */ +struct jpeg_forward_dct { + JMETHOD(void, start_pass, (j_compress_ptr cinfo)); + /* perhaps this should be an array??? */ + JMETHOD(void, forward_DCT, (j_compress_ptr cinfo, + jpeg_component_info * compptr, + JSAMPARRAY sample_data, JBLOCKROW coef_blocks, + JDIMENSION start_row, JDIMENSION start_col, + JDIMENSION num_blocks)); +}; + +/* Entropy encoding */ +struct jpeg_entropy_encoder { + JMETHOD(void, start_pass, (j_compress_ptr cinfo, boolean gather_statistics)); + JMETHOD(boolean, encode_mcu, (j_compress_ptr cinfo, JBLOCKROW *MCU_data)); + JMETHOD(void, finish_pass, (j_compress_ptr cinfo)); +}; + +/* Marker writing */ +struct jpeg_marker_writer { + JMETHOD(void, write_file_header, (j_compress_ptr cinfo)); + JMETHOD(void, write_frame_header, (j_compress_ptr cinfo)); + JMETHOD(void, write_scan_header, (j_compress_ptr cinfo)); + JMETHOD(void, write_file_trailer, (j_compress_ptr cinfo)); + JMETHOD(void, write_tables_only, (j_compress_ptr cinfo)); + /* These routines are exported to allow insertion of extra markers */ + /* Probably only COM and APPn markers should be written this way */ + JMETHOD(void, write_marker_header, (j_compress_ptr cinfo, int marker, + unsigned int datalen)); + JMETHOD(void, write_marker_byte, (j_compress_ptr cinfo, int val)); +}; + + +/* Declarations for decompression modules */ + +/* Master control module */ +struct jpeg_decomp_master { + JMETHOD(void, prepare_for_output_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, finish_output_pass, (j_decompress_ptr cinfo)); + + /* State variables made visible to other modules */ + boolean is_dummy_pass; /* True during 1st pass for 2-pass quant */ +}; + +/* Input control module */ +struct jpeg_input_controller { + JMETHOD(int, consume_input, (j_decompress_ptr cinfo)); + JMETHOD(void, reset_input_controller, (j_decompress_ptr cinfo)); + JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, finish_input_pass, (j_decompress_ptr cinfo)); + + /* State variables made visible to other modules */ + boolean has_multiple_scans; /* True if file has multiple scans */ + boolean eoi_reached; /* True when EOI has been consumed */ +}; + +/* Main buffer control (downsampled-data buffer) */ +struct jpeg_d_main_controller { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(void, process_data, (j_decompress_ptr cinfo, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); +}; + +/* Coefficient buffer control */ +struct jpeg_d_coef_controller { + JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo)); + JMETHOD(int, consume_data, (j_decompress_ptr cinfo)); + JMETHOD(void, start_output_pass, (j_decompress_ptr cinfo)); + JMETHOD(int, decompress_data, (j_decompress_ptr cinfo, + JSAMPIMAGE output_buf)); + /* Pointer to array of coefficient virtual arrays, or NULL if none */ + jvirt_barray_ptr *coef_arrays; +}; + +/* Decompression postprocessing (color quantization buffer control) */ +struct jpeg_d_post_controller { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(void, post_process_data, (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, + JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, + JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); +}; + +/* Marker reading & parsing */ +struct jpeg_marker_reader { + JMETHOD(void, reset_marker_reader, (j_decompress_ptr cinfo)); + /* Read markers until SOS or EOI. + * Returns same codes as are defined for jpeg_consume_input: + * JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI. + */ + JMETHOD(int, read_markers, (j_decompress_ptr cinfo)); + /* Read a restart marker --- exported for use by entropy decoder only */ + jpeg_marker_parser_method read_restart_marker; + + /* State of marker reader --- nominally internal, but applications + * supplying COM or APPn handlers might like to know the state. + */ + boolean saw_SOI; /* found SOI? */ + boolean saw_SOF; /* found SOF? */ + int next_restart_num; /* next restart number expected (0-7) */ + unsigned int discarded_bytes; /* # of bytes skipped looking for a marker */ +}; + +/* Entropy decoding */ +struct jpeg_entropy_decoder { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + JMETHOD(boolean, decode_mcu, (j_decompress_ptr cinfo, + JBLOCKROW *MCU_data)); + + /* This is here to share code between baseline and progressive decoders; */ + /* other modules probably should not use it */ + boolean insufficient_data; /* set TRUE after emitting warning */ +}; + +/* Inverse DCT (also performs dequantization) */ +typedef JMETHOD(void, inverse_DCT_method_ptr, + (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col)); + +struct jpeg_inverse_dct { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + /* It is useful to allow each component to have a separate IDCT method. */ + inverse_DCT_method_ptr inverse_DCT[MAX_COMPONENTS]; +}; + +/* Upsampling (note that upsampler must also call color converter) */ +struct jpeg_upsampler { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, upsample, (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, + JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, + JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); + + boolean need_context_rows; /* TRUE if need rows above & below */ +}; + +/* Colorspace conversion */ +struct jpeg_color_deconverter { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, color_convert, (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows)); +}; + +/* Color quantization or color precision reduction */ +struct jpeg_color_quantizer { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo, boolean is_pre_scan)); + JMETHOD(void, color_quantize, (j_decompress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPARRAY output_buf, + int num_rows)); + JMETHOD(void, finish_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, new_color_map, (j_decompress_ptr cinfo)); +}; + + +/* Miscellaneous useful macros */ + +#undef MAX +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#undef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) + + +/* We assume that right shift corresponds to signed division by 2 with + * rounding towards minus infinity. This is correct for typical "arithmetic + * shift" instructions that shift in copies of the sign bit. But some + * C compilers implement >> with an unsigned shift. For these machines you + * must define RIGHT_SHIFT_IS_UNSIGNED. + * RIGHT_SHIFT provides a proper signed right shift of an INT32 quantity. + * It is only applied with constant shift counts. SHIFT_TEMPS must be + * included in the variables of any routine using RIGHT_SHIFT. + */ + +#ifdef RIGHT_SHIFT_IS_UNSIGNED +#define SHIFT_TEMPS INT32 shift_temp; +#define RIGHT_SHIFT(x,shft) \ + ((shift_temp = (x)) < 0 ? \ + (shift_temp >> (shft)) | ((~((INT32) 0)) << (32-(shft))) : \ + (shift_temp >> (shft))) +#else +#define SHIFT_TEMPS +#define RIGHT_SHIFT(x,shft) ((x) >> (shft)) +#endif + + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jinit_compress_master jICompress +#define jinit_c_master_control jICMaster +#define jinit_c_main_controller jICMainC +#define jinit_c_prep_controller jICPrepC +#define jinit_c_coef_controller jICCoefC +#define jinit_color_converter jICColor +#define jinit_downsampler jIDownsampler +#define jinit_forward_dct jIFDCT +#define jinit_huff_encoder jIHEncoder +#define jinit_phuff_encoder jIPHEncoder +#define jinit_marker_writer jIMWriter +#define jinit_master_decompress jIDMaster +#define jinit_d_main_controller jIDMainC +#define jinit_d_coef_controller jIDCoefC +#define jinit_d_post_controller jIDPostC +#define jinit_input_controller jIInCtlr +#define jinit_marker_reader jIMReader +#define jinit_huff_decoder jIHDecoder +#define jinit_phuff_decoder jIPHDecoder +#define jinit_inverse_dct jIIDCT +#define jinit_upsampler jIUpsampler +#define jinit_color_deconverter jIDColor +#define jinit_1pass_quantizer jI1Quant +#define jinit_2pass_quantizer jI2Quant +#define jinit_merged_upsampler jIMUpsampler +#define jinit_memory_mgr jIMemMgr +#define jdiv_round_up jDivRound +#define jround_up jRound +#define jcopy_sample_rows jCopySamples +#define jcopy_block_row jCopyBlocks +#define jzero_far jZeroFar +#define jpeg_zigzag_order jZIGTable +#define jpeg_natural_order jZAGTable +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* Compression module initialization routines */ +EXTERN(void) jinit_compress_master JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_c_master_control JPP((j_compress_ptr cinfo, + boolean transcode_only)); +EXTERN(void) jinit_c_main_controller JPP((j_compress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_c_prep_controller JPP((j_compress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_c_coef_controller JPP((j_compress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_color_converter JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_downsampler JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_forward_dct JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_huff_encoder JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_phuff_encoder JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_marker_writer JPP((j_compress_ptr cinfo)); +/* Decompression module initialization routines */ +EXTERN(void) jinit_master_decompress JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_d_main_controller JPP((j_decompress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_d_coef_controller JPP((j_decompress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_d_post_controller JPP((j_decompress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_input_controller JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_marker_reader JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_huff_decoder JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_phuff_decoder JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_inverse_dct JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_upsampler JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_color_deconverter JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_1pass_quantizer JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_2pass_quantizer JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_merged_upsampler JPP((j_decompress_ptr cinfo)); +/* Memory manager initialization */ +EXTERN(void) jinit_memory_mgr JPP((j_common_ptr cinfo)); + +/* Utility routines in jutils.c */ +EXTERN(long) jdiv_round_up JPP((long a, long b)); +EXTERN(long) jround_up JPP((long a, long b)); +EXTERN(void) jcopy_sample_rows JPP((JSAMPARRAY input_array, int source_row, + JSAMPARRAY output_array, int dest_row, + int num_rows, JDIMENSION num_cols)); +EXTERN(void) jcopy_block_row JPP((JBLOCKROW input_row, JBLOCKROW output_row, + JDIMENSION num_blocks)); +EXTERN(void) jzero_far JPP((void FAR * target, size_t bytestozero)); +/* Constant tables in jutils.c */ +#if 0 /* This table is not actually needed in v6a */ +extern const int jpeg_zigzag_order[]; /* natural coef order to zigzag order */ +#endif +extern const int jpeg_natural_order[]; /* zigzag coef order to natural order */ + +/* Suppress undefined-structure complaints if necessary. */ + +#ifdef INCOMPLETE_TYPES_BROKEN +#ifndef AM_MEMORY_MANAGER /* only jmemmgr.c defines these */ +struct jvirt_sarray_control { long dummy; }; +struct jvirt_barray_control { long dummy; }; +#endif +#endif /* INCOMPLETE_TYPES_BROKEN */ diff --git a/mk4/modimage/jpeglib.h b/mk4/modimage/jpeglib.h new file mode 100644 index 0000000..d1be8dd --- /dev/null +++ b/mk4/modimage/jpeglib.h @@ -0,0 +1,1096 @@ +/* + * jpeglib.h + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file defines the application interface for the JPEG library. + * Most applications using the library need only include this file, + * and perhaps jerror.h if they want to know the exact error codes. + */ + +#ifndef JPEGLIB_H +#define JPEGLIB_H + +/* + * First we include the configuration files that record how this + * installation of the JPEG library is set up. jconfig.h can be + * generated automatically for many systems. jmorecfg.h contains + * manual configuration options that most people need not worry about. + */ + +#ifndef JCONFIG_INCLUDED /* in case jinclude.h already did */ +#include "jconfig.h" /* widely used configuration options */ +#endif +#include "jmorecfg.h" /* seldom changed options */ + + +/* Version ID for the JPEG library. + * Might be useful for tests like "#if JPEG_LIB_VERSION >= 60". + */ + +#define JPEG_LIB_VERSION 62 /* Version 6b */ + + +/* Various constants determining the sizes of things. + * All of these are specified by the JPEG standard, so don't change them + * if you want to be compatible. + */ + +#define DCTSIZE 8 /* The basic DCT block is 8x8 samples */ +#define DCTSIZE2 64 /* DCTSIZE squared; # of elements in a block */ +#define NUM_QUANT_TBLS 4 /* Quantization tables are numbered 0..3 */ +#define NUM_HUFF_TBLS 4 /* Huffman tables are numbered 0..3 */ +#define NUM_ARITH_TBLS 16 /* Arith-coding tables are numbered 0..15 */ +#define MAX_COMPS_IN_SCAN 4 /* JPEG limit on # of components in one scan */ +#define MAX_SAMP_FACTOR 4 /* JPEG limit on sampling factors */ +/* Unfortunately, some bozo at Adobe saw no reason to be bound by the standard; + * the PostScript DCT filter can emit files with many more than 10 blocks/MCU. + * If you happen to run across such a file, you can up D_MAX_BLOCKS_IN_MCU + * to handle it. We even let you do this from the jconfig.h file. However, + * we strongly discourage changing C_MAX_BLOCKS_IN_MCU; just because Adobe + * sometimes emits noncompliant files doesn't mean you should too. + */ +#define C_MAX_BLOCKS_IN_MCU 10 /* compressor's limit on blocks per MCU */ +#ifndef D_MAX_BLOCKS_IN_MCU +#define D_MAX_BLOCKS_IN_MCU 10 /* decompressor's limit on blocks per MCU */ +#endif + + +/* Data structures for images (arrays of samples and of DCT coefficients). + * On 80x86 machines, the image arrays are too big for near pointers, + * but the pointer arrays can fit in near memory. + */ + +typedef JSAMPLE FAR *JSAMPROW; /* ptr to one image row of pixel samples. */ +typedef JSAMPROW *JSAMPARRAY; /* ptr to some rows (a 2-D sample array) */ +typedef JSAMPARRAY *JSAMPIMAGE; /* a 3-D sample array: top index is color */ + +typedef JCOEF JBLOCK[DCTSIZE2]; /* one block of coefficients */ +typedef JBLOCK FAR *JBLOCKROW; /* pointer to one row of coefficient blocks */ +typedef JBLOCKROW *JBLOCKARRAY; /* a 2-D array of coefficient blocks */ +typedef JBLOCKARRAY *JBLOCKIMAGE; /* a 3-D array of coefficient blocks */ + +typedef JCOEF FAR *JCOEFPTR; /* useful in a couple of places */ + + +/* Types for JPEG compression parameters and working tables. */ + + +/* DCT coefficient quantization tables. */ + +typedef struct { + /* This array gives the coefficient quantizers in natural array order + * (not the zigzag order in which they are stored in a JPEG DQT marker). + * CAUTION: IJG versions prior to v6a kept this array in zigzag order. + */ + UINT16 quantval[DCTSIZE2]; /* quantization step for each coefficient */ + /* This field is used only during compression. It's initialized FALSE when + * the table is created, and set TRUE when it's been output to the file. + * You could suppress output of a table by setting this to TRUE. + * (See jpeg_suppress_tables for an example.) + */ + boolean sent_table; /* TRUE when table has been output */ +} JQUANT_TBL; + + +/* Huffman coding tables. */ + +typedef struct { + /* These two fields directly represent the contents of a JPEG DHT marker */ + UINT8 bits[17]; /* bits[k] = # of symbols with codes of */ + /* length k bits; bits[0] is unused */ + UINT8 huffval[256]; /* The symbols, in order of incr code length */ + /* This field is used only during compression. It's initialized FALSE when + * the table is created, and set TRUE when it's been output to the file. + * You could suppress output of a table by setting this to TRUE. + * (See jpeg_suppress_tables for an example.) + */ + boolean sent_table; /* TRUE when table has been output */ +} JHUFF_TBL; + + +/* Basic info about one component (color channel). */ + +typedef struct { + /* These values are fixed over the whole image. */ + /* For compression, they must be supplied by parameter setup; */ + /* for decompression, they are read from the SOF marker. */ + int component_id; /* identifier for this component (0..255) */ + int component_index; /* its index in SOF or cinfo->comp_info[] */ + int h_samp_factor; /* horizontal sampling factor (1..4) */ + int v_samp_factor; /* vertical sampling factor (1..4) */ + int quant_tbl_no; /* quantization table selector (0..3) */ + /* These values may vary between scans. */ + /* For compression, they must be supplied by parameter setup; */ + /* for decompression, they are read from the SOS marker. */ + /* The decompressor output side may not use these variables. */ + int dc_tbl_no; /* DC entropy table selector (0..3) */ + int ac_tbl_no; /* AC entropy table selector (0..3) */ + + /* Remaining fields should be treated as private by applications. */ + + /* These values are computed during compression or decompression startup: */ + /* Component's size in DCT blocks. + * Any dummy blocks added to complete an MCU are not counted; therefore + * these values do not depend on whether a scan is interleaved or not. + */ + JDIMENSION width_in_blocks; + JDIMENSION height_in_blocks; + /* Size of a DCT block in samples. Always DCTSIZE for compression. + * For decompression this is the size of the output from one DCT block, + * reflecting any scaling we choose to apply during the IDCT step. + * Values of 1,2,4,8 are likely to be supported. Note that different + * components may receive different IDCT scalings. + */ + int DCT_scaled_size; + /* The downsampled dimensions are the component's actual, unpadded number + * of samples at the main buffer (preprocessing/compression interface), thus + * downsampled_width = ceil(image_width * Hi/Hmax) + * and similarly for height. For decompression, IDCT scaling is included, so + * downsampled_width = ceil(image_width * Hi/Hmax * DCT_scaled_size/DCTSIZE) + */ + JDIMENSION downsampled_width; /* actual width in samples */ + JDIMENSION downsampled_height; /* actual height in samples */ + /* This flag is used only for decompression. In cases where some of the + * components will be ignored (eg grayscale output from YCbCr image), + * we can skip most computations for the unused components. + */ + boolean component_needed; /* do we need the value of this component? */ + + /* These values are computed before starting a scan of the component. */ + /* The decompressor output side may not use these variables. */ + int MCU_width; /* number of blocks per MCU, horizontally */ + int MCU_height; /* number of blocks per MCU, vertically */ + int MCU_blocks; /* MCU_width * MCU_height */ + int MCU_sample_width; /* MCU width in samples, MCU_width*DCT_scaled_size */ + int last_col_width; /* # of non-dummy blocks across in last MCU */ + int last_row_height; /* # of non-dummy blocks down in last MCU */ + + /* Saved quantization table for component; NULL if none yet saved. + * See jdinput.c comments about the need for this information. + * This field is currently used only for decompression. + */ + JQUANT_TBL * quant_table; + + /* Private per-component storage for DCT or IDCT subsystem. */ + void * dct_table; +} jpeg_component_info; + + +/* The script for encoding a multiple-scan file is an array of these: */ + +typedef struct { + int comps_in_scan; /* number of components encoded in this scan */ + int component_index[MAX_COMPS_IN_SCAN]; /* their SOF/comp_info[] indexes */ + int Ss, Se; /* progressive JPEG spectral selection parms */ + int Ah, Al; /* progressive JPEG successive approx. parms */ +} jpeg_scan_info; + +/* The decompressor can save APPn and COM markers in a list of these: */ + +typedef struct jpeg_marker_struct FAR * jpeg_saved_marker_ptr; + +struct jpeg_marker_struct { + jpeg_saved_marker_ptr next; /* next in list, or NULL */ + UINT8 marker; /* marker code: JPEG_COM, or JPEG_APP0+n */ + unsigned int original_length; /* # bytes of data in the file */ + unsigned int data_length; /* # bytes of data saved at data[] */ + JOCTET FAR * data; /* the data contained in the marker */ + /* the marker length word is not counted in data_length or original_length */ +}; + +/* Known color spaces. */ + +typedef enum { + JCS_UNKNOWN, /* error/unspecified */ + JCS_GRAYSCALE, /* monochrome */ + JCS_RGB, /* red/green/blue */ + JCS_YCbCr, /* Y/Cb/Cr (also known as YUV) */ + JCS_CMYK, /* C/M/Y/K */ + JCS_YCCK /* Y/Cb/Cr/K */ +} J_COLOR_SPACE; + +/* DCT/IDCT algorithm options. */ + +typedef enum { + JDCT_ISLOW, /* slow but accurate integer algorithm */ + JDCT_IFAST, /* faster, less accurate integer method */ + JDCT_FLOAT /* floating-point: accurate, fast on fast HW */ +} J_DCT_METHOD; + +#ifndef JDCT_DEFAULT /* may be overridden in jconfig.h */ +#define JDCT_DEFAULT JDCT_ISLOW +#endif +#ifndef JDCT_FASTEST /* may be overridden in jconfig.h */ +#define JDCT_FASTEST JDCT_IFAST +#endif + +/* Dithering options for decompression. */ + +typedef enum { + JDITHER_NONE, /* no dithering */ + JDITHER_ORDERED, /* simple ordered dither */ + JDITHER_FS /* Floyd-Steinberg error diffusion dither */ +} J_DITHER_MODE; + + +/* Common fields between JPEG compression and decompression master structs. */ + +#define jpeg_common_fields \ + struct jpeg_error_mgr * err; /* Error handler module */\ + struct jpeg_memory_mgr * mem; /* Memory manager module */\ + struct jpeg_progress_mgr * progress; /* Progress monitor, or NULL if none */\ + void * client_data; /* Available for use by application */\ + boolean is_decompressor; /* So common code can tell which is which */\ + int global_state /* For checking call sequence validity */ + +/* Routines that are to be used by both halves of the library are declared + * to receive a pointer to this structure. There are no actual instances of + * jpeg_common_struct, only of jpeg_compress_struct and jpeg_decompress_struct. + */ +struct jpeg_common_struct { + jpeg_common_fields; /* Fields common to both master struct types */ + /* Additional fields follow in an actual jpeg_compress_struct or + * jpeg_decompress_struct. All three structs must agree on these + * initial fields! (This would be a lot cleaner in C++.) + */ +}; + +typedef struct jpeg_common_struct * j_common_ptr; +typedef struct jpeg_compress_struct * j_compress_ptr; +typedef struct jpeg_decompress_struct * j_decompress_ptr; + + +/* Master record for a compression instance */ + +struct jpeg_compress_struct { + jpeg_common_fields; /* Fields shared with jpeg_decompress_struct */ + + /* Destination for compressed data */ + struct jpeg_destination_mgr * dest; + + /* Description of source image --- these fields must be filled in by + * outer application before starting compression. in_color_space must + * be correct before you can even call jpeg_set_defaults(). + */ + + JDIMENSION image_width; /* input image width */ + JDIMENSION image_height; /* input image height */ + int input_components; /* # of color components in input image */ + J_COLOR_SPACE in_color_space; /* colorspace of input image */ + + double input_gamma; /* image gamma of input image */ + + /* Compression parameters --- these fields must be set before calling + * jpeg_start_compress(). We recommend calling jpeg_set_defaults() to + * initialize everything to reasonable defaults, then changing anything + * the application specifically wants to change. That way you won't get + * burnt when new parameters are added. Also note that there are several + * helper routines to simplify changing parameters. + */ + + int data_precision; /* bits of precision in image data */ + + int num_components; /* # of color components in JPEG image */ + J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */ + + jpeg_component_info * comp_info; + /* comp_info[i] describes component that appears i'th in SOF */ + + JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS]; + /* ptrs to coefficient quantization tables, or NULL if not defined */ + + JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; + JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; + /* ptrs to Huffman coding tables, or NULL if not defined */ + + UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ + UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ + UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ + + int num_scans; /* # of entries in scan_info array */ + const jpeg_scan_info * scan_info; /* script for multi-scan file, or NULL */ + /* The default value of scan_info is NULL, which causes a single-scan + * sequential JPEG file to be emitted. To create a multi-scan file, + * set num_scans and scan_info to point to an array of scan definitions. + */ + + boolean raw_data_in; /* TRUE=caller supplies downsampled data */ + boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ + boolean optimize_coding; /* TRUE=optimize entropy encoding parms */ + boolean CCIR601_sampling; /* TRUE=first samples are cosited */ + int smoothing_factor; /* 1..100, or 0 for no input smoothing */ + J_DCT_METHOD dct_method; /* DCT algorithm selector */ + + /* The restart interval can be specified in absolute MCUs by setting + * restart_interval, or in MCU rows by setting restart_in_rows + * (in which case the correct restart_interval will be figured + * for each scan). + */ + unsigned int restart_interval; /* MCUs per restart, or 0 for no restart */ + int restart_in_rows; /* if > 0, MCU rows per restart interval */ + + /* Parameters controlling emission of special markers. */ + + boolean write_JFIF_header; /* should a JFIF marker be written? */ + UINT8 JFIF_major_version; /* What to write for the JFIF version number */ + UINT8 JFIF_minor_version; + /* These three values are not used by the JPEG code, merely copied */ + /* into the JFIF APP0 marker. density_unit can be 0 for unknown, */ + /* 1 for dots/inch, or 2 for dots/cm. Note that the pixel aspect */ + /* ratio is defined by X_density/Y_density even when density_unit=0. */ + UINT8 density_unit; /* JFIF code for pixel size units */ + UINT16 X_density; /* Horizontal pixel density */ + UINT16 Y_density; /* Vertical pixel density */ + boolean write_Adobe_marker; /* should an Adobe marker be written? */ + + /* State variable: index of next scanline to be written to + * jpeg_write_scanlines(). Application may use this to control its + * processing loop, e.g., "while (next_scanline < image_height)". + */ + + JDIMENSION next_scanline; /* 0 .. image_height-1 */ + + /* Remaining fields are known throughout compressor, but generally + * should not be touched by a surrounding application. + */ + + /* + * These fields are computed during compression startup + */ + boolean progressive_mode; /* TRUE if scan script uses progressive mode */ + int max_h_samp_factor; /* largest h_samp_factor */ + int max_v_samp_factor; /* largest v_samp_factor */ + + JDIMENSION total_iMCU_rows; /* # of iMCU rows to be input to coef ctlr */ + /* The coefficient controller receives data in units of MCU rows as defined + * for fully interleaved scans (whether the JPEG file is interleaved or not). + * There are v_samp_factor * DCTSIZE sample rows of each component in an + * "iMCU" (interleaved MCU) row. + */ + + /* + * These fields are valid during any one scan. + * They describe the components and MCUs actually appearing in the scan. + */ + int comps_in_scan; /* # of JPEG components in this scan */ + jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; + /* *cur_comp_info[i] describes component that appears i'th in SOS */ + + JDIMENSION MCUs_per_row; /* # of MCUs across the image */ + JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ + + int blocks_in_MCU; /* # of DCT blocks per MCU */ + int MCU_membership[C_MAX_BLOCKS_IN_MCU]; + /* MCU_membership[i] is index in cur_comp_info of component owning */ + /* i'th block in an MCU */ + + int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */ + + /* + * Links to compression subobjects (methods and private variables of modules) + */ + struct jpeg_comp_master * master; + struct jpeg_c_main_controller * main; + struct jpeg_c_prep_controller * prep; + struct jpeg_c_coef_controller * coef; + struct jpeg_marker_writer * marker; + struct jpeg_color_converter * cconvert; + struct jpeg_downsampler * downsample; + struct jpeg_forward_dct * fdct; + struct jpeg_entropy_encoder * entropy; + jpeg_scan_info * script_space; /* workspace for jpeg_simple_progression */ + int script_space_size; +}; + + +/* Master record for a decompression instance */ + +struct jpeg_decompress_struct { + jpeg_common_fields; /* Fields shared with jpeg_compress_struct */ + + /* Source of compressed data */ + struct jpeg_source_mgr * src; + + /* Basic description of image --- filled in by jpeg_read_header(). */ + /* Application may inspect these values to decide how to process image. */ + + JDIMENSION image_width; /* nominal image width (from SOF marker) */ + JDIMENSION image_height; /* nominal image height */ + int num_components; /* # of color components in JPEG image */ + J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */ + + /* Decompression processing parameters --- these fields must be set before + * calling jpeg_start_decompress(). Note that jpeg_read_header() initializes + * them to default values. + */ + + J_COLOR_SPACE out_color_space; /* colorspace for output */ + + unsigned int scale_num, scale_denom; /* fraction by which to scale image */ + + double output_gamma; /* image gamma wanted in output */ + + boolean buffered_image; /* TRUE=multiple output passes */ + boolean raw_data_out; /* TRUE=downsampled data wanted */ + + J_DCT_METHOD dct_method; /* IDCT algorithm selector */ + boolean do_fancy_upsampling; /* TRUE=apply fancy upsampling */ + boolean do_block_smoothing; /* TRUE=apply interblock smoothing */ + + boolean quantize_colors; /* TRUE=colormapped output wanted */ + /* the following are ignored if not quantize_colors: */ + J_DITHER_MODE dither_mode; /* type of color dithering to use */ + boolean two_pass_quantize; /* TRUE=use two-pass color quantization */ + int desired_number_of_colors; /* max # colors to use in created colormap */ + /* these are significant only in buffered-image mode: */ + boolean enable_1pass_quant; /* enable future use of 1-pass quantizer */ + boolean enable_external_quant;/* enable future use of external colormap */ + boolean enable_2pass_quant; /* enable future use of 2-pass quantizer */ + + /* Description of actual output image that will be returned to application. + * These fields are computed by jpeg_start_decompress(). + * You can also use jpeg_calc_output_dimensions() to determine these values + * in advance of calling jpeg_start_decompress(). + */ + + JDIMENSION output_width; /* scaled image width */ + JDIMENSION output_height; /* scaled image height */ + int out_color_components; /* # of color components in out_color_space */ + int output_components; /* # of color components returned */ + /* output_components is 1 (a colormap index) when quantizing colors; + * otherwise it equals out_color_components. + */ + int rec_outbuf_height; /* min recommended height of scanline buffer */ + /* If the buffer passed to jpeg_read_scanlines() is less than this many rows + * high, space and time will be wasted due to unnecessary data copying. + * Usually rec_outbuf_height will be 1 or 2, at most 4. + */ + + /* When quantizing colors, the output colormap is described by these fields. + * The application can supply a colormap by setting colormap non-NULL before + * calling jpeg_start_decompress; otherwise a colormap is created during + * jpeg_start_decompress or jpeg_start_output. + * The map has out_color_components rows and actual_number_of_colors columns. + */ + int actual_number_of_colors; /* number of entries in use */ + JSAMPARRAY colormap; /* The color map as a 2-D pixel array */ + + /* State variables: these variables indicate the progress of decompression. + * The application may examine these but must not modify them. + */ + + /* Row index of next scanline to be read from jpeg_read_scanlines(). + * Application may use this to control its processing loop, e.g., + * "while (output_scanline < output_height)". + */ + JDIMENSION output_scanline; /* 0 .. output_height-1 */ + + /* Current input scan number and number of iMCU rows completed in scan. + * These indicate the progress of the decompressor input side. + */ + int input_scan_number; /* Number of SOS markers seen so far */ + JDIMENSION input_iMCU_row; /* Number of iMCU rows completed */ + + /* The "output scan number" is the notional scan being displayed by the + * output side. The decompressor will not allow output scan/row number + * to get ahead of input scan/row, but it can fall arbitrarily far behind. + */ + int output_scan_number; /* Nominal scan number being displayed */ + JDIMENSION output_iMCU_row; /* Number of iMCU rows read */ + + /* Current progression status. coef_bits[c][i] indicates the precision + * with which component c's DCT coefficient i (in zigzag order) is known. + * It is -1 when no data has yet been received, otherwise it is the point + * transform (shift) value for the most recent scan of the coefficient + * (thus, 0 at completion of the progression). + * This pointer is NULL when reading a non-progressive file. + */ + int (*coef_bits)[DCTSIZE2]; /* -1 or current Al value for each coef */ + + /* Internal JPEG parameters --- the application usually need not look at + * these fields. Note that the decompressor output side may not use + * any parameters that can change between scans. + */ + + /* Quantization and Huffman tables are carried forward across input + * datastreams when processing abbreviated JPEG datastreams. + */ + + JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS]; + /* ptrs to coefficient quantization tables, or NULL if not defined */ + + JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; + JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; + /* ptrs to Huffman coding tables, or NULL if not defined */ + + /* These parameters are never carried across datastreams, since they + * are given in SOF/SOS markers or defined to be reset by SOI. + */ + + int data_precision; /* bits of precision in image data */ + + jpeg_component_info * comp_info; + /* comp_info[i] describes component that appears i'th in SOF */ + + boolean progressive_mode; /* TRUE if SOFn specifies progressive mode */ + boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ + + UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ + UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ + UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ + + unsigned int restart_interval; /* MCUs per restart interval, or 0 for no restart */ + + /* These fields record data obtained from optional markers recognized by + * the JPEG library. + */ + boolean saw_JFIF_marker; /* TRUE iff a JFIF APP0 marker was found */ + /* Data copied from JFIF marker; only valid if saw_JFIF_marker is TRUE: */ + UINT8 JFIF_major_version; /* JFIF version number */ + UINT8 JFIF_minor_version; + UINT8 density_unit; /* JFIF code for pixel size units */ + UINT16 X_density; /* Horizontal pixel density */ + UINT16 Y_density; /* Vertical pixel density */ + boolean saw_Adobe_marker; /* TRUE iff an Adobe APP14 marker was found */ + UINT8 Adobe_transform; /* Color transform code from Adobe marker */ + + boolean CCIR601_sampling; /* TRUE=first samples are cosited */ + + /* Aside from the specific data retained from APPn markers known to the + * library, the uninterpreted contents of any or all APPn and COM markers + * can be saved in a list for examination by the application. + */ + jpeg_saved_marker_ptr marker_list; /* Head of list of saved markers */ + + /* Remaining fields are known throughout decompressor, but generally + * should not be touched by a surrounding application. + */ + + /* + * These fields are computed during decompression startup + */ + int max_h_samp_factor; /* largest h_samp_factor */ + int max_v_samp_factor; /* largest v_samp_factor */ + + int min_DCT_scaled_size; /* smallest DCT_scaled_size of any component */ + + JDIMENSION total_iMCU_rows; /* # of iMCU rows in image */ + /* The coefficient controller's input and output progress is measured in + * units of "iMCU" (interleaved MCU) rows. These are the same as MCU rows + * in fully interleaved JPEG scans, but are used whether the scan is + * interleaved or not. We define an iMCU row as v_samp_factor DCT block + * rows of each component. Therefore, the IDCT output contains + * v_samp_factor*DCT_scaled_size sample rows of a component per iMCU row. + */ + + JSAMPLE * sample_range_limit; /* table for fast range-limiting */ + + /* + * These fields are valid during any one scan. + * They describe the components and MCUs actually appearing in the scan. + * Note that the decompressor output side must not use these fields. + */ + int comps_in_scan; /* # of JPEG components in this scan */ + jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; + /* *cur_comp_info[i] describes component that appears i'th in SOS */ + + JDIMENSION MCUs_per_row; /* # of MCUs across the image */ + JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ + + int blocks_in_MCU; /* # of DCT blocks per MCU */ + int MCU_membership[D_MAX_BLOCKS_IN_MCU]; + /* MCU_membership[i] is index in cur_comp_info of component owning */ + /* i'th block in an MCU */ + + int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */ + + /* This field is shared between entropy decoder and marker parser. + * It is either zero or the code of a JPEG marker that has been + * read from the data source, but has not yet been processed. + */ + int unread_marker; + + /* + * Links to decompression subobjects (methods, private variables of modules) + */ + struct jpeg_decomp_master * master; + struct jpeg_d_main_controller * main; + struct jpeg_d_coef_controller * coef; + struct jpeg_d_post_controller * post; + struct jpeg_input_controller * inputctl; + struct jpeg_marker_reader * marker; + struct jpeg_entropy_decoder * entropy; + struct jpeg_inverse_dct * idct; + struct jpeg_upsampler * upsample; + struct jpeg_color_deconverter * cconvert; + struct jpeg_color_quantizer * cquantize; +}; + + +/* "Object" declarations for JPEG modules that may be supplied or called + * directly by the surrounding application. + * As with all objects in the JPEG library, these structs only define the + * publicly visible methods and state variables of a module. Additional + * private fields may exist after the public ones. + */ + + +/* Error handler object */ + +struct jpeg_error_mgr { + /* Error exit handler: does not return to caller */ + JMETHOD(void, error_exit, (j_common_ptr cinfo)); + /* Conditionally emit a trace or warning message */ + JMETHOD(void, emit_message, (j_common_ptr cinfo, int msg_level)); + /* Routine that actually outputs a trace or error message */ + JMETHOD(void, output_message, (j_common_ptr cinfo)); + /* Format a message string for the most recent JPEG error or message */ + JMETHOD(void, format_message, (j_common_ptr cinfo, char * buffer)); +#define JMSG_LENGTH_MAX 200 /* recommended size of format_message buffer */ + /* Reset error state variables at start of a new image */ + JMETHOD(void, reset_error_mgr, (j_common_ptr cinfo)); + + /* The message ID code and any parameters are saved here. + * A message can have one string parameter or up to 8 int parameters. + */ + int msg_code; +#define JMSG_STR_PARM_MAX 80 + union { + int i[8]; + char s[JMSG_STR_PARM_MAX]; + } msg_parm; + + /* Standard state variables for error facility */ + + int trace_level; /* max msg_level that will be displayed */ + + /* For recoverable corrupt-data errors, we emit a warning message, + * but keep going unless emit_message chooses to abort. emit_message + * should count warnings in num_warnings. The surrounding application + * can check for bad data by seeing if num_warnings is nonzero at the + * end of processing. + */ + long num_warnings; /* number of corrupt-data warnings */ + + /* These fields point to the table(s) of error message strings. + * An application can change the table pointer to switch to a different + * message list (typically, to change the language in which errors are + * reported). Some applications may wish to add additional error codes + * that will be handled by the JPEG library error mechanism; the second + * table pointer is used for this purpose. + * + * First table includes all errors generated by JPEG library itself. + * Error code 0 is reserved for a "no such error string" message. + */ + const char * const * jpeg_message_table; /* Library errors */ + int last_jpeg_message; /* Table contains strings 0..last_jpeg_message */ + /* Second table can be added by application (see cjpeg/djpeg for example). + * It contains strings numbered first_addon_message..last_addon_message. + */ + const char * const * addon_message_table; /* Non-library errors */ + int first_addon_message; /* code for first string in addon table */ + int last_addon_message; /* code for last string in addon table */ +}; + + +/* Progress monitor object */ + +struct jpeg_progress_mgr { + JMETHOD(void, progress_monitor, (j_common_ptr cinfo)); + + long pass_counter; /* work units completed in this pass */ + long pass_limit; /* total number of work units in this pass */ + int completed_passes; /* passes completed so far */ + int total_passes; /* total number of passes expected */ +}; + + +/* Data destination object for compression */ + +struct jpeg_destination_mgr { + JOCTET * next_output_byte; /* => next byte to write in buffer */ + size_t free_in_buffer; /* # of byte spaces remaining in buffer */ + + JMETHOD(void, init_destination, (j_compress_ptr cinfo)); + JMETHOD(boolean, empty_output_buffer, (j_compress_ptr cinfo)); + JMETHOD(void, term_destination, (j_compress_ptr cinfo)); +}; + + +/* Data source object for decompression */ + +struct jpeg_source_mgr { + const JOCTET * next_input_byte; /* => next byte to read from buffer */ + size_t bytes_in_buffer; /* # of bytes remaining in buffer */ + + JMETHOD(void, init_source, (j_decompress_ptr cinfo)); + JMETHOD(boolean, fill_input_buffer, (j_decompress_ptr cinfo)); + JMETHOD(void, skip_input_data, (j_decompress_ptr cinfo, long num_bytes)); + JMETHOD(boolean, resync_to_restart, (j_decompress_ptr cinfo, int desired)); + JMETHOD(void, term_source, (j_decompress_ptr cinfo)); +}; + + +/* Memory manager object. + * Allocates "small" objects (a few K total), "large" objects (tens of K), + * and "really big" objects (virtual arrays with backing store if needed). + * The memory manager does not allow individual objects to be freed; rather, + * each created object is assigned to a pool, and whole pools can be freed + * at once. This is faster and more convenient than remembering exactly what + * to free, especially where malloc()/free() are not too speedy. + * NB: alloc routines never return NULL. They exit to error_exit if not + * successful. + */ + +#define JPOOL_PERMANENT 0 /* lasts until master record is destroyed */ +#define JPOOL_IMAGE 1 /* lasts until done with image/datastream */ +#define JPOOL_NUMPOOLS 2 + +typedef struct jvirt_sarray_control * jvirt_sarray_ptr; +typedef struct jvirt_barray_control * jvirt_barray_ptr; + + +struct jpeg_memory_mgr { + /* Method pointers */ + JMETHOD(void *, alloc_small, (j_common_ptr cinfo, int pool_id, + size_t sizeofobject)); + JMETHOD(void FAR *, alloc_large, (j_common_ptr cinfo, int pool_id, + size_t sizeofobject)); + JMETHOD(JSAMPARRAY, alloc_sarray, (j_common_ptr cinfo, int pool_id, + JDIMENSION samplesperrow, + JDIMENSION numrows)); + JMETHOD(JBLOCKARRAY, alloc_barray, (j_common_ptr cinfo, int pool_id, + JDIMENSION blocksperrow, + JDIMENSION numrows)); + JMETHOD(jvirt_sarray_ptr, request_virt_sarray, (j_common_ptr cinfo, + int pool_id, + boolean pre_zero, + JDIMENSION samplesperrow, + JDIMENSION numrows, + JDIMENSION maxaccess)); + JMETHOD(jvirt_barray_ptr, request_virt_barray, (j_common_ptr cinfo, + int pool_id, + boolean pre_zero, + JDIMENSION blocksperrow, + JDIMENSION numrows, + JDIMENSION maxaccess)); + JMETHOD(void, realize_virt_arrays, (j_common_ptr cinfo)); + JMETHOD(JSAMPARRAY, access_virt_sarray, (j_common_ptr cinfo, + jvirt_sarray_ptr ptr, + JDIMENSION start_row, + JDIMENSION num_rows, + boolean writable)); + JMETHOD(JBLOCKARRAY, access_virt_barray, (j_common_ptr cinfo, + jvirt_barray_ptr ptr, + JDIMENSION start_row, + JDIMENSION num_rows, + boolean writable)); + JMETHOD(void, free_pool, (j_common_ptr cinfo, int pool_id)); + JMETHOD(void, self_destruct, (j_common_ptr cinfo)); + + /* Limit on memory allocation for this JPEG object. (Note that this is + * merely advisory, not a guaranteed maximum; it only affects the space + * used for virtual-array buffers.) May be changed by outer application + * after creating the JPEG object. + */ + long max_memory_to_use; + + /* Maximum allocation request accepted by alloc_large. */ + long max_alloc_chunk; +}; + + +/* Routine signature for application-supplied marker processing methods. + * Need not pass marker code since it is stored in cinfo->unread_marker. + */ +typedef JMETHOD(boolean, jpeg_marker_parser_method, (j_decompress_ptr cinfo)); + + +/* Declarations for routines called by application. + * The JPP macro hides prototype parameters from compilers that can't cope. + * Note JPP requires double parentheses. + */ + +#ifdef HAVE_PROTOTYPES +#define JPP(arglist) arglist +#else +#define JPP(arglist) () +#endif + + +/* Short forms of external names for systems with brain-damaged linkers. + * We shorten external names to be unique in the first six letters, which + * is good enough for all known systems. + * (If your compiler itself needs names to be unique in less than 15 + * characters, you are out of luck. Get a better compiler.) + */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_std_error jStdError +#define jpeg_CreateCompress jCreaCompress +#define jpeg_CreateDecompress jCreaDecompress +#define jpeg_destroy_compress jDestCompress +#define jpeg_destroy_decompress jDestDecompress +#define jpeg_stdio_dest jStdDest +#define jpeg_stdio_src jStdSrc +#define jpeg_set_defaults jSetDefaults +#define jpeg_set_colorspace jSetColorspace +#define jpeg_default_colorspace jDefColorspace +#define jpeg_set_quality jSetQuality +#define jpeg_set_linear_quality jSetLQuality +#define jpeg_add_quant_table jAddQuantTable +#define jpeg_quality_scaling jQualityScaling +#define jpeg_simple_progression jSimProgress +#define jpeg_suppress_tables jSuppressTables +#define jpeg_alloc_quant_table jAlcQTable +#define jpeg_alloc_huff_table jAlcHTable +#define jpeg_start_compress jStrtCompress +#define jpeg_write_scanlines jWrtScanlines +#define jpeg_finish_compress jFinCompress +#define jpeg_write_raw_data jWrtRawData +#define jpeg_write_marker jWrtMarker +#define jpeg_write_m_header jWrtMHeader +#define jpeg_write_m_byte jWrtMByte +#define jpeg_write_tables jWrtTables +#define jpeg_read_header jReadHeader +#define jpeg_start_decompress jStrtDecompress +#define jpeg_read_scanlines jReadScanlines +#define jpeg_finish_decompress jFinDecompress +#define jpeg_read_raw_data jReadRawData +#define jpeg_has_multiple_scans jHasMultScn +#define jpeg_start_output jStrtOutput +#define jpeg_finish_output jFinOutput +#define jpeg_input_complete jInComplete +#define jpeg_new_colormap jNewCMap +#define jpeg_consume_input jConsumeInput +#define jpeg_calc_output_dimensions jCalcDimensions +#define jpeg_save_markers jSaveMarkers +#define jpeg_set_marker_processor jSetMarker +#define jpeg_read_coefficients jReadCoefs +#define jpeg_write_coefficients jWrtCoefs +#define jpeg_copy_critical_parameters jCopyCrit +#define jpeg_abort_compress jAbrtCompress +#define jpeg_abort_decompress jAbrtDecompress +#define jpeg_abort jAbort +#define jpeg_destroy jDestroy +#define jpeg_resync_to_restart jResyncRestart +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* Default error-management setup */ +EXTERN(struct jpeg_error_mgr *) jpeg_std_error + JPP((struct jpeg_error_mgr * err)); + +/* Initialization of JPEG compression objects. + * jpeg_create_compress() and jpeg_create_decompress() are the exported + * names that applications should call. These expand to calls on + * jpeg_CreateCompress and jpeg_CreateDecompress with additional information + * passed for version mismatch checking. + * NB: you must set up the error-manager BEFORE calling jpeg_create_xxx. + */ +#define jpeg_create_compress(cinfo) \ + jpeg_CreateCompress((cinfo), JPEG_LIB_VERSION, \ + (size_t) sizeof(struct jpeg_compress_struct)) +#define jpeg_create_decompress(cinfo) \ + jpeg_CreateDecompress((cinfo), JPEG_LIB_VERSION, \ + (size_t) sizeof(struct jpeg_decompress_struct)) +EXTERN(void) jpeg_CreateCompress JPP((j_compress_ptr cinfo, + int version, size_t structsize)); +EXTERN(void) jpeg_CreateDecompress JPP((j_decompress_ptr cinfo, + int version, size_t structsize)); +/* Destruction of JPEG compression objects */ +EXTERN(void) jpeg_destroy_compress JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_destroy_decompress JPP((j_decompress_ptr cinfo)); + +/* Standard data source and destination managers: stdio streams. */ +/* Caller is responsible for opening the file before and closing after. */ +EXTERN(void) jpeg_stdio_dest JPP((j_compress_ptr cinfo, FILE * outfile)); +EXTERN(void) jpeg_stdio_src JPP((j_decompress_ptr cinfo, FILE * infile)); + +/* Default parameter setup for compression */ +EXTERN(void) jpeg_set_defaults JPP((j_compress_ptr cinfo)); +/* Compression parameter setup aids */ +EXTERN(void) jpeg_set_colorspace JPP((j_compress_ptr cinfo, + J_COLOR_SPACE colorspace)); +EXTERN(void) jpeg_default_colorspace JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_set_quality JPP((j_compress_ptr cinfo, int quality, + boolean force_baseline)); +EXTERN(void) jpeg_set_linear_quality JPP((j_compress_ptr cinfo, + int scale_factor, + boolean force_baseline)); +EXTERN(void) jpeg_add_quant_table JPP((j_compress_ptr cinfo, int which_tbl, + const unsigned int *basic_table, + int scale_factor, + boolean force_baseline)); +EXTERN(int) jpeg_quality_scaling JPP((int quality)); +EXTERN(void) jpeg_simple_progression JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_suppress_tables JPP((j_compress_ptr cinfo, + boolean suppress)); +EXTERN(JQUANT_TBL *) jpeg_alloc_quant_table JPP((j_common_ptr cinfo)); +EXTERN(JHUFF_TBL *) jpeg_alloc_huff_table JPP((j_common_ptr cinfo)); + +/* Main entry points for compression */ +EXTERN(void) jpeg_start_compress JPP((j_compress_ptr cinfo, + boolean write_all_tables)); +EXTERN(JDIMENSION) jpeg_write_scanlines JPP((j_compress_ptr cinfo, + JSAMPARRAY scanlines, + JDIMENSION num_lines)); +EXTERN(void) jpeg_finish_compress JPP((j_compress_ptr cinfo)); + +/* Replaces jpeg_write_scanlines when writing raw downsampled data. */ +EXTERN(JDIMENSION) jpeg_write_raw_data JPP((j_compress_ptr cinfo, + JSAMPIMAGE data, + JDIMENSION num_lines)); + +/* Write a special marker. See libjpeg.doc concerning safe usage. */ +EXTERN(void) jpeg_write_marker + JPP((j_compress_ptr cinfo, int marker, + const JOCTET * dataptr, unsigned int datalen)); +/* Same, but piecemeal. */ +EXTERN(void) jpeg_write_m_header + JPP((j_compress_ptr cinfo, int marker, unsigned int datalen)); +EXTERN(void) jpeg_write_m_byte + JPP((j_compress_ptr cinfo, int val)); + +/* Alternate compression function: just write an abbreviated table file */ +EXTERN(void) jpeg_write_tables JPP((j_compress_ptr cinfo)); + +/* Decompression startup: read start of JPEG datastream to see what's there */ +EXTERN(int) jpeg_read_header JPP((j_decompress_ptr cinfo, + boolean require_image)); +/* Return value is one of: */ +#define JPEG_SUSPENDED 0 /* Suspended due to lack of input data */ +#define JPEG_HEADER_OK 1 /* Found valid image datastream */ +#define JPEG_HEADER_TABLES_ONLY 2 /* Found valid table-specs-only datastream */ +/* If you pass require_image = TRUE (normal case), you need not check for + * a TABLES_ONLY return code; an abbreviated file will cause an error exit. + * JPEG_SUSPENDED is only possible if you use a data source module that can + * give a suspension return (the stdio source module doesn't). + */ + +/* Main entry points for decompression */ +EXTERN(boolean) jpeg_start_decompress JPP((j_decompress_ptr cinfo)); +EXTERN(JDIMENSION) jpeg_read_scanlines JPP((j_decompress_ptr cinfo, + JSAMPARRAY scanlines, + JDIMENSION max_lines)); +EXTERN(boolean) jpeg_finish_decompress JPP((j_decompress_ptr cinfo)); + +/* Replaces jpeg_read_scanlines when reading raw downsampled data. */ +EXTERN(JDIMENSION) jpeg_read_raw_data JPP((j_decompress_ptr cinfo, + JSAMPIMAGE data, + JDIMENSION max_lines)); + +/* Additional entry points for buffered-image mode. */ +EXTERN(boolean) jpeg_has_multiple_scans JPP((j_decompress_ptr cinfo)); +EXTERN(boolean) jpeg_start_output JPP((j_decompress_ptr cinfo, + int scan_number)); +EXTERN(boolean) jpeg_finish_output JPP((j_decompress_ptr cinfo)); +EXTERN(boolean) jpeg_input_complete JPP((j_decompress_ptr cinfo)); +EXTERN(void) jpeg_new_colormap JPP((j_decompress_ptr cinfo)); +EXTERN(int) jpeg_consume_input JPP((j_decompress_ptr cinfo)); +/* Return value is one of: */ +/* #define JPEG_SUSPENDED 0 Suspended due to lack of input data */ +#define JPEG_REACHED_SOS 1 /* Reached start of new scan */ +#define JPEG_REACHED_EOI 2 /* Reached end of image */ +#define JPEG_ROW_COMPLETED 3 /* Completed one iMCU row */ +#define JPEG_SCAN_COMPLETED 4 /* Completed last iMCU row of a scan */ + +/* Precalculate output dimensions for current decompression parameters. */ +EXTERN(void) jpeg_calc_output_dimensions JPP((j_decompress_ptr cinfo)); + +/* Control saving of COM and APPn markers into marker_list. */ +EXTERN(void) jpeg_save_markers + JPP((j_decompress_ptr cinfo, int marker_code, + unsigned int length_limit)); + +/* Install a special processing method for COM or APPn markers. */ +EXTERN(void) jpeg_set_marker_processor + JPP((j_decompress_ptr cinfo, int marker_code, + jpeg_marker_parser_method routine)); + +/* Read or write raw DCT coefficients --- useful for lossless transcoding. */ +EXTERN(jvirt_barray_ptr *) jpeg_read_coefficients JPP((j_decompress_ptr cinfo)); +EXTERN(void) jpeg_write_coefficients JPP((j_compress_ptr cinfo, + jvirt_barray_ptr * coef_arrays)); +EXTERN(void) jpeg_copy_critical_parameters JPP((j_decompress_ptr srcinfo, + j_compress_ptr dstinfo)); + +/* If you choose to abort compression or decompression before completing + * jpeg_finish_(de)compress, then you need to clean up to release memory, + * temporary files, etc. You can just call jpeg_destroy_(de)compress + * if you're done with the JPEG object, but if you want to clean it up and + * reuse it, call this: + */ +EXTERN(void) jpeg_abort_compress JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_abort_decompress JPP((j_decompress_ptr cinfo)); + +/* Generic versions of jpeg_abort and jpeg_destroy that work on either + * flavor of JPEG object. These may be more convenient in some places. + */ +EXTERN(void) jpeg_abort JPP((j_common_ptr cinfo)); +EXTERN(void) jpeg_destroy JPP((j_common_ptr cinfo)); + +/* Default restart-marker-resync procedure for use by data source modules */ +EXTERN(boolean) jpeg_resync_to_restart JPP((j_decompress_ptr cinfo, + int desired)); + + +/* These marker codes are exported since applications and data source modules + * are likely to want to use them. + */ + +#define JPEG_RST0 0xD0 /* RST0 marker code */ +#define JPEG_EOI 0xD9 /* EOI marker code */ +#define JPEG_APP0 0xE0 /* APP0 marker code */ +#define JPEG_COM 0xFE /* COM marker code */ + + +/* If we have a brain-damaged compiler that emits warnings (or worse, errors) + * for structure definitions that are never filled in, keep it quiet by + * supplying dummy definitions for the various substructures. + */ + +#ifdef INCOMPLETE_TYPES_BROKEN +#ifndef JPEG_INTERNALS /* will be defined in jpegint.h */ +struct jvirt_sarray_control { long dummy; }; +struct jvirt_barray_control { long dummy; }; +struct jpeg_comp_master { long dummy; }; +struct jpeg_c_main_controller { long dummy; }; +struct jpeg_c_prep_controller { long dummy; }; +struct jpeg_c_coef_controller { long dummy; }; +struct jpeg_marker_writer { long dummy; }; +struct jpeg_color_converter { long dummy; }; +struct jpeg_downsampler { long dummy; }; +struct jpeg_forward_dct { long dummy; }; +struct jpeg_entropy_encoder { long dummy; }; +struct jpeg_decomp_master { long dummy; }; +struct jpeg_d_main_controller { long dummy; }; +struct jpeg_d_coef_controller { long dummy; }; +struct jpeg_d_post_controller { long dummy; }; +struct jpeg_input_controller { long dummy; }; +struct jpeg_marker_reader { long dummy; }; +struct jpeg_entropy_decoder { long dummy; }; +struct jpeg_inverse_dct { long dummy; }; +struct jpeg_upsampler { long dummy; }; +struct jpeg_color_deconverter { long dummy; }; +struct jpeg_color_quantizer { long dummy; }; +#endif /* JPEG_INTERNALS */ +#endif /* INCOMPLETE_TYPES_BROKEN */ + + +/* + * The JPEG library modules define JPEG_INTERNALS before including this file. + * The internal structure declarations are read only when that is true. + * Applications using the library should not include jpegint.h, but may wish + * to include jerror.h. + */ + +#ifdef JPEG_INTERNALS +#include "jpegint.h" /* fetch private declarations */ +#include "jerror.h" /* fetch error codes too */ +#endif + +#endif /* JPEGLIB_H */ diff --git a/mk4/modimage/jversion.h b/mk4/modimage/jversion.h new file mode 100644 index 0000000..6472c58 --- /dev/null +++ b/mk4/modimage/jversion.h @@ -0,0 +1,14 @@ +/* + * jversion.h + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains software version identification. + */ + + +#define JVERSION "6b 27-Mar-1998" + +#define JCOPYRIGHT "Copyright (C) 1998, Thomas G. Lane" diff --git a/mk4/modimage/transupp.h b/mk4/modimage/transupp.h new file mode 100644 index 0000000..5c2d32a --- /dev/null +++ b/mk4/modimage/transupp.h @@ -0,0 +1,135 @@ +/* + * transupp.h + * + * Copyright (C) 1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains declarations for image transformation routines and + * other utility code used by the jpegtran sample application. These are + * NOT part of the core JPEG library. But we keep these routines separate + * from jpegtran.c to ease the task of maintaining jpegtran-like programs + * that have other user interfaces. + * + * NOTE: all the routines declared here have very specific requirements + * about when they are to be executed during the reading and writing of the + * source and destination files. See the comments in transupp.c, or see + * jpegtran.c for an example of correct usage. + */ + +/* If you happen not to want the image transform support, disable it here */ +#ifndef TRANSFORMS_SUPPORTED +#define TRANSFORMS_SUPPORTED 1 /* 0 disables transform code */ +#endif + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jtransform_request_workspace jTrRequest +#define jtransform_adjust_parameters jTrAdjust +#define jtransform_execute_transformation jTrExec +#define jcopy_markers_setup jCMrkSetup +#define jcopy_markers_execute jCMrkExec +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* + * Codes for supported types of image transformations. + */ + +typedef enum { + JXFORM_NONE, /* no transformation */ + JXFORM_FLIP_H, /* horizontal flip */ + JXFORM_FLIP_V, /* vertical flip */ + JXFORM_TRANSPOSE, /* transpose across UL-to-LR axis */ + JXFORM_TRANSVERSE, /* transpose across UR-to-LL axis */ + JXFORM_ROT_90, /* 90-degree clockwise rotation */ + JXFORM_ROT_180, /* 180-degree rotation */ + JXFORM_ROT_270 /* 270-degree clockwise (or 90 ccw) */ +} JXFORM_CODE; + +/* + * Although rotating and flipping data expressed as DCT coefficients is not + * hard, there is an asymmetry in the JPEG format specification for images + * whose dimensions aren't multiples of the iMCU size. The right and bottom + * image edges are padded out to the next iMCU boundary with junk data; but + * no padding is possible at the top and left edges. If we were to flip + * the whole image including the pad data, then pad garbage would become + * visible at the top and/or left, and real pixels would disappear into the + * pad margins --- perhaps permanently, since encoders & decoders may not + * bother to preserve DCT blocks that appear to be completely outside the + * nominal image area. So, we have to exclude any partial iMCUs from the + * basic transformation. + * + * Transpose is the only transformation that can handle partial iMCUs at the + * right and bottom edges completely cleanly. flip_h can flip partial iMCUs + * at the bottom, but leaves any partial iMCUs at the right edge untouched. + * Similarly flip_v leaves any partial iMCUs at the bottom edge untouched. + * The other transforms are defined as combinations of these basic transforms + * and process edge blocks in a way that preserves the equivalence. + * + * The "trim" option causes untransformable partial iMCUs to be dropped; + * this is not strictly lossless, but it usually gives the best-looking + * result for odd-size images. Note that when this option is active, + * the expected mathematical equivalences between the transforms may not hold. + * (For example, -rot 270 -trim trims only the bottom edge, but -rot 90 -trim + * followed by -rot 180 -trim trims both edges.) + * + * We also offer a "force to grayscale" option, which simply discards the + * chrominance channels of a YCbCr image. This is lossless in the sense that + * the luminance channel is preserved exactly. It's not the same kind of + * thing as the rotate/flip transformations, but it's convenient to handle it + * as part of this package, mainly because the transformation routines have to + * be aware of the option to know how many components to work on. + */ + +typedef struct { + /* Options: set by caller */ + JXFORM_CODE transform; /* image transform operator */ + boolean trim; /* if TRUE, trim partial MCUs as needed */ + boolean force_grayscale; /* if TRUE, convert color image to grayscale */ + + /* Internal workspace: caller should not touch these */ + int num_components; /* # of components in workspace */ + jvirt_barray_ptr * workspace_coef_arrays; /* workspace for transformations */ +} jpeg_transform_info; + + +#if TRANSFORMS_SUPPORTED + +/* Request any required workspace */ +EXTERN(void) jtransform_request_workspace + JPP((j_decompress_ptr srcinfo, jpeg_transform_info *info)); +/* Adjust output image parameters */ +EXTERN(jvirt_barray_ptr *) jtransform_adjust_parameters + JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + jvirt_barray_ptr *src_coef_arrays, + jpeg_transform_info *info)); +/* Execute the actual transformation, if any */ +EXTERN(void) jtransform_execute_transformation + JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + jvirt_barray_ptr *src_coef_arrays, + jpeg_transform_info *info)); + +#endif /* TRANSFORMS_SUPPORTED */ + + +/* + * Support for copying optional markers from source to destination file. + */ + +typedef enum { + JCOPYOPT_NONE, /* copy no optional markers */ + JCOPYOPT_COMMENTS, /* copy only comment (COM) markers */ + JCOPYOPT_ALL /* copy all optional markers */ +} JCOPY_OPTION; + +#define JCOPYOPT_DEFAULT JCOPYOPT_COMMENTS /* recommended default */ + +/* Setup decompression object to save desired markers in memory */ +EXTERN(void) jcopy_markers_setup + JPP((j_decompress_ptr srcinfo, JCOPY_OPTION option)); +/* Copy markers saved in the given source object to the destination object */ +EXTERN(void) jcopy_markers_execute + JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + JCOPY_OPTION option)); diff --git a/mk4/modjava/CVS/Entries b/mk4/modjava/CVS/Entries new file mode 100644 index 0000000..9e26121 --- /dev/null +++ b/mk4/modjava/CVS/Entries @@ -0,0 +1,6 @@ +/Makefile.in/1.2/Mon Apr 26 15:04:31 2004//Tmk4_mod6_rc2 +/Prog.java/1.5/Mon Mar 15 22:15:12 2004//Tmk4_mod6_rc2 +/entrance.c/1.6/Thu Mar 18 15:04:15 2004//Tmk4_mod6_rc2 +/modjava.c/1.5/Thu Mar 18 15:04:15 2004//Tmk4_mod6_rc2 +/module.cfg/1.2/Tue Feb 11 23:30:12 2003//Tmk4_mod6_rc2 +D/com//// diff --git a/mk4/modjava/CVS/Repository b/mk4/modjava/CVS/Repository new file mode 100644 index 0000000..c8c3354 --- /dev/null +++ b/mk4/modjava/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/modjava diff --git a/mk4/modjava/CVS/Root b/mk4/modjava/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/modjava/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/modjava/CVS/Tag b/mk4/modjava/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/modjava/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/modjava/Makefile.in b/mk4/modjava/Makefile.in new file mode 100644 index 0000000..12156f1 --- /dev/null +++ b/mk4/modjava/Makefile.in @@ -0,0 +1,37 @@ +CDIR=../continuity + +include $(CDIR)/lib/env.mk + +JINCLUDE=-I/usr/j2se/include -I/usr/j2se/include/solaris + +CFLAGS=-g $(JINCLUDE) -I$(CDIR)/include + +SRCS=modjava.c +OBJS=modjava.o + +world: com/ashpool/continuity/ContRequest.class modjava.so libentrance.so Prog.class + +com/ashpool/continuity/ContRequest.class: com/ashpool/continuity/ContRequest.java + javac com/ashpool/continuity/ContRequest.java + +modjava.so: $(OBJS) + $(LD_SHARECMD) $(OBJS) -o modjava.so + cp modjava.so ../continuity/lib +#-L/usr/j2se/jre/lib/sparc -ljvm + +libjavaentrance.so: com_ashpool_continuity_ContRequest.h entrance.o + $(LD_SHARECMD) entrance.o -o libjavaentrance.so + cp libjavaentrance.so ../continuity/lib + +com_ashpool_continuity_ContRequest.h: + javah com.ashpool.continuity.ContRequest + +Prog.class: Prog.java + javac Prog.java + +clean: + $(RM) modjava.so $(OBJS) *~ Prog.class libentrance.so entrance.o + $(RM) com_ashpool_continuity_ContRequest.h + +depend: + $(MAKEDEPEND) $(DEPFLAGS) -I ../continuity/include $(JINCLUDE) $(SRCS) diff --git a/mk4/modjava/Prog.java b/mk4/modjava/Prog.java new file mode 100644 index 0000000..518f101 --- /dev/null +++ b/mk4/modjava/Prog.java @@ -0,0 +1,45 @@ +/* + * $Header: /san01/cvs/ashpool/csrc/modjava/Attic/Prog.java,v 1.5 2004/03/15 22:15:12 aleigh Exp $ + */ + +/* + * Copyright (c) 2003 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Use, disclosure, copying, distribution, or transmission of this code without + * express permission is prohibited. + */ + +import com.ashpool.continuity.*; + + public class Prog { + public static void main(String[] args) { + System.out.println("-java-> Loading entrance.so.."); + + System.setProperty("java.library.path","../lib"); + try { + System.loadLibrary("javaentrance"); + } catch (Exception e) { + System.out.println("loadLibrary: " + e.getMessage()); + } + } + + public static void handle(String[] args) { + System.out.println("Prog->Handler: called"); + + String foo = ContRequest.getResponseTuple("Server"); + String uri = ContRequest.getRequestTuple("uri"); + + ContRequest.setResponseTuple("Content-Type","text/plain"); + System.out.println("->java-> server: " + foo); + System.out.println("->java-> uri: " + uri); + + ContRequest.logMessage(3,"-java-> internal handler run."); + ContRequest.setResponseTuple("Java-Version","v.0.0.0"); + ContRequest.startResponse(200); + ContRequest.write("Hello World"); + } + } diff --git a/mk4/modjava/com/CVS/Entries b/mk4/modjava/com/CVS/Entries new file mode 100644 index 0000000..28ce2b1 --- /dev/null +++ b/mk4/modjava/com/CVS/Entries @@ -0,0 +1 @@ +D/ashpool//// diff --git a/mk4/modjava/com/CVS/Repository b/mk4/modjava/com/CVS/Repository new file mode 100644 index 0000000..8326002 --- /dev/null +++ b/mk4/modjava/com/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/modjava/com diff --git a/mk4/modjava/com/CVS/Root b/mk4/modjava/com/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/modjava/com/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/modjava/com/CVS/Tag b/mk4/modjava/com/CVS/Tag new file mode 100644 index 0000000..3677f37 --- /dev/null +++ b/mk4/modjava/com/CVS/Tag @@ -0,0 +1 @@ +Tmk4_mod6_rc2 diff --git a/mk4/modjava/com/ashpool/CVS/Entries b/mk4/modjava/com/ashpool/CVS/Entries new file mode 100644 index 0000000..b638a6b --- /dev/null +++ b/mk4/modjava/com/ashpool/CVS/Entries @@ -0,0 +1 @@ +D/continuity//// diff --git a/mk4/modjava/com/ashpool/CVS/Repository b/mk4/modjava/com/ashpool/CVS/Repository new file mode 100644 index 0000000..e5e264c --- /dev/null +++ b/mk4/modjava/com/ashpool/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/modjava/com/ashpool diff --git a/mk4/modjava/com/ashpool/CVS/Root b/mk4/modjava/com/ashpool/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/modjava/com/ashpool/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/modjava/com/ashpool/CVS/Tag b/mk4/modjava/com/ashpool/CVS/Tag new file mode 100644 index 0000000..3677f37 --- /dev/null +++ b/mk4/modjava/com/ashpool/CVS/Tag @@ -0,0 +1 @@ +Tmk4_mod6_rc2 diff --git a/mk4/modjava/com/ashpool/continuity/CVS/Entries b/mk4/modjava/com/ashpool/continuity/CVS/Entries new file mode 100644 index 0000000..fec8378 --- /dev/null +++ b/mk4/modjava/com/ashpool/continuity/CVS/Entries @@ -0,0 +1,4 @@ +/CatalinaConnector.java/1.2/Tue Feb 11 23:30:12 2003//Tmk4_mod6_rc2 +/ContHttpRequest.java/1.3/Tue Feb 11 23:30:12 2003//Tmk4_mod6_rc2 +/ContRequest.java/1.3/Mon Mar 15 22:15:12 2004//Tmk4_mod6_rc2 +D diff --git a/mk4/modjava/com/ashpool/continuity/CVS/Repository b/mk4/modjava/com/ashpool/continuity/CVS/Repository new file mode 100644 index 0000000..69c3f84 --- /dev/null +++ b/mk4/modjava/com/ashpool/continuity/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/modjava/com/ashpool/continuity diff --git a/mk4/modjava/com/ashpool/continuity/CVS/Root b/mk4/modjava/com/ashpool/continuity/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/modjava/com/ashpool/continuity/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/modjava/com/ashpool/continuity/CVS/Tag b/mk4/modjava/com/ashpool/continuity/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/modjava/com/ashpool/continuity/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/modjava/com/ashpool/continuity/CatalinaConnector.java b/mk4/modjava/com/ashpool/continuity/CatalinaConnector.java new file mode 100644 index 0000000..6fe4baa --- /dev/null +++ b/mk4/modjava/com/ashpool/continuity/CatalinaConnector.java @@ -0,0 +1,307 @@ +package com.tessier.continuity; + +import org.apache.catalina.Container; +import org.apache.catalina.HttpRequest; +import org.apache.catalina.HttpResponse; +import org.apache.catalina.Lifecycle; +import org.apache.catalina.LifecycleEvent; +import org.apache.catalina.LifecycleException; +import org.apache.catalina.LifecycleListener; +import org.apache.catalina.Logger; +import org.apache.catalina.Request; +import org.apache.catalina.Response; +import org.apache.catalina.Service; +import org.apache.catalina.net.DefaultServerSocketFactory; +import org.apache.catalina.net.ServerSocketFactory; +import org.apache.catalina.util.LifecycleSupport; +import org.apache.catalina.util.StringManager; +import org.apache.catalina.Connector; + +/** + * Implementation of a Connectinuity interior connector. + * + * @author Alex Leigh + * @version $Revision: 1.2 $ + */ + +public final class CatalinaConnector + implements Lifecycle, Connector, Runnable { + + /** + * The Service we are associated with (if any). + */ + private Service service = null; + + /** + * The secure connection flag that will be set on all requests received + * through this connector. + */ + private boolean secure = false; + + + /** + * The redirect port for non-SSL to SSL redirects. + */ + private int redirectPort = 443; + + + /** + * The request scheme that will be set on all requests received + * through this connector. + */ + private String scheme = "http"; + + /** + * Descriptive information about this Connector implementation. + */ + private static final String info = + "com.tessier.continuity.CatalinaConnector/1.0"; + + /** + * The Container used for processing requests received by this Connector. + */ + protected Container container = null; + + /** + * The lifecycle event support for this component. + */ + protected LifecycleSupport lifecycle = new LifecycleSupport(this); + + + /** + * The "enable DNS lookups" flag for this Connector. + */ + private boolean enableLookups = false; + + + /** + * The server socket factory for this component. + */ + private ServerSocketFactory factory = null; + + + public void run() { + System.out.println("CatalinaConnector: run() called."); + } + + /** + * Add a lifecycle event listener to this component. + * + * @param listener The listener to add + */ + public void addLifecycleListener(LifecycleListener listener) { + lifecycle.addLifecycleListener(listener); + } + + /** + * Get the lifecycle listeners associated with this lifecycle. If this + * Lifecycle has no listeners registered, a zero-length array is returned. + */ + public LifecycleListener[] findLifecycleListeners() { + return lifecycle.findLifecycleListeners(); + } + + /** + * Remove a lifecycle event listener from this component. + * + * @param listener The listener to add + */ + public void removeLifecycleListener(LifecycleListener listener) { + lifecycle.removeLifecycleListener(listener); + } + + /** + * Begin processing requests via this Connector. + * + * @exception LifecycleException if a fatal startup error occurs + */ + public void start() throws LifecycleException { + // This really does nothing since our requests are going to come + // directly from Continuity. + } + + /** + * Terminate processing requests via this Connector. + * + * @exception LifecycleException if a fatal shutdown error occurs + */ + public void stop() throws LifecycleException { + } + + /** + * Return the Container used for processing requests received by this + * Connector. + */ + public Container getContainer() { + return (container); + } + + /** + * Set the Container used for processing requests received by this + * Connector. + * + * @param container The new Container to use + */ + public void setContainer(Container container) { + this.container = container; + } + + /** + * Return the "enable DNS lookups" flag. + */ + public boolean getEnableLookups() { + return (this.enableLookups); + } + + /** + * Set the "enable DNS lookups" flag. + * + * @param enableLookups The new "enable DNS lookups" flag value + */ + public void setEnableLookups(boolean enableLookups) { + this.enableLookups = enableLookups; + } + + /** + * Return the server socket factory used by this Container. + */ + public ServerSocketFactory getFactory() { + if (this.factory == null) { + synchronized (this) { + this.factory = new DefaultServerSocketFactory(); + } + } + return (this.factory); + } + + /** + * Set the server socket factory used by this Container. + * + * @param factory The new server socket factory + */ + public void setFactory(ServerSocketFactory factory) { + this.factory = factory; + } + + /** + * Return descriptive information about this Connector implementation. + */ + public String getInfo() { + return (info); + } + + /** + * Return the port number to which a request should be redirected if + * it comes in on a non-SSL port and is subject to a security constraint + * with a transport guarantee that requires SSL. + */ + public int getRedirectPort() { + + return (this.redirectPort); + + } + + /** + * Set the redirect port number. + * + * @param redirectPort The redirect port number (non-SSL to SSL) + */ + public void setRedirectPort(int redirectPort) { + + this.redirectPort = redirectPort; + + } + + /** + * Return the scheme that will be assigned to requests received + * through this connector. Default value is "http". + */ + public String getScheme() { + + return (this.scheme); + + } + + + /** + * Set the scheme that will be assigned to requests received through + * this connector. + * + * @param scheme The new scheme + */ + public void setScheme(String scheme) { + + this.scheme = scheme; + + } + + + /** + * Return the secure connection flag that will be assigned to requests + * received through this connector. Default value is "false". + */ + public boolean getSecure() { + + return (this.secure); + + } + + + /** + * Set the secure connection flag that will be assigned to requests + * received through this connector. + * + * @param secure The new secure connection flag + */ + public void setSecure(boolean secure) { + + this.secure = secure; + + } + + /** + * Return the Service with which we are associated (if any). + */ + public Service getService() { + + return (this.service); + + } + + + /** + * Set the Service with which we are associated (if any). + * + * @param service The service that owns this Engine + */ + public void setService(Service service) { + + this.service = service; + + } + + /** + * Create (or allocate) and return a Request object suitable for + * specifying the contents of a Request to the responsible Container. + */ + public Request createRequest() { + ContHttpRequest req = new ContHttpRequest(); + + req.setConnector(this); + return req; + } + + /** + * Create (or allocate) and return a Response object suitable for + * receiving the contents of a Response from the responsible Container. + */ + public Response createResponse() { + return null; + } + + public void initialize() + throws LifecycleException { + System.out.println("CatalinaConnector: initialize() called."); + } +} + diff --git a/mk4/modjava/com/ashpool/continuity/ContHttpRequest.java b/mk4/modjava/com/ashpool/continuity/ContHttpRequest.java new file mode 100644 index 0000000..84b9baf --- /dev/null +++ b/mk4/modjava/com/ashpool/continuity/ContHttpRequest.java @@ -0,0 +1,82 @@ + +package com.tessier.continuity; + +import java.util.Locale; +import java.security.Principal; +import java.net.Socket; +import java.io.InputStream; +import java.util.Iterator; + +import javax.servlet.http.Cookie; +import javax.servlet.ServletInputStream; +import javax.servlet.ServletRequest; + +import org.apache.catalina.HttpRequest; +import org.apache.catalina.Context; +import org.apache.catalina.Connector; +import org.apache.catalina.Wrapper; +import org.apache.catalina.Response; + +/** + * Implementation of HttpRequest specific to the + * Continuity catalina connector. + * + * @author Alex Leigh + * @version $Revision: 1.3 $ $Date: 2003/02/11 23:30:12 $ + */ +final public class ContHttpRequest implements HttpRequest { + + public void addCookie(Cookie cookie) {} + public void addHeader (String name, String value) {} + public void addLocale(Locale locale) {} + public void addParameter(String name, String[] values) {} + public void clearCookies() {} + public void clearHeaders() {} + public void clearLocales() {} + public void clearParameters() {} + public String getDecodedRequestURI() {return null;} + public void setAuthType(String type) {} + public void setContextPath(String path) {} + public void setDecodedRequestURI(String uri) {} + public void setMethod(String method) {} + public void setPathInfo(String path) {} + public void setQueryString(String query) {} + public void setRequestedSessionCookie(boolean flag) {} + public void setRequestedSessionId(String id) {} + public void setRequestedSessionURL(boolean flag) {} + public void setRequestURI(String uri) {} + public void setServletPath(String path) {} + public void setUserPrincipal(Principal principal) {} + + public ServletInputStream createInputStream() {return null;} + public void finishRequest() {} + public String getAuthorization(){return null;} + public Connector getConnector(){return null;} + public Context getContext(){return null;} + public String getInfo(){return null;} + public Object getNote(String name){return null;} + public Iterator getNoteNames(){return null;} + public ServletRequest getRequest(){return null;} + public Response getResponse(){return null;} + public Socket getSocket(){return null;} + public InputStream getStream(){return null;} + public Wrapper getWrapper(){return null;} + public void recycle(){} + public void removeNote(String name){} + public void setAuthorization(String authorization){} + public void setConnector(Connector connector){} + public void setContentLength(int length){} + public void setContentType(String type){} + public void setContext(Context context){} + public void setNote(String name, Object value){} + public void setProtocol(String protocol){} + public void setRemoteAddr(String remote){} + public void setResponse(Response response){} + public void setScheme(String scheme){} + public void setSecure(boolean secure){} + public void setServerName(String name){} + public void setServerPort(int port){} + public void setSocket(Socket socket){} + public void setStream(InputStream stream){} + public void setWrapper(Wrapper wrapper){} +} diff --git a/mk4/modjava/com/ashpool/continuity/ContRequest.java b/mk4/modjava/com/ashpool/continuity/ContRequest.java new file mode 100644 index 0000000..6804e61 --- /dev/null +++ b/mk4/modjava/com/ashpool/continuity/ContRequest.java @@ -0,0 +1,33 @@ +package com.ashpool.continuity; + +/** + * ContRequest implements a series of static methods which window + * into the Continuity server. The context for each method is the + * currently executing transaction for this thread. + */ + +public class ContRequest { +/** + * Log a message to the Continuity console. + * @param level The log level to use. 0 OK 1 WARN 2 ERR 3 DIAG + * msg The message to log to the console. + */ + public static native void logMessage(int level, String msg); + + public static native String getRequestTuple(String key); + public static native String getResponseTuple(String key); + public static native String getVarTuple(String key); + + public static native void setRequestTuple(String key, String value); + public static native void setResponseTuple(String key, String value); + public static native void setVarTuple(String key, String value); + + public static native void startResponse(int status); + + public static native void write(String str); + public static native void write(byte[] b, int length); + + public static native byte[] read(int length); + + public static native void glueObject(Object obj, String method, String name); +} diff --git a/mk4/modjava/entrance.c b/mk4/modjava/entrance.c new file mode 100644 index 0000000..4e4fe52 --- /dev/null +++ b/mk4/modjava/entrance.c @@ -0,0 +1,277 @@ +/* + * Copyright (c) 2003 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Use, disclosure, copying, distribution, or transmission of this code without + * express permission is prohibited. + */ + +#include "com_ashpool_continuity_ContRequest.h" +#include +#include + +JNIEXPORT void JNICALL + Java_com_ashpool_continuity_ContRequest_setResponseTuple(JNIEnv * env, + jclass class, + jstring key, + jstring value) +{ + httpTtrans *t = httpFthread_gettrans(); + jbyte *kstr; + jbyte *vstr; + + if (t == NULL) { + logFmsg(3, "mod/java: entrance thread had an orphaned context."); + return; + } + kstr = (jbyte *) (*env)->GetStringUTFChars(env, key, NULL); + vstr = (jbyte *) (*env)->GetStringUTFChars(env, value, NULL); + + logFmsg(3, "Setting %s/%s", kstr, vstr); + + lstFset_update(t->res_hdrs, (char *) kstr, (char *) vstr); + + (*env)->ReleaseStringUTFChars(env, key, (const char *) kstr); + (*env)->ReleaseStringUTFChars(env, value, (const char *) vstr); + + return; +} + + +JNIEXPORT jstring JNICALL + Java_com_ashpool_continuity_ContRequest_getResponseTuple(JNIEnv * env, + jclass class, + jstring key) { + httpTtrans *t; + char *v; + const jbyte *kstr; + + logFmsg(3, "getResponseTuple() called."); + + t == httpFthread_gettrans(); + + if (t == NULL) { + logFmsg(3, "mod/java: entrance thread had an orphaned context."); + return; + } + kstr = (jbyte *) (*env)->GetStringUTFChars(env, key, NULL); + + v = lstFset_get(t->res_hdrs, (char *) kstr); + + (*env)->ReleaseStringUTFChars(env, key, (const char *) kstr); + + if (v == NULL) + return NULL; + + return (*env)->NewStringUTF(env, v); +} + +JNIEXPORT void JNICALL + Java_com_ashpool_continuity_ContRequest_setRequestTuple(JNIEnv * env, + jclass class, + jstring key, + jstring value) +{ + httpTtrans *t = httpFthread_gettrans(); + jbyte *kstr; + jbyte *vstr; + + + logFmsg(3, "setRequestTuple() called."); + + if (t == NULL) { + logFmsg(3, "mod/java: entrance thread had an orphaned context."); + return; + } + kstr = (jbyte *) (*env)->GetStringUTFChars(env, key, NULL); + vstr = (jbyte *) (*env)->GetStringUTFChars(env, value, NULL); + + logFmsg(3, "Setting %s/%s", kstr, vstr); + + lstFset_update(t->req_hdrs, (char *) kstr, (char *) vstr); + + (*env)->ReleaseStringUTFChars(env, key, (const char *) kstr); + (*env)->ReleaseStringUTFChars(env, value, (const char *) vstr); + + return; +} + + +JNIEXPORT jstring JNICALL + Java_com_ashpool_continuity_ContRequest_getRequestTuple(JNIEnv * env, + jclass class, + jstring key) { + httpTtrans *t; + char *v; + const jbyte *kstr; + + logFmsg(3, "getRequestTuple() called."); + + t = httpFthread_gettrans(); + + + if (t == NULL) { + logFmsg(3, "mod/java: entrance thread had an orphaned context."); + return; + } + kstr = (jbyte *) (*env)->GetStringUTFChars(env, key, NULL); + + v = lstFset_get(t->req_hdrs, (char *) kstr); + + (*env)->ReleaseStringUTFChars(env, key, (const char *) kstr); + + if (v == NULL) + return NULL; + + return (*env)->NewStringUTF(env, v); +} + +JNIEXPORT void JNICALL Java_com_ashpool_continuity_ContRequest_setVarTuple + (JNIEnv * env, jclass class, jstring key, jstring value) { + httpTtrans *t = httpFthread_gettrans(); + jbyte *kstr; + jbyte *vstr; + + if (t == NULL) { + logFmsg(3, "mod/java: entrance thread had an orphaned context."); + return; + } + kstr = (jbyte *) (*env)->GetStringUTFChars(env, key, NULL); + vstr = (jbyte *) (*env)->GetStringUTFChars(env, value, NULL); + + logFmsg(3, "Setting %s/%s", kstr, vstr); + + lstFset_update(t->vars, (char *) kstr, (char *) vstr); + + (*env)->ReleaseStringUTFChars(env, key, (const char *) kstr); + (*env)->ReleaseStringUTFChars(env, value, (const char *) vstr); + + return; +} + + +JNIEXPORT jstring JNICALL + Java_com_ashpool_continuity_ContRequest_getVarTuple(JNIEnv * env, + jclass class, + jstring key) { + httpTtrans *t = httpFthread_gettrans(); + char *v; + const jbyte *kstr; + + logFmsg(3, "getVarTuple() called."); + + if (t == NULL) { + logFmsg(3, "mod/java: entrance thread had an orphaned context."); + return; + } + kstr = (jbyte *) (*env)->GetStringUTFChars(env, key, NULL); + + v = lstFset_get(t->vars, (char *) kstr); + + (*env)->ReleaseStringUTFChars(env, key, (const char *) kstr); + + if (v == NULL) + return NULL; + + return (*env)->NewStringUTF(env, v); +} + +JNIEXPORT void JNICALL Java_com_ashpool_continuity_ContRequest_write___3BI + (JNIEnv * env, jclass class, jbyteArray bytes, jint length) { + + httpTtrans *t = httpFthread_gettrans(); + + logFmsg(3, "write() called."); + + if (t == NULL) { + logFmsg(3, "mod/java: entrance thread had an orphaned context."); + return; + } + httpFwrite(t, (char *) bytes, length); +} + +JNIEXPORT void JNICALL Java_com_ashpool_continuity_ContRequest_logMessage + (JNIEnv * env, jclass class, jint level, jstring msg) { + char buf[128]; + const jbyte *str; + + logFmsg(3, "logMessage() called."); + + str = (jbyte *) (*env)->GetStringUTFChars(env, msg, NULL); + if (str == NULL) + return; + + logFmsg(level, (char *) str); + + (*env)->ReleaseStringUTFChars(env, msg, (const char *) str); + + return; +} + +JNIEXPORT void JNICALL + Java_com_ashpool_continuity_ContRequest_startResponse(JNIEnv * env, + jclass class, + jint status) { + httpTtrans *t = httpFthread_gettrans(); + + logFmsg(3, "startResponse() called."); + + if (t == NULL) { + logFmsg(3, "mod/java: entrance thread had an orphaned context."); + return; + } + logFmsg(3, "Setting status to %d and starting..", status); + + httpFset_status(t, status, NULL); + httpFstart_response(t); + + return; +} + +JNIEXPORT void JNICALL + Java_com_ashpool_continuity_ContRequest_write__Ljava_lang_String_2 + (JNIEnv * env, jclass class, jstring strv) { + const jbyte *str; + httpTtrans *t = httpFthread_gettrans(); + + if (t == NULL) { + logFmsg(3, "mod/java: entrance thread had an orphaned context."); + return; + } + str = (jbyte *) (*env)->GetStringUTFChars(env, strv, NULL); + if (str == NULL) + return; + + httpFwrite(t, (char *) str, strlen(str)); + + (*env)->ReleaseStringUTFChars(env, strv, (const char *) str); + return; +} + + +/* Let them come - There is still one dwarf in Moria who yet draws breath */ + +/* + * Class: com_ashpool_continuity_ContRequest Method: glueObject + * Signature: (Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;)V + */ + +/* obj method name */ + +JNIEXPORT void JNICALL Java_com_ashpool_continuity_ContRequest_glueObject + (JNIEnv * env, jclass class, jobject obj, jstring method, + jstring name) { + + /* + * right now we don't support any other container systems, so we are going + * to go ahead and just set this object as the catalina connector in + * modjava. + */ + + /* javaFsetCatalinaConnector(env,obj); */ + + return; +} diff --git a/mk4/modjava/modjava.c b/mk4/modjava/modjava.c new file mode 100644 index 0000000..3eadea2 --- /dev/null +++ b/mk4/modjava/modjava.c @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2003 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Use, disclosure, copying, distribution, or transmission of this code without + * express permission is prohibited. + */ + +#include +#include +#include + +#define PATH_SEPARATOR ';' /* define it to be ':' on Solaris */ +#define USER_CLASSPATH "." /* where Prog.class is */ + +JNIEnv *javaGenv; +JavaVM *javaGjvm; + +JNIEnv *javaFcreate_vm(char *classpath); +int javaFrun_method(JNIEnv * env, const char *class, const char *method); +int javaFinit(void *p, lstTset * opts); + +int javaFinit(void *p, lstTset * opts) +{ + pthread_t tid; + char *classpath = lstFset_get(opts, "classpath"); + char *initclass = lstFset_get(opts, "initclass"); + char *initmethod = lstFset_get(opts, "initmethod"); + + logFmsg(0, "mod/java: Java Runtime Engine v1.0.0"); + logFmsg(0, "mod/java: Copyright (c) 2003, Alex Leigh"); + + if (classpath == NULL || initclass == NULL || initmethod == NULL) { + logFmsg(2, + "mod/java: javaFinit: classpath, initclass, and initmethod must be specified."); + exit(0); + } + javaGenv = javaFcreate_vm(classpath); + javaFrun_method(javaGenv, initclass, initmethod); + + return STATUS_OK; +} + +int javaFrun_method(JNIEnv * env, const char *class, const char *method) +{ + jclass cls; + jmethodID mid; + jstring jstr; + jclass stringClass; + jobjectArray args; + + cls = (*env)->FindClass(env, class); + if (cls == NULL) { + logFmsg(2, "mod/java: init class %s could not be loaded.", class); + exit(0); + } + mid = (*env)->GetStaticMethodID(env, cls, method, + "([Ljava/lang/String;)V"); + if (mid == NULL) { + logFmsg(2, "mod/java: init method %s.%s could not be loaded.", + class, method); + exit(0); + + } + jstr = (*env)->NewStringUTF(env, " from C!"); + if (jstr == NULL) { + + } + stringClass = (*env)->FindClass(env, "java/lang/String"); + args = (*env)->NewObjectArray(env, 1, stringClass, jstr); + if (args == NULL) { + + } + + (*env)->CallStaticVoidMethod(env, cls, mid, args); + + return STATUS_OK; +} + +JNIEnv *javaFcreate_vm(char *classpath) +{ + JNIEnv *env; + jint res; + jclass cls; + jmethodID mid; + jstring jstr; + jclass stringClass; + jobjectArray args; + char argbuf[512]; + +#ifdef JNI_VERSION_1_2 + JavaVMInitArgs vm_args; + JavaVMOption options[3]; + + sprintf(argbuf, "-Djava.class.path=%s", classpath); + + options[0].optionString = &argbuf; + options[1].optionString = "-Djava.security.policy=lib/java.policy"; + options[2].optionString = "-verbose:jni"; + vm_args.version = 0x00010002; + vm_args.options = options; + vm_args.nOptions = 3; + vm_args.ignoreUnrecognized = JNI_TRUE; + /* Create the Java VM */ + res = JNI_CreateJavaVM(&javaGjvm, (void **) &env, &vm_args); +#else + JDK1_1InitArgs vm_args; + char classpath[1024]; + vm_args.version = 0x00010001; + JNI_GetDefaultJavaVMInitArgs(&vm_args); + /* Append USER_CLASSPATH to the default system class path */ + sprintf(classpath, "%s%c%s", + vm_args.classpath, PATH_SEPARATOR, USER_CLASSPATH); + vm_args.classpath = classpath; + /* Create the Java VM */ + res = JNI_CreateJavaVM(&javaGjvm, &env, &vm_args); +#endif /* JNI_VERSION_1_2 */ + + if (res < 0) { + fprintf(stderr, "Can't create Java VM\n"); + exit(1); + } + return env; + + destroy: + if ((*env)->ExceptionOccurred(env)) { + (*env)->ExceptionDescribe(env); + } + (*javaGjvm)->DestroyJavaVM(javaGjvm); + + return NULL; +} + +int javaFservice(httpTtrans * t, lstTset * opts) +{ + jint res; + JNIEnv *env; + const char *class_arg = lstFset_get(opts, "class"); + const char *method_arg = lstFset_get(opts, "method"); + + logFmsg(3, "mod/java: service: Called."); + + if (class_arg == NULL || method_arg == NULL) { + logFmsg(2, + "mod/java: javaFservice: method or class not specified."); + return STATUS_ERROR; + } +#ifdef JNI_VERSION_1_2 + res = (*javaGjvm)->AttachCurrentThread(javaGjvm, (void **) &env, NULL); +#else + res = (*javaGjvm)->AttachCurrentThread(javaGjvm, &env, NULL); +#endif + + if (res < 0) { + logFmsg(2, "mod/java: thread attach to VM failed."); + return STATUS_ERROR; + } + + javaFrun_method(env, class_arg, method_arg); + return STATUS_EXIT; +} diff --git a/mk4/modjava/module.cfg b/mk4/modjava/module.cfg new file mode 100644 index 0000000..eae9d9c --- /dev/null +++ b/mk4/modjava/module.cfg @@ -0,0 +1,10 @@ +load shlib=./http.so +load shlib=/usr/j2se/jre/lib/sparc/libjvm.so +load shlib=./modjava.so + +init fn=httpFinit +init fn=javaFinit initclass=Prog initmethod=main classpath=/usr/j2se/lib/tools.jar:/datum01/users/aleigh/proj/java/tomcat/bin/bootstrap.jar:. +init fn=ipv4_dispatcher port=8990 handler=httpFhandler + +natr fn=javaFcatalina_service +natr fn=javaFservice method=handler class=Prog diff --git a/mk4/modm3/.rev b/mk4/modm3/.rev new file mode 100644 index 0000000..fd6d73e --- /dev/null +++ b/mk4/modm3/.rev @@ -0,0 +1 @@ +0.95 diff --git a/mk4/modm3/CVS/Entries b/mk4/modm3/CVS/Entries new file mode 100644 index 0000000..a1ed9bd --- /dev/null +++ b/mk4/modm3/CVS/Entries @@ -0,0 +1,4 @@ +/.rev/1.1/Tue Apr 27 06:31:52 2004//Tmk4_mod6_rc2 +/Makefile.in/1.1/Wed May 19 19:48:27 2004//Tmk4_mod6_rc2 +D/include//// +D/src//// diff --git a/mk4/modm3/CVS/Repository b/mk4/modm3/CVS/Repository new file mode 100644 index 0000000..827ba32 --- /dev/null +++ b/mk4/modm3/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/modm3 diff --git a/mk4/modm3/CVS/Root b/mk4/modm3/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/modm3/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/modm3/CVS/Tag b/mk4/modm3/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/modm3/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/modm3/Makefile.in b/mk4/modm3/Makefile.in new file mode 100644 index 0000000..9e8cc4f --- /dev/null +++ b/mk4/modm3/Makefile.in @@ -0,0 +1,22 @@ +CONTINUITY = ../continuity + +TARGET = m3 +TARGETTYPE = module + +SOURCES = src/m3.c src/ixtime.c src/support.c \ + src/queue_playlist_engine.c src/order_playlist_engine.c \ + src/randomlist_playlist_engine.c src/m3_tcl.c src/file_entry.c \ + src/music_packet.c src/file_reader.c src/mp3_reader.c src/mp3_frame.c \ + src/shoutcast_metadata_writer.c src/m3_client.c src/m3_server.c \ + src/m3_server_factory.c src/file_catalog.c src/playlist_engine_factory.c \ + src/playlist_manager.c + +INCLUDES += -Iinclude -I../lib/aura/include +LOCAL_CFLAGS += + +STATIC_LIBS += ../lib/aura/libaura.a + +include $(CONTINUITY)/lib/build.mk + +depend: + echo No depend. diff --git a/mk4/modm3/include/CVS/Entries b/mk4/modm3/include/CVS/Entries new file mode 100644 index 0000000..b9b69de --- /dev/null +++ b/mk4/modm3/include/CVS/Entries @@ -0,0 +1,24 @@ +/_build.h/1.1/Wed Apr 28 16:51:50 2004//Tmk4_mod6_rc2 +/file_catalog.h/1.1/Thu Apr 29 07:21:17 2004//Tmk4_mod6_rc2 +/file_entry.h/1.1/Tue Apr 27 06:31:52 2004//Tmk4_mod6_rc2 +/file_reader.h/1.1/Tue Apr 27 06:31:52 2004//Tmk4_mod6_rc2 +/idata_reader.h/1.2/Fri May 14 16:51:26 2004//Tmk4_mod6_rc2 +/iplaylist.h/1.3/Fri May 14 06:20:33 2004//Tmk4_mod6_rc2 +/ixtime.h/1.1/Tue Apr 27 06:31:52 2004//Tmk4_mod6_rc2 +/m3.h/1.6/Fri May 14 16:51:26 2004//Tmk4_mod6_rc2 +/m3_client.h/1.2/Fri May 14 16:51:26 2004//Tmk4_mod6_rc2 +/m3_server.h/1.4/Fri May 14 06:20:33 2004//Tmk4_mod6_rc2 +/m3_server_factory.h/1.1/Tue Apr 27 06:31:52 2004//Tmk4_mod6_rc2 +/m3_tcl.h/1.1/Tue Apr 27 06:31:52 2004//Tmk4_mod6_rc2 +/mp3_frame.h/1.1/Tue Apr 27 06:31:52 2004//Tmk4_mod6_rc2 +/mp3_reader.h/1.2/Fri May 14 16:51:26 2004//Tmk4_mod6_rc2 +/music_packet.h/1.1/Tue Apr 27 06:31:52 2004//Tmk4_mod6_rc2 +/order_playlist_engine.h/1.1/Tue Apr 27 06:31:52 2004//Tmk4_mod6_rc2 +/playlist.h/1.1/Tue Apr 27 06:31:52 2004//Tmk4_mod6_rc2 +/playlist_engine_factory.h/1.1/Thu Apr 29 07:21:17 2004//Tmk4_mod6_rc2 +/playlist_manager.h/1.3/Fri May 14 06:20:33 2004//Tmk4_mod6_rc2 +/queue_playlist_engine.h/1.2/Thu Apr 29 07:21:17 2004//Tmk4_mod6_rc2 +/randomlist_playlist_engine.h/1.2/Thu Apr 29 07:21:17 2004//Tmk4_mod6_rc2 +/shoutcast_metadata_writer.h/1.2/Fri May 14 16:51:26 2004//Tmk4_mod6_rc2 +/support.h/1.1/Tue Apr 27 06:31:52 2004//Tmk4_mod6_rc2 +D diff --git a/mk4/modm3/include/CVS/Repository b/mk4/modm3/include/CVS/Repository new file mode 100644 index 0000000..fa7af44 --- /dev/null +++ b/mk4/modm3/include/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/modm3/include diff --git a/mk4/modm3/include/CVS/Root b/mk4/modm3/include/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/modm3/include/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/modm3/include/CVS/Tag b/mk4/modm3/include/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/modm3/include/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/modm3/_build.h b/mk4/modm3/include/_build.h similarity index 100% rename from modm3/_build.h rename to mk4/modm3/include/_build.h diff --git a/modm3/file_catalog.h b/mk4/modm3/include/file_catalog.h similarity index 100% rename from modm3/file_catalog.h rename to mk4/modm3/include/file_catalog.h diff --git a/modm3/file_entry.h b/mk4/modm3/include/file_entry.h similarity index 100% rename from modm3/file_entry.h rename to mk4/modm3/include/file_entry.h diff --git a/modm3/file_reader.h b/mk4/modm3/include/file_reader.h similarity index 100% rename from modm3/file_reader.h rename to mk4/modm3/include/file_reader.h diff --git a/modm3/idata_reader.h b/mk4/modm3/include/idata_reader.h similarity index 100% rename from modm3/idata_reader.h rename to mk4/modm3/include/idata_reader.h diff --git a/mk4/modm3/include/iplaylist.h b/mk4/modm3/include/iplaylist.h new file mode 100644 index 0000000..9b9f432 --- /dev/null +++ b/mk4/modm3/include/iplaylist.h @@ -0,0 +1,25 @@ +#ifndef __IPLAYLIST_H__ +#define __IPLAYLIST_H__ + +#include "mecha.h" + +#include "iterator.h" + +typedef struct s_IPlaylist IPlaylist; + +struct s_IPlaylist +{ + void (*destroy) (IPlaylist *); + + const char * (*get_name) (IPlaylist *); + const char * (*get_type) (IPlaylist *); + + int (*get_next) (IPlaylist *); + bool (*add_file) (IPlaylist *, int fileid); + bool (*remove_file) (IPlaylist *, int fileid); + + IIterator * (*get_list_iterator) (IPlaylist *); + IIterator * (*get_next_iterator) (IPlaylist *); +}; + +#endif diff --git a/modm3/ixtime.h b/mk4/modm3/include/ixtime.h similarity index 100% rename from modm3/ixtime.h rename to mk4/modm3/include/ixtime.h diff --git a/mk4/modm3/include/m3.h b/mk4/modm3/include/m3.h new file mode 100644 index 0000000..c478405 --- /dev/null +++ b/mk4/modm3/include/m3.h @@ -0,0 +1,14 @@ +#ifndef __M3_H__ +#define __M3_H__ + +#include "mecha.h" + +const char * m3_get_songname (httpTtrans *trans); +int m3_get_skip_addr (httpTtrans *trans); +int m3_get_user_count (httpTtrans *trans); +void m3_skip_track (httpTtrans *trans); +bool m3_reload_playlist (httpTtrans *trans); + +bool m3_add_file (httpTtrans *trans, const char *playlist, const char *fileName); + +#endif diff --git a/mk4/modm3/include/m3_client.h b/mk4/modm3/include/m3_client.h new file mode 100644 index 0000000..f776ca2 --- /dev/null +++ b/mk4/modm3/include/m3_client.h @@ -0,0 +1,23 @@ + +#ifndef __M3_CLIENT_H__ +#define __M3_CLIENT_H__ + +#include "mecha.h" +#include "http.h" +#include "music_packet.h" + +typedef struct s_M3Client M3Client; + +M3Client * m3_client_new (httpTtrans *trans, bool wantMetadata, int metadataInterval); +void m3_client_destroy (void *ptr); + +const char * m3_client_ip_address_get (M3Client *instance); + +void m3_client_packet_add (M3Client *instance, MusicPacket *packet); + +void m3_client_process_request (M3Client *instance); + +void m3_client_metadata_set (M3Client *instance, const char *title, const char *url); + + +#endif diff --git a/mk4/modm3/include/m3_server.h b/mk4/modm3/include/m3_server.h new file mode 100644 index 0000000..82750c7 --- /dev/null +++ b/mk4/modm3/include/m3_server.h @@ -0,0 +1,32 @@ + +#ifndef __M3_SERVER_H__ +#define __M3_SERVER_H__ + +#include "mecha.h" +#include "m3_client.h" + +typedef struct s_M3Server M3Server; + +M3Server * m3_server_new (void); +void m3_server_destroy (void *ptr); + +bool m3_server_parse (M3Server *instance, const char *siteid, const xmlTtag *m3Tag); + +const char * m3_server_metadata_title_get (M3Server *instance); +const char * m3_server_metadata_url_get (M3Server *instance); +const char * m3_server_browser_url_get (M3Server *instance); +const char * m3_server_file_displayname_get (M3Server *instance); +const char * m3_server_mountpoint_get (M3Server *instance); +int m3_server_connected_clients (M3Server *instance); +int m3_server_skipped_ip_address (M3Server *instance); + +void m3_server_skip_track (M3Server *instance, httpTtrans *trans); + +bool m3_server_reload_playlist (M3Server *instance); + +void m3_server_client_add (M3Server *instance, M3Client *client); +void m3_server_client_remove (M3Server *instance, M3Client *client); + +bool m3_server_add_file (M3Server *instance, const char *playlist, const char *fileName); + +#endif diff --git a/modm3/m3_server_factory.h b/mk4/modm3/include/m3_server_factory.h similarity index 100% rename from modm3/m3_server_factory.h rename to mk4/modm3/include/m3_server_factory.h diff --git a/modm3/m3_tcl.h b/mk4/modm3/include/m3_tcl.h similarity index 100% rename from modm3/m3_tcl.h rename to mk4/modm3/include/m3_tcl.h diff --git a/modm3/mp3_frame.h b/mk4/modm3/include/mp3_frame.h similarity index 100% rename from modm3/mp3_frame.h rename to mk4/modm3/include/mp3_frame.h diff --git a/mk4/modm3/include/mp3_reader.h b/mk4/modm3/include/mp3_reader.h new file mode 100644 index 0000000..f9d1b13 --- /dev/null +++ b/mk4/modm3/include/mp3_reader.h @@ -0,0 +1,17 @@ + +#ifndef __MP3_READER_H__ +#define __MP3_READER_H__ + +#include "mecha.h" +#include "music_packet.h" + +typedef struct s_Mp3Reader Mp3Reader; + +Mp3Reader * mp3_reader_new (void); +void mp3_reader_destroy (void *ptr); + +bool mp3_reader_open (Mp3Reader *instance, const char *uri); + +MusicPacket * mp3_reader_get_packet (Mp3Reader *instance, int requestedUsecs); + +#endif diff --git a/mk4/modm3/include/music_packet.h b/mk4/modm3/include/music_packet.h new file mode 100644 index 0000000..9d73ab6 --- /dev/null +++ b/mk4/modm3/include/music_packet.h @@ -0,0 +1,25 @@ + +#ifndef __MUSIC_PACKET_H__ +#define __MUSIC_PACKET_H__ + +#include + +#include "mecha.h" + +typedef struct s_MusicPacket MusicPacket; + +MusicPacket * music_packet_new (void); +void music_packet_destroy (void *ptr); + +MusicPacket * music_packet_duplicate (MusicPacket *instance); + +dynTstring * music_packet_data_get (MusicPacket *instance); +struct timeval music_packet_time_length_get (MusicPacket *instance); + +void music_packet_time_length_add_usec (MusicPacket *instance, long usec); + +int music_packet_timestamp_get (MusicPacket *instance); + +int music_packet_time_length_usecs_get (MusicPacket *instance); + +#endif diff --git a/modm3/order_playlist_engine.h b/mk4/modm3/include/order_playlist_engine.h similarity index 100% rename from modm3/order_playlist_engine.h rename to mk4/modm3/include/order_playlist_engine.h diff --git a/mk4/modm3/include/playlist.h b/mk4/modm3/include/playlist.h new file mode 100644 index 0000000..a115527 --- /dev/null +++ b/mk4/modm3/include/playlist.h @@ -0,0 +1,61 @@ +#ifndef __PLAYLIST_H__ +#define __PLAYLIST_H__ + +#include "mecha.h" + +#include "file_entry.h" + +#define PLAYLIST_TYPE_ORDER 0x001 /* playlist is played in order (from filelist) */ +#define PLAYLIST_TYPE_RANDOM 0x002 /* playlist is played completely randomly (with possible duplicates) */ +#define PLAYLIST_TYPE_RANDOMLIST 0x004 /* playlist is played randomly without duplicates */ +#define PLAYLIST_TYPE_RANDOMWEIGHTED 0x008 /* playlist is played randomly with weighting (with possible duplicates) */ +#define PLAYLIST_TYPE_QUEUE 0x010 /* playlist is played once - files removed after playing */ + +#define PLAYLIST_OPTION_FILEBASED 0x020 /* playlist is attached to a file */ +#define PLAYLIST_OPTION_MEMORYBASED 0x040 /* playlist is attached to a file */ + +typedef struct +{ + char *name; + + int type; + int options; + + int offset; + int len; + FileEntry **list; + + lstTlist *filelist; +} playlist; + +typedef struct +{ + char *name; + + int type; + + FileEntry * (*get_next) (playlist *); + int (*add_file) (playlist *, FileEntry *file); + int (*remove_file) (playlist *, const char *filename); + int (*set_to_filelist) (playlist *, const char *file); + int (*peek) (int num_entries, int *out_num_entries, lstTlist **out_entries); + +} playlist_engine; + +void playlist_init (void); +void playlist_destroy (void *ptr); + +void playlist_engine_destroy (void *ptr); + +FileEntry * playlist_get_next (void); + +int playlist_create (const char *name, const char *type); +int playlist_delete (const char *name); + +int playlist_add_file (const char *playlistname, const char *file); +int playlist_add_fileglob (const char *playlistname, const char *file); +int playlist_add_filelist (const char *playlistname, const char *file); + +int playlist_reload_filelist (const char *playlistname, const char *file); + +#endif diff --git a/modm3/playlist_engine_factory.h b/mk4/modm3/include/playlist_engine_factory.h similarity index 100% rename from modm3/playlist_engine_factory.h rename to mk4/modm3/include/playlist_engine_factory.h diff --git a/mk4/modm3/include/playlist_manager.h b/mk4/modm3/include/playlist_manager.h new file mode 100644 index 0000000..f797532 --- /dev/null +++ b/mk4/modm3/include/playlist_manager.h @@ -0,0 +1,19 @@ + +#ifndef __PLAYLIST_MANAGER_H__ +#define __PLAYLIST_MANAGER_H__ + +#include "mecha.h" + +#include "file_entry.h" + +typedef struct s_PlaylistManager PlaylistManager; + +PlaylistManager * playlist_manager_new (void); +void playlist_manager_destroy (void *ptr); + +bool playlist_manager_add_playlist (PlaylistManager *instance, const char *playlistType, const char *playlistName); +bool playlist_manager_add_file (PlaylistManager *instance, const char *playlistName, const char *fileName); +bool playlist_manager_add_filelist (PlaylistManager *instance, const char *playlistName, const char *fileName); +FileEntry * playlist_manager_get_next_file_entry (PlaylistManager *instance); + +#endif diff --git a/modm3/queue_playlist_engine.h b/mk4/modm3/include/queue_playlist_engine.h similarity index 100% rename from modm3/queue_playlist_engine.h rename to mk4/modm3/include/queue_playlist_engine.h diff --git a/modm3/randomlist_playlist_engine.h b/mk4/modm3/include/randomlist_playlist_engine.h similarity index 100% rename from modm3/randomlist_playlist_engine.h rename to mk4/modm3/include/randomlist_playlist_engine.h diff --git a/modm3/shoutcast_metadata_writer.h b/mk4/modm3/include/shoutcast_metadata_writer.h similarity index 100% rename from modm3/shoutcast_metadata_writer.h rename to mk4/modm3/include/shoutcast_metadata_writer.h diff --git a/modm3/support.h b/mk4/modm3/include/support.h similarity index 100% rename from modm3/support.h rename to mk4/modm3/include/support.h diff --git a/mk4/modm3/src/.cvsignore b/mk4/modm3/src/.cvsignore new file mode 100644 index 0000000..39a0668 --- /dev/null +++ b/mk4/modm3/src/.cvsignore @@ -0,0 +1 @@ +.deps diff --git a/mk4/modm3/src/CVS/Entries b/mk4/modm3/src/CVS/Entries new file mode 100644 index 0000000..3c16eae --- /dev/null +++ b/mk4/modm3/src/CVS/Entries @@ -0,0 +1,22 @@ +/.cvsignore/1.1/Thu Apr 29 07:21:17 2004//Tmk4_mod6_rc2 +/file_catalog.c/1.1/Thu Apr 29 07:21:17 2004//Tmk4_mod6_rc2 +/file_entry.c/1.1/Tue Apr 27 06:31:52 2004//Tmk4_mod6_rc2 +/file_reader.c/1.2/Fri May 14 16:51:26 2004//Tmk4_mod6_rc2 +/ixtime.c/1.1/Tue Apr 27 06:31:52 2004//Tmk4_mod6_rc2 +/m3.c/1.4/Fri May 14 16:51:26 2004//Tmk4_mod6_rc2 +/m3_client.c/1.2/Fri May 14 16:51:26 2004//Tmk4_mod6_rc2 +/m3_server.c/1.2/Thu Apr 29 07:21:17 2004//Tmk4_mod6_rc2 +/m3_server_factory.c/1.2/Fri May 14 16:51:26 2004//Tmk4_mod6_rc2 +/m3_tcl.c/1.3/Fri May 14 16:51:26 2004//Tmk4_mod6_rc2 +/mp3_frame.c/1.1/Tue Apr 27 06:31:52 2004//Tmk4_mod6_rc2 +/mp3_reader.c/1.2/Fri May 14 16:51:26 2004//Tmk4_mod6_rc2 +/music_packet.c/1.1/Tue Apr 27 06:31:52 2004//Tmk4_mod6_rc2 +/order_playlist_engine.c/1.1/Tue Apr 27 06:31:52 2004//Tmk4_mod6_rc2 +/playlist.c/1.2/Thu Apr 29 07:21:17 2004//Tmk4_mod6_rc2 +/playlist_engine_factory.c/1.1/Thu Apr 29 07:21:17 2004//Tmk4_mod6_rc2 +/playlist_manager.c/1.2/Fri Apr 30 19:06:23 2004//Tmk4_mod6_rc2 +/queue_playlist_engine.c/1.2/Thu Apr 29 07:21:17 2004//Tmk4_mod6_rc2 +/randomlist_playlist_engine.c/1.3/Thu May 13 07:48:44 2004//Tmk4_mod6_rc2 +/shoutcast_metadata_writer.c/1.2/Fri May 14 16:51:26 2004//Tmk4_mod6_rc2 +/support.c/1.1/Tue Apr 27 06:31:52 2004//Tmk4_mod6_rc2 +D diff --git a/mk4/modm3/src/CVS/Repository b/mk4/modm3/src/CVS/Repository new file mode 100644 index 0000000..18c0311 --- /dev/null +++ b/mk4/modm3/src/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/modm3/src diff --git a/mk4/modm3/src/CVS/Root b/mk4/modm3/src/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/modm3/src/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/modm3/src/CVS/Tag b/mk4/modm3/src/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/modm3/src/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/modm3/src/file_catalog.c b/mk4/modm3/src/file_catalog.c new file mode 100644 index 0000000..3e59395 --- /dev/null +++ b/mk4/modm3/src/file_catalog.c @@ -0,0 +1,63 @@ + +#include + +#include "mecha.h" + +#include "file_entry.h" +#include "file_catalog.h" + +struct s_FileCatalog +{ + hshTvoid_list *file_by_id; + hshTvoid_list *file_by_filename; +}; + +FileCatalog * +file_catalog_new (void) +{ + FileCatalog *instance = (FileCatalog *) malloc (sizeof (FileCatalog)); + + instance->file_by_id = hshFvoid_int_init (file_entry_destroy); + instance->file_by_filename = hshFvoid_init (NULL); + + return (instance); +} + +void +file_catalog_destroy (void *ptr) +{ + FileCatalog *instance = (FileCatalog *) ptr; + + hshFvoid_destroy (instance->file_by_id); + hshFvoid_destroy (instance->file_by_filename); + + free (instance); +} + +int +file_catalog_get_fileid (FileCatalog *instance, const char *filename) +{ + FileEntry *entry; + + entry = (FileEntry *) hshFvoid_find (instance->file_by_filename, filename); + + if (entry == NULL) + { + entry = file_entry_new (filename); + + hshFvoid_add (instance->file_by_filename, filename, entry); + hshFvoid_int_add (instance->file_by_id, file_entry_get_fileno (entry), entry); + } + + return (file_entry_get_fileno (entry)); +} + +FileEntry * +file_catalog_get_file_entry (FileCatalog *instance, int fileId) +{ + FileEntry *entry; + + entry = (FileEntry *) hshFvoid_int_find (instance->file_by_id, fileId); + + return (entry); +} diff --git a/mk4/modm3/src/file_entry.c b/mk4/modm3/src/file_entry.c new file mode 100644 index 0000000..f019d7c --- /dev/null +++ b/mk4/modm3/src/file_entry.c @@ -0,0 +1,111 @@ + +#include + +#include "file_entry.h" + +#include "mecha.h" + +static char * file_entry_create_display_name (FileEntry *instance); + +static int g_file_sequence_counter = 0; + +struct s_FileEntry +{ + int fileno; + char * filename; + char * displayName; +}; + +FileEntry * +file_entry_new (const char *filename) +{ + FileEntry *instance = (FileEntry *) malloc (sizeof (FileEntry)); + + instance->fileno = g_file_sequence_counter++; + + instance->filename = strFcopy (filename); + + instance->displayName = file_entry_create_display_name ( + instance); + + return (instance); +} + +void +file_entry_destroy (void *ptr) +{ + FileEntry *instance = (FileEntry *) ptr; + + free (instance->filename); + + free (instance->displayName); + + free (instance); +} + +FileEntry * +file_entry_duplicate (FileEntry *instance) +{ + FileEntry *dest = (FileEntry *) malloc (sizeof (FileEntry)); + + dest->fileno = instance->fileno; + dest->filename = strFcopy (instance->filename); + dest->displayName = strFcopy (instance->displayName); + + return (dest); +} + +const char * +file_entry_get_filename (FileEntry *instance) +{ + return (instance->filename); +} + +const char * +file_entry_get_display_name (FileEntry *instance) +{ + return (instance->displayName); +} + +int +file_entry_get_fileno (FileEntry *instance) +{ + return (instance->fileno); +} + +static char * +file_entry_create_display_name (FileEntry *instance) +{ + const char *p, *q; + char *ret; + int len; + + p = strrchr (instance->filename, '/'); + + if (p != NULL) + { + p++; + } + else + { + p = instance->filename; + } + + q = strrchr (p, '.'); + + if (q) + { + len = q - p; + } + else + { + len = strlen (p); + } + + ret = (char *) malloc (len + 1); + memcpy (ret, p, len); + ret[len] = 0; + + return (ret); +} + diff --git a/mk4/modm3/src/file_reader.c b/mk4/modm3/src/file_reader.c new file mode 100644 index 0000000..b885d2d --- /dev/null +++ b/mk4/modm3/src/file_reader.c @@ -0,0 +1,395 @@ + +#include + +#include "mecha.h" + +#include "file_reader.h" + +#include "idata_reader.h" + +struct s_FileReader +{ + IDataReader reader; + + int fd; + + size_t start_offset; + size_t end_offset; + char *buffer; + size_t buffer_len; +}; + +static bool file_reader_read_exact (IDataReader *inst, char *buf, size_t count); +ssize_t file_reader_read_bytes (IDataReader *inst, char *buf, size_t count); +static bool file_reader_peek_bytes (IDataReader *inst, char *buf, size_t count); +ssize_t file_reader_seek_to_data (IDataReader *instance, const char *needle, size_t count); +static ssize_t file_reader_seek_to_data_func (IDataReader *inst, size_t count, int (*) (const char *ptr)); + +static bool file_reader_open (IDataReader *inst, const char *file); +static void file_reader_close (IDataReader *inst); + +FileReader * +file_reader_new (void) +{ + FileReader *instance = (FileReader *) malloc (sizeof (FileReader)); + + instance->reader.open = file_reader_open; + instance->reader.close = file_reader_close; + + instance->reader.read_exact = file_reader_read_exact; + instance->reader.read_bytes = file_reader_read_bytes; + instance->reader.peek_bytes = file_reader_peek_bytes; + instance->reader.seek_to_data = file_reader_seek_to_data; + instance->reader.seek_to_data_func = file_reader_seek_to_data_func; + + instance->reader.destroy = file_reader_destroy; + + instance->fd = -1; + + instance->start_offset = 0; + instance->end_offset = 0; + + instance->buffer_len = 1024; + instance->buffer = malloc (sizeof (char) * instance->buffer_len); + + return (instance); +} + +void +file_reader_destroy (void *ptr) +{ + FileReader *instance = (FileReader *) ptr; + + file_reader_close ((IDataReader *) instance); + + free (instance->buffer); + + free (instance); +} + +static bool +file_reader_open (IDataReader *inst, const char *file) +{ + FileReader *instance = (FileReader *) inst; + + instance->fd = open (file, O_RDONLY); + + if (instance->fd == -1) + { + return (false); + } + else + { + instance->start_offset = 0; + instance->end_offset = 0; + + return (true); + } +} + +static void +file_reader_close (IDataReader *inst) +{ + FileReader *instance = (FileReader *) inst; + + if (instance->fd != -1) + { + close (instance->fd); + } +} + +static size_t +file_reader_buffer_len_get (FileReader *instance) +{ + return (instance->end_offset - instance->start_offset); +} + +static int +file_reader_buffer_avail_len (FileReader *instance) +{ + return (instance->buffer_len - instance->end_offset); +} + +static char * +file_reader_buffer_get (FileReader *instance) +{ + return (instance->buffer + instance->start_offset); +} + +static bool +file_reader_buffer_populate (FileReader *instance, size_t minLen) +{ + if (minLen <= file_reader_buffer_len_get (instance)) + { + return (true); + } + else + { + int ret; + + if (file_reader_buffer_avail_len (instance) + file_reader_buffer_len_get (instance) < minLen) + { + size_t growAmount = 1024; + + if (minLen > growAmount) + { + growAmount = minLen; + } + + /* + * if we have more room at the start of the buffer that is unused + * than we're looking to grow by, we'll just move the buffer to + * the start. + */ + if (growAmount < instance->start_offset) + { + memmove (instance->buffer, instance->buffer + instance->start_offset, + instance->end_offset - instance->start_offset); + + instance->end_offset = instance->end_offset - instance->start_offset; + instance->start_offset = 0; + } + else + { + instance->buffer = realloc (instance->buffer, instance->buffer_len + growAmount); + instance->buffer_len += growAmount; + } + } + + while (file_reader_buffer_len_get (instance) < minLen) + { + ret = read (instance->fd, instance->buffer + instance->end_offset, + file_reader_buffer_avail_len (instance)); + + if (ret < 1) + { + return (false); + } + + instance->end_offset += ret; + } + + return (true); + } +} + +static bool +file_reader_buffer_copy (FileReader *instance, char *buf, size_t len) +{ + if (len > file_reader_buffer_len_get (instance)) + { + return (false); + } + else + { + memcpy (buf, file_reader_buffer_get (instance), len); + + instance->start_offset += len; + + if (instance->start_offset == instance->end_offset) + { + instance->start_offset = 0; + instance->end_offset = 0; + } + + return (true); + } +} + +static bool +file_reader_read_exact (IDataReader *inst, char *buf, size_t count) +{ + FileReader *instance = (FileReader *) inst; + + /* + * couldn't read the length we needed to, we have to fail -- we want to + * either read the length we were asked or fail. + */ + if (file_reader_buffer_populate (instance, count) == false) + { + return (false); + } + + if (file_reader_buffer_copy (instance, buf, count) == true) + { + return (true); + } + else + { + /* + * this can't fail -- we already checked that there was enough room to + * do this copy + */ + + abort(); + } +} + +ssize_t +file_reader_read_bytes (IDataReader *inst, char *buf, size_t count) +{ + FileReader *instance = (FileReader *) inst; + size_t buffer_len = 0; + + /* couldn't read even one byte -- we obviously are at the end */ + if (file_reader_buffer_populate (instance, 1) == false) + { + return (-1); + } + + /* figure out how much we want to read */ + buffer_len = file_reader_buffer_len_get (instance); + + if (count < buffer_len) + { + buffer_len = count; + } + + if (file_reader_buffer_copy (instance, buf, buffer_len) == true) + { + return (buffer_len); + } + else + { + /* + * this can't fail -- we already checked that there was enough room to + * do this copy + */ + + abort(); + } +} + +static bool +file_reader_peek_bytes (IDataReader *inst, char *buf, size_t count) +{ + FileReader *instance = (FileReader *) inst; + + /* make sure the buffer has at least the number of bytes we need */ + if (file_reader_buffer_populate (instance, count) == false) + { + return (false); + } + + memcpy (buf, file_reader_buffer_get (instance), count); + + return (true); +} + +static ssize_t +file_reader_seek_to_data_func (IDataReader *inst, size_t count, int (*compare_func) (const char *)) +{ + FileReader *instance = (FileReader *) inst; + int skippedBytes = 0; + + assert (count > 0); + + if (count < 1) + { + return (-1); + } + + while (true) + { + /* make sure we have at least the number of bytes we're looking for */ + if (file_reader_buffer_populate (instance, count) == false) + { + return (-1); + } + + if (compare_func (file_reader_buffer_get (instance)) == 0) + { + /* + * if we found it, start_offset is correct, and everything is + * happy + */ + + return (skippedBytes); + } + else + { + instance->start_offset++; + skippedBytes++; + } + } +} + +ssize_t +file_reader_seek_to_data (IDataReader *inst, const char *needle, size_t count) +{ + FileReader *instance = (FileReader *) inst; + int skippedBytes = 0; + + assert (count > 0); + + if (count < 1) + { + return (-1); + } + + while (true) + { + char *ptr; + + /* make sure we have at least the number of bytes we're looking for */ + if (file_reader_buffer_populate (instance, count) == false) + { + return (-1); + } + + ptr = memchr (file_reader_buffer_get (instance), needle[0], file_reader_buffer_len_get (instance)); + + if (ptr != NULL) + { + int new_start_offset = ptr - instance->buffer; + + skippedBytes += new_start_offset - instance->start_offset; + + instance->start_offset = new_start_offset; + + /* + * if we don't have enough bytes in the buffer, we'll just do this + * again (which will force enough bytes on the buffer) + */ + if (file_reader_buffer_len_get (instance) < count) + { + continue; + } + + if (memcmp (ptr, needle, count) == 0) + { + /* + * if we found it, start_offset is correct, and everything is + * happy + */ + + return (skippedBytes); + } + else + { + /* + * if we didn't find it, so we'll skip one more byte so that + * the next time around, we'll be searching the rest of the + * data. + */ + + skippedBytes++; + instance->start_offset++; + + continue; + } + } + else + { + /* + * if we didn't find the first byte anywhere.. we'll have to ditch + * this buffer and try for another one + */ + skippedBytes += instance->end_offset - instance->start_offset; + + instance->start_offset = 0; + instance->end_offset = 0; + } + } +} + diff --git a/modm3/ixtime.c b/mk4/modm3/src/ixtime.c similarity index 100% rename from modm3/ixtime.c rename to mk4/modm3/src/ixtime.c diff --git a/mk4/modm3/src/m3.c b/mk4/modm3/src/m3.c new file mode 100644 index 0000000..867239f --- /dev/null +++ b/mk4/modm3/src/m3.c @@ -0,0 +1,275 @@ + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mecha.h" +#include "site.h" +#include "continuity.h" +#include "modtcl.h" + +#include "ixtime.h" +#include "support.h" + +#include "_build.h" + +#include "m3_tcl.h" + +#include "m3.h" +#include "mp3_reader.h" + +#include "m3_server.h" +#include "m3_client.h" + +#include "m3_server.h" +#include "m3_server_factory.h" + +static M3Server * m3_get_server (httpTtrans *trans, const char *uri); + + + +int m3_client (httpTtrans *t, lstTset *opts); + +#define METADISTANCE (10 * 1024) + +static M3Server * +m3_get_this_server (httpTtrans *trans) +{ + const char *uri = lstFset_get (trans->vars, "uri"); + + assert (trans != NULL); + + if (uri == NULL) + { + return (NULL); + } + + return (m3_get_server (trans, uri)); +} + +static M3Server * +m3_get_server (httpTtrans *trans, const char *uri) +{ + const char *siteid = lstFset_get (trans->vars, "siteid"); + M3ServerFactory *serverFactory; + + assert (trans != NULL); + assert (uri != NULL); + assert (siteid != NULL); + + if (siteid == NULL) + { + return (NULL); + } + + serverFactory = (M3ServerFactory *) siteFsite_data_get (siteid, "m3"); + + if (serverFactory == NULL) + { + serverFactory = m3_server_factory_new (siteid); + + siteFsite_data_set (siteid, "m3", serverFactory); + } + + return (m3_server_factory_find_mountpoint (serverFactory, uri)); +} + +static bool +m3_is_browser_connection (httpTtrans *trans) +{ + const char *user_agent = lstFset_iget (trans->req_hdrs, "user-agent"); + + if (user_agent == NULL) + { + return (false); + } + + + if (strFcasestr (user_agent, "mozilla") || strFcasestr (user_agent, "lynx")) + { + return (true); + } + else + { + return (false); + } +} + + +int +m3_client (httpTtrans *t, MECHA_UNUSED_ARGUMENT lstTset *opts) +{ + const char *metac; + bool wantmeta = false; + M3Client *client; + M3Server *server; + + server = m3_get_this_server (t); + + if (server == NULL) + { + return (STATUS_PROCEED); + } + + if (m3_is_browser_connection (t) == true) + { + if (m3_server_browser_url_get (server) != NULL) + { + return (httpFredirect (t, m3_server_browser_url_get (server))); + } + } + + httpFset_nph (t); + + if ((metac = lstFset_iget (t->req_hdrs, "Icy-MetaData"))) + { + wantmeta = atoi (metac); + } + + httpFwritef (t, "HTTP/1.0 200 HAPPY HAPPY\r\n"); + httpFwritef (t, "icy-notice1:continuity/m3 v%s - http://5stops.com/m3/\r\n", _L_BUILDREV); + httpFwritef (t, "icy-name:%s\r\n", m3_server_metadata_title_get (server)); + httpFwritef (t, "icy-pub:0\r\n"); + httpFwritef (t, "icy-genre:mixed\r\n"); + httpFwritef (t, "icy-url:%s\r\n", m3_server_metadata_url_get (server)); + + if (wantmeta) + { + httpFwritef (t, "icy-metaint:%d\r\n", METADISTANCE); + } + + httpFwrite (t, "\r\n", 2); + + client = m3_client_new (t, wantmeta, METADISTANCE); + + m3_server_client_add (server, client); + + logFmsg (CONT_LOG_OK, "%s: starting stream // connected clients: %d", + m3_client_ip_address_get (client), m3_server_connected_clients (server)); + + m3_client_process_request (client); + + m3_server_client_remove (server, client); + + logFmsg (CONT_LOG_OK, "%s: closing stream // connected clients: %d", + m3_client_ip_address_get (client), m3_server_connected_clients (server)); + + m3_client_destroy (client); + + return (STATUS_EXIT); +} + +static bool +ensure_httpFwrite (httpTtrans * t, const char *buf, size_t len) +{ + ssize_t ret; + + ret = ensure_httpFwrite (t, buf, len); + + if (ret != (ssize_t) len) + { + return (false); + } + else + { + return (true); + } +} + +/* + * ---------------------------------------------------------- + * TCL HELPERS + * ---------------------------------------------------------- + */ + +const char * +m3_get_songname (httpTtrans *trans) +{ + M3Server *server = m3_get_server (trans, "/"); + + if (server == NULL) + { + return ("(none)"); + } + else + { + return (m3_server_file_displayname_get (server)); + } +} + +int +m3_get_skip_addr (httpTtrans *trans) +{ + M3Server *server = m3_get_server (trans, "/"); + + if (server == NULL) + { + return (0); + } + else + { + return (m3_server_skipped_ip_address (server)); + } +} + +int +m3_get_user_count (httpTtrans *trans) +{ + M3Server *server = m3_get_server (trans, "/"); + + if (server == NULL) + { + return (0); + } + else + { + return (m3_server_connected_clients (server)); + } +} + +bool +m3_add_file (httpTtrans *trans, const char *playlist, const char *fileName) +{ + M3Server *server = m3_get_server (trans, "/"); + + if (server == NULL) + { + return (false); + } + else + { + return (m3_server_add_file (server, playlist, fileName)); + } +} + +void +m3_skip_track (httpTtrans *trans) +{ + M3Server *server = m3_get_server (trans, "/"); + + if (server != NULL) + { + m3_server_skip_track (server, trans); + } +} + +bool +m3_reload_playlist (httpTtrans *trans) +{ + M3Server *server = m3_get_server (trans, "/"); + + if (server == NULL) + { + return (0); + } + else + { + return (m3_server_reload_playlist (server)); + } +} diff --git a/mk4/modm3/src/m3_client.c b/mk4/modm3/src/m3_client.c new file mode 100644 index 0000000..c5abea4 --- /dev/null +++ b/mk4/modm3/src/m3_client.c @@ -0,0 +1,134 @@ + +#include + +#include "m3_client.h" +#include "music_packet.h" +#include "shoutcast_metadata_writer.h" + +/* the maximum ip addr size including the null */ +#define MAX_IP_ADDR_SIZE 16 + +struct s_M3Client +{ + httpTtrans *trans; + + char ipAddress[MAX_IP_ADDR_SIZE]; + + lstTlist *messages; + + pthread_mutex_t messagesMutex; + pthread_cond_t messagesCond; + + ShoutcastMetadataWriter *metadataWriter; +}; + +M3Client * +m3_client_new (httpTtrans *trans, bool wantMetadata, int metadataInterval) +{ + M3Client *instance = (M3Client *) malloc (sizeof (M3Client)); + + instance->trans = trans; + + utlFip_to_str (trans->cli_ipv4_addr, instance->ipAddress, MAX_IP_ADDR_SIZE); + + instance->messages = lstFlist_create (music_packet_destroy); + + pthread_mutex_init (&instance->messagesMutex, 0); + pthread_cond_init (&instance->messagesCond, 0); + + instance->metadataWriter = shoutcast_metadata_writer_new (trans, wantMetadata, metadataInterval); + + return (instance); +} + +void +m3_client_destroy (void *ptr) +{ + M3Client *instance = (M3Client *) ptr; + + pthread_cond_destroy (&instance->messagesCond); + pthread_mutex_destroy (&instance->messagesMutex); + + lstFlist_free (instance->messages); + + shoutcast_metadata_writer_destroy (instance->metadataWriter); + + free (instance); +} + +const char * +m3_client_ip_address_get (M3Client *instance) +{ + return (instance->ipAddress); +} + +static void +m3_client_trim_old_messages (M3Client *instance) +{ + if (lstFlist_size (instance->messages) > 0) + { + MusicPacket *oldestPacket = (MusicPacket *) lstFlist_data (lstFlist_tail (instance->messages)); + + if (time(0) > music_packet_timestamp_get (oldestPacket) + 6) + { + logFmsg (CONT_LOG_WARN, "%s: too far behind -- clearing queue of %d packets.", + instance->ipAddress, lstFlist_size (instance->messages)); + + while (lstFlist_size (instance->messages) > 0) + { + lstFlist_remove (instance->messages, lstFlist_tail (instance->messages), (void **) &oldestPacket); + + music_packet_destroy (oldestPacket); + } + } + } +} + +void +m3_client_packet_add (M3Client *instance, MusicPacket *packet) +{ + pthread_mutex_lock (&instance->messagesMutex); + + m3_client_trim_old_messages (instance); + + lstFlist_add_prev (instance->messages, lstFlist_head (instance->messages), packet); + + pthread_cond_signal (&instance->messagesCond); + pthread_mutex_unlock (&instance->messagesMutex); +} + +void +m3_client_metadata_set (M3Client *instance, const char *title, const char *url) +{ + shoutcast_metadata_writer_set_metadata (instance->metadataWriter, title, url); +} + +void +m3_client_process_request (M3Client *instance) +{ + while (true) + { + MusicPacket *packet; + + pthread_mutex_lock (&instance->messagesMutex); + + if (lstFlist_size (instance->messages) == 0) + { + pthread_cond_wait (&instance->messagesCond, &instance->messagesMutex); + } + + lstFlist_remove (instance->messages, lstFlist_tail (instance->messages), (void **) &packet); + + pthread_mutex_unlock (&instance->messagesMutex); + + if (shoutcast_metadata_writer_write (instance->metadataWriter, + music_packet_data_get (packet)) == false) + { + music_packet_destroy (packet); + + break; + } + + music_packet_destroy (packet); + } +} diff --git a/mk4/modm3/src/m3_server.c b/mk4/modm3/src/m3_server.c new file mode 100644 index 0000000..3a8ad44 --- /dev/null +++ b/mk4/modm3/src/m3_server.c @@ -0,0 +1,481 @@ + +#include +#include + +#include +#include "ixtime.h" + +#include "mp3_reader.h" + +#include "m3_server.h" +#include "file_entry.h" + +#include "m3_client.h" + +#include "playlist_manager.h" + +#if 0 +#include "playlist.h" +#endif + +#include "m3_tcl.h" + +struct s_M3Server +{ + const char *siteid; + + const char *mountpoint; + const char *browserUrl; + const char *metadataTitle; + const char *metadataUrl; + + PlaylistManager *playlistManager; + + FileEntry *currentFile; + pthread_rwlock_t currentFileLock; + + bool skipToNext; + + long ipAddressHitNext; + + const char *playlistFile; + + lstTlist *clientlist; + pthread_mutex_t clientlistMutex; + pthread_cond_t clientlistCond; +}; + + +static void * m3_server_process (void *ptr); +static bool m3_server_init (M3Server *instance); + +static void m3_server_broadcast_metadata (M3Server *instance, const char *title, const char *url); +static void m3_server_broadcast_packet (M3Server *instance, MusicPacket *packet); + +M3Server * +m3_server_new (void) +{ + M3Server *instance = (M3Server *) malloc (sizeof (M3Server)); + + instance->mountpoint = NULL; + instance->browserUrl = NULL; + instance->metadataTitle = NULL; + instance->metadataUrl = NULL; + + instance->playlistManager = playlist_manager_new(); + + instance->currentFile = NULL; + pthread_rwlock_init (&instance->currentFileLock, 0); + + instance->skipToNext = false; + + instance->ipAddressHitNext = 0; + + instance->playlistFile = NULL; + + instance->clientlist = lstFlist_create (m3_client_destroy); + + pthread_mutex_init (&instance->clientlistMutex, 0); + pthread_cond_init (&instance->clientlistCond, 0); + + return (instance); +} + +void +m3_server_destroy (void *ptr) +{ + M3Server *instance = (M3Server *) ptr; + + playlist_manager_destroy (instance->playlistManager); + + lstFlist_free (instance->clientlist); + + pthread_mutex_destroy (&instance->clientlistMutex); + pthread_cond_destroy (&instance->clientlistCond); + + free (instance); +} + +/* + * Example XML chunk: + * + * + * /home/eric/src/music.m3u + * /m3/ + * + * 5stops/radio + * http://stream.5stops.com/m3/currently_playing.html + * + * + */ + +bool +m3_server_parse (M3Server *instance, const char *siteid, const xmlTtag *m3Tag) +{ + instance->siteid = siteid; + + instance->mountpoint = xmlFtag_get_attrib_value (m3Tag, "mountpoint"); + + if (instance->mountpoint == NULL) + { + logFmsg (CONT_LOG_ERROR, "mod/m3: A mountpoint must be specified."); + + return (false); + } + + instance->playlistFile = xmlFfirst_child_value_str (m3Tag, "playlist"); + + if (instance->playlistFile == NULL) + { + logFmsg (CONT_LOG_ERROR, "mod/m3: %s:%s: A playlist must be specified.", + instance->siteid, instance->mountpoint); + + return (false); + } + + instance->browserUrl = xmlFfirst_child_value_str (m3Tag, "browserUrl"); + + { + const xmlTtag *metadataTag = xmlFfind_first_child (m3Tag, "shoutcastMetadata"); + + if (metadataTag != NULL) + { + instance->metadataTitle = xmlFfirst_child_value_str (metadataTag, "title"); + instance->metadataUrl = xmlFfirst_child_value_str (metadataTag, "url"); + } + } + + return (m3_server_init (instance)); +} + +static bool +m3_server_init (M3Server *instance) +{ + pthread_t thread; + + /* BUGBUG: This should be pulled from the config file */ + playlist_manager_add_playlist (instance->playlistManager, "queue", "preempt"); + playlist_manager_add_playlist (instance->playlistManager, "randomlist", "general"); + + if (playlist_manager_add_filelist (instance->playlistManager, "general", instance->playlistFile)) + { + logFmsg (CONT_LOG_OK, "mod/m3: %s:%s: Added filelist: %s", + instance->siteid, instance->mountpoint, instance->playlistFile); + } + else + { + logFmsg (CONT_LOG_ERROR, "mod/m3: %s:%s: Could not add filelist: %s", + instance->siteid, instance->mountpoint, instance->playlistFile); + + return (false); + } + + m3_tcl_init(); + + if (pthread_create (&thread, 0, m3_server_process, instance) != 0) + { + logFmsg (CONT_LOG_ERROR, "mod/m3: %s:%s: pthread_create: %s", + instance->siteid, instance->mountpoint, strerror (errno)); + + return (false); + } + + return (true); +} + +const char * +m3_server_metadata_title_get (M3Server *instance) +{ + return (instance->metadataTitle); +} + +const char * +m3_server_metadata_url_get (M3Server *instance) +{ + return (instance->metadataUrl); +} + +const char * +m3_server_browser_url_get (M3Server *instance) +{ + return (instance->browserUrl); +} + +const char * +m3_server_mountpoint_get (M3Server *instance) +{ + return (instance->mountpoint); +} + +int +m3_server_skipped_ip_address (M3Server *instance) +{ + return (instance->ipAddressHitNext); +} + +void +m3_server_skip_track (M3Server *instance, httpTtrans *trans) +{ + instance->skipToNext = true; + instance->ipAddressHitNext = trans->cli_ipv4_addr; +} + +int +m3_server_connected_clients (M3Server *instance) +{ + int count; + + pthread_mutex_lock (&instance->clientlistMutex); + + count = lstFlist_size (instance->clientlist); + + pthread_mutex_unlock (&instance->clientlistMutex); + + return (count); +} + +bool +m3_server_reload_playlist (MECHA_UNUSED_ARGUMENT M3Server *instance) +{ +#if 0 + if (playlist_reload_filelist ("general", instance->playlistFile) == 0) + { + return (true); + } + else + { + return (false); + } +#endif + + logFmsg (CONT_LOG_ERROR, "mod/m3: m3_server_reload_playlist needs to be implemented."); + + return (false); +} + +bool +m3_server_add_file (M3Server *instance, const char *playlist, const char *fileName) +{ + return (playlist_manager_add_file (instance->playlistManager, playlist, fileName)); +} + +void +m3_server_client_add (M3Server *instance, M3Client *client) +{ + pthread_mutex_lock (&instance->clientlistMutex); + + lstFlist_add_next (instance->clientlist, lstFlist_head (instance->clientlist), client); + + pthread_cond_signal (&instance->clientlistCond); + + tasFstat_set ((char *) "m3", 0, (char *) "users", lstFlist_size (instance->clientlist)); + + pthread_mutex_unlock (&instance->clientlistMutex); + + /* + * This will send an update notification to all clients, allowing the + * mini-browser to update, showing the current number of connected users + */ + m3_server_broadcast_metadata (instance, m3_server_file_displayname_get (instance), instance->metadataUrl); +} + +void +m3_server_client_remove (M3Server *instance, M3Client *client) +{ + lstTlist_elem *eptr; + + pthread_mutex_lock (&instance->clientlistMutex); + + for (eptr = lstFlist_head (instance->clientlist); eptr; eptr = lstFlist_next (eptr)) + { + if (client == lstFlist_data (eptr)) + { + lstFlist_remove (instance->clientlist, eptr, (void **) 0); + + tasFstat_set ((char *) "m3", 0, (char *) "users", lstFlist_size (instance->clientlist)); + + break; + } + } + + pthread_mutex_unlock (&instance->clientlistMutex); + + /* + * This will send an update notification to all clients, allowing the + * mini-browser to update, showing the current number of connected users + */ + m3_server_broadcast_metadata (instance, m3_server_file_displayname_get (instance), instance->metadataUrl); +} + +static void +m3_server_wait_for_clients (M3Server *instance) +{ + pthread_mutex_lock (&instance->clientlistMutex); + + if (lstFlist_size (instance->clientlist) == 0) + { + pthread_cond_wait (&instance->clientlistCond, &instance->clientlistMutex); + } + + pthread_mutex_unlock (&instance->clientlistMutex); +} + +static void +m3_server_get_next_file (M3Server *instance) +{ + pthread_rwlock_wrlock (&instance->currentFileLock); + + while ((instance->currentFile = playlist_manager_get_next_file_entry (instance->playlistManager)) == NULL) + { + thrFsleep (1000); + } + + pthread_rwlock_unlock (&instance->currentFileLock); +} + +const char * +m3_server_file_displayname_get (M3Server *instance) +{ + const char *name; + + pthread_rwlock_rdlock (&instance->currentFileLock); + + if (instance->currentFile != NULL) + { + name = file_entry_get_display_name (instance->currentFile); + } + else + { + name = ""; + } + + pthread_rwlock_unlock (&instance->currentFileLock); + + return (name); +} + +static void * +m3_server_process (void *ptr) +{ + M3Server *instance = (M3Server *) ptr; + struct timeval curtv; + bool playing = false; + Mp3Reader *mp3Reader = NULL; + + logFmsg (CONT_LOG_OK, "mod/m3: %s:%s: spinning up", + instance->siteid, instance->mountpoint); + + gettimeofday (&curtv, 0); + + while (true) + { + MusicPacket *packet; + + if (playing == false) + { + m3_server_get_next_file (instance); + + mp3Reader = mp3_reader_new(); + + if (mp3_reader_open (mp3Reader, file_entry_get_filename (instance->currentFile)) == false) + { + logFmsg (CONT_LOG_ERROR, "mod/m3: Could not open file: %s", + file_entry_get_filename (instance->currentFile)); + + mp3_reader_destroy (mp3Reader); + + continue; + } + + m3_server_wait_for_clients (instance); + + logFmsg (CONT_LOG_OK, "playing %s", file_entry_get_filename (instance->currentFile)); + + m3_server_broadcast_metadata (instance, m3_server_file_displayname_get (instance), + instance->metadataUrl); + + playing = true; + gettimeofday (&curtv, 0); + } + + if (instance->skipToNext == false) + { + packet = mp3_reader_get_packet (mp3Reader, 200000L); + } + else + { + packet = NULL; + } + + if (packet == NULL) + { + mp3_reader_destroy (mp3Reader); + + if (instance->skipToNext == false) + { + instance->ipAddressHitNext = 0; + } + + playing = false; + instance->skipToNext = false; + + continue; + } + + m3_server_broadcast_packet (instance, packet); + + { + struct timeval t1, t2, tsl, tdiff, twait, temptv; + + struct timeval packet_length = music_packet_time_length_get (packet); + + gettimeofday (&t1, 0); + timeval_add (&temptv, &curtv, &packet_length); /* add how long we want to sleep to the last run time */ + timeval_subtract (&twait, &temptv, &t1); /* subtract where we want to end up from where we are */ + + thrFsleep (timeval_to_ms (&twait)); + + gettimeofday (&t2, 0); + timeval_subtract (&tsl, &t2, &t1); /* get how long it took */ + timeval_subtract (&tdiff, &tsl, &twait); /* get the difference between how long it should and how long it did */ + timeval_subtract (&curtv, &t2, &tdiff); /* sent curtime to the last gettimeofday minus how long it shouldn't have taken */ + } + + music_packet_destroy (packet); + } +} + +static void +m3_server_broadcast_metadata (M3Server *instance, const char *title, const char *url) +{ + lstTlist_elem *ep; + + pthread_mutex_lock (&instance->clientlistMutex); + + for (ep = lstFlist_head (instance->clientlist); ep; ep = lstFlist_next (ep)) + { + M3Client *client = (M3Client *) lstFlist_data (ep); + + m3_client_metadata_set (client, title, url); + } + + pthread_mutex_unlock (&instance->clientlistMutex); +} + +static void +m3_server_broadcast_packet (M3Server *instance, MusicPacket *packet) +{ + lstTlist_elem *ep; + + pthread_mutex_lock (&instance->clientlistMutex); + + for (ep = lstFlist_head (instance->clientlist); ep; ep = lstFlist_next (ep)) + { + MusicPacket *newPacket = music_packet_duplicate (packet); + M3Client *client = (M3Client *) lstFlist_data (ep); + + m3_client_packet_add (client, newPacket); + } + + pthread_mutex_unlock (&instance->clientlistMutex); +} diff --git a/mk4/modm3/src/m3_server_factory.c b/mk4/modm3/src/m3_server_factory.c new file mode 100644 index 0000000..b518a42 --- /dev/null +++ b/mk4/modm3/src/m3_server_factory.c @@ -0,0 +1,109 @@ + +#include + +#include "site.h" + +#include "m3_server_factory.h" +#include "m3_server.h" + +struct s_M3ServerFactory +{ + lstTlist *serverlist; +}; + +static void m3_server_factory_parse (M3ServerFactory *instance, const char *siteid); + +M3ServerFactory * +m3_server_factory_new (const char *siteid) +{ + M3ServerFactory *instance = (M3ServerFactory *) malloc (sizeof (M3ServerFactory)); + + instance->serverlist = lstFlist_create (m3_server_destroy); + + m3_server_factory_parse (instance, siteid); + + return (instance); +} + +void +m3_server_factory_destroy (void *ptr) +{ + M3ServerFactory *instance = (M3ServerFactory *) ptr; + + lstFlist_free (instance->serverlist); + + free (instance); +} + +M3Server * +m3_server_factory_find_mountpoint (M3ServerFactory *instance, const char *mountpoint) +{ + lstTlist_elem *ep; + + for (ep = lstFlist_head (instance->serverlist); ep; ep = lstFlist_next (ep)) + { + M3Server *server = (M3Server *) lstFlist_data (ep); + + if (strcmp (m3_server_mountpoint_get (server), mountpoint) == 0) + { + return (server); + } + } + + return (NULL); +} + +static void +m3_server_factory_add (M3ServerFactory *instance, M3Server *server) +{ + lstFlist_add_next (instance->serverlist, lstFlist_tail (instance->serverlist), server); +} + +static void +m3_server_factory_parse (M3ServerFactory *instance, const char *siteid) +{ + const xmlTtag *config = siteFconfig_get_by_siteid (siteid); + xmlTiterator *iter; + const xmlTtag *tag; + + if (config == NULL) + { + return; + } + + iter = xmlFiterator_init (config); + + if (iter == NULL) + { + return; + } + + while ((tag = xmlFiterator_next_name (iter, "m3")) != NULL) + { + M3Server *server = m3_server_new(); + + if (m3_server_parse (server, siteid, tag) == true) + { + if (m3_server_factory_find_mountpoint (instance, m3_server_mountpoint_get (server)) == NULL) + { + m3_server_factory_add (instance, server); + } + else + { + logFmsg (CONT_LOG_ERROR, "mod/m3: Found a duplicate mountpoint for site %s: %s", + siteid, m3_server_mountpoint_get (server)); + + m3_server_destroy (server); + } + } + else + { + logFmsg (CONT_LOG_ERROR, "mod/m3: Could not parse m3 entry for site %s", + siteid); + + m3_server_destroy (server); + } + } + + xmlFiterator_free (iter); +} diff --git a/mk4/modm3/src/m3_tcl.c b/mk4/modm3/src/m3_tcl.c new file mode 100644 index 0000000..25d0bbb --- /dev/null +++ b/mk4/modm3/src/m3_tcl.c @@ -0,0 +1,131 @@ + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mecha.h" +#include "continuity.h" +#include "modtcl.h" + +#include "m3.h" + +#include "m3_tcl.h" + +static int m3_tcl_get_loser (ClientData ignored, Tcl_Interp *interp, int argc, char **argv); +static int m3_tcl_get_displayname (ClientData ignored, Tcl_Interp *interp, int argc, char **argv); +static int m3_tcl_skip_track (ClientData ignored, Tcl_Interp *interp, int argc, char **argv); +static int m3_tcl_get_users (ClientData ignored, Tcl_Interp *interp, int argc, char **argv); +static int m3_tcl_add_track (ClientData ignored, Tcl_Interp *interp, int argc, char **argv); +static int m3_tcl_reload_playlist (ClientData ignored, Tcl_Interp *interp, int argc, char **argv); + +void +m3_tcl_init() +{ + tclFbind_dyn_command ((char *) "m3_get_displayname", &m3_tcl_get_displayname); + tclFbind_dyn_command ((char *) "m3_skip_track", &m3_tcl_skip_track); + tclFbind_dyn_command ((char *) "m3_get_users", &m3_tcl_get_users); + tclFbind_dyn_command ((char *) "m3_get_loser", &m3_tcl_get_loser); + tclFbind_dyn_command ((char *) "m3_add_track", &m3_tcl_add_track); + tclFbind_dyn_command ((char *) "m3_reload_playlist", &m3_tcl_reload_playlist); +} + +static int +m3_tcl_get_loser (MECHA_UNUSED_ARGUMENT ClientData ignored, Tcl_Interp *interp, + MECHA_UNUSED_ARGUMENT int argc, MECHA_UNUSED_ARGUMENT char **argv) +{ + httpTtrans *trans = httpFthread_gettrans(); + + if (m3_get_skip_addr (trans)) + { + char *ip = Tcl_Alloc (17); + + utlFip_to_str (m3_get_skip_addr (trans), ip, 16); + Tcl_SetResult (interp, ip, TCL_DYNAMIC); + } + + return (TCL_OK); +} + +static int +m3_tcl_get_displayname (MECHA_UNUSED_ARGUMENT ClientData ignored, + Tcl_Interp *interp, MECHA_UNUSED_ARGUMENT int argc, + MECHA_UNUSED_ARGUMENT char **argv) +{ + Tcl_AppendResult (interp, m3_get_songname (httpFthread_gettrans()), (char *) NULL); + + return (TCL_OK); +} + +static int +m3_tcl_get_users (MECHA_UNUSED_ARGUMENT ClientData ignored, Tcl_Interp *interp, + MECHA_UNUSED_ARGUMENT int argc, MECHA_UNUSED_ARGUMENT char **argv) +{ + char *users = Tcl_Alloc (33); + + snprintf (users, 32, "%d", m3_get_user_count (httpFthread_gettrans())); + Tcl_SetResult (interp, users, TCL_DYNAMIC); + + return (TCL_OK); +} + +static int +m3_tcl_skip_track (MECHA_UNUSED_ARGUMENT ClientData ignored, + MECHA_UNUSED_ARGUMENT Tcl_Interp *interp, + MECHA_UNUSED_ARGUMENT int argc, MECHA_UNUSED_ARGUMENT char **argv) +{ + httpTtrans *trans = httpFthread_gettrans (); + char ipaddr[18]; + + utlFip_to_str (trans->cli_ipv4_addr, ipaddr, 17); + logFmsg (CONT_LOG_OK, "%s: skipped %s", ipaddr, m3_get_songname (trans)); + + m3_skip_track (trans); + + return (TCL_OK); +} + +static int +m3_tcl_add_track (MECHA_UNUSED_ARGUMENT ClientData ignored, + Tcl_Interp *interp, int argc, char **argv) +{ + if (argc != 3) + { + Tcl_SetResult (interp, (char *) "ERROR: requires two arguments: plalistname, filename", TCL_STATIC); + + return (TCL_ERROR); + } + + if (m3_add_file (httpFthread_gettrans(), argv[1], argv[2])) + { + Tcl_AppendResult (interp, "file ", argv[2], " added", (char *) NULL); + return (TCL_OK); + } + else + { + Tcl_AppendResult (interp, "ERROR: Could not add file '", argv[2], "' to playlist '", argv[1], "'", (char *) NULL); + return (TCL_ERROR); + } +} + +static int +m3_tcl_reload_playlist (MECHA_UNUSED_ARGUMENT ClientData ignored, + MECHA_UNUSED_ARGUMENT Tcl_Interp *interp, + MECHA_UNUSED_ARGUMENT int argc, MECHA_UNUSED_ARGUMENT char **argv) +{ + if (m3_reload_playlist (httpFthread_gettrans()) == true) + { + Tcl_AppendResult (interp, "Playlist reloaded.", NULL); + return (TCL_OK); + } + else + { + Tcl_AppendResult (interp, "Unable to reload playlist.", NULL); + return (TCL_ERROR); + } +} diff --git a/modm3/mp3_frame.c b/mk4/modm3/src/mp3_frame.c similarity index 100% rename from modm3/mp3_frame.c rename to mk4/modm3/src/mp3_frame.c diff --git a/mk4/modm3/src/mp3_reader.c b/mk4/modm3/src/mp3_reader.c new file mode 100644 index 0000000..ec9ae44 --- /dev/null +++ b/mk4/modm3/src/mp3_reader.c @@ -0,0 +1,313 @@ + +#include + +#include "mp3_reader.h" + +#include "music_packet.h" +#include "idata_reader.h" +#include "file_reader.h" + +#include "mp3_frame.h" + +struct s_Mp3Reader +{ + IDataReader *reader; +}; + +Mp3Reader * +mp3_reader_new (void) +{ + Mp3Reader *instance = (Mp3Reader *) malloc (sizeof (Mp3Reader)); + + instance->reader = NULL; + + return (instance); +} + +void +mp3_reader_destroy (void *ptr) +{ + Mp3Reader *instance = (Mp3Reader *) ptr; + + if (instance->reader != NULL) + { + instance->reader->destroy (instance->reader); + } + + free (instance); +} + +bool +mp3_reader_open (Mp3Reader *instance, const char *uri) +{ + /* this should be using DataReaderFactory -- if such a thing existed */ + instance->reader = (IDataReader *) file_reader_new(); + + if (instance->reader->open (instance->reader, uri) == false) + { + return (false); + } + else + { + return (true); + } +} + +static bool +mp3_reader_parse_frame_header (MECHA_UNUSED_ARGUMENT Mp3Reader *instance, char *frameHeader, struct mp3frame *frameToFill) +{ + frameToFill->version = ((frameHeader[1] & 0x18) >> 3); + + if (frameToFill->version == 1) + { + logFmsg (CONT_LOG_ERROR, "found reserved version set"); + + return (false); + } + + if (frameToFill->version < 0 || frameToFill->version > 3) + { + logFmsg (CONT_LOG_ERROR, "unknown version %x", frameToFill->version); + + return (false); + } + + if (frameToFill->version == 3) + { + frameToFill->version = 1; + } + else if (frameToFill->version == 0) + { + frameToFill->version = 3; + } + + frameToFill->layer = ((frameHeader[1] & 0x06) >> 1); + + if (frameToFill->layer == 0) + { + logFmsg (CONT_LOG_ERROR, "found reserved layer set"); + + return (false); + } + if (frameToFill->layer < 1 || frameToFill->layer > 3) + { + logFmsg (CONT_LOG_ERROR, "unknown layer %x", frameToFill->layer); + + return (false); + } + + if (frameToFill->layer == 1) + { + frameToFill->layer = 3; + } + else if (frameToFill->layer == 3) + { + frameToFill->layer = 1; + } + + frameToFill->protection = frameHeader[1] & 0x01; + + frameToFill->bitrate = bitrate_index[frameToFill->version][frameToFill->layer][(frameHeader[2] & 0xf0) >> 4]; + + if (frameToFill->bitrate == -1) + { + logFmsg (CONT_LOG_ERROR, "don't know how to handle free format frames"); + + return (false); + } + else if (frameToFill->bitrate == -2) + { + logFmsg (CONT_LOG_ERROR, "found a frame with bad bitrate"); + + return (false); + } + else + { + frameToFill->bitrate *= 1000; + } + + frameToFill->frequency = samplerate_index[frameToFill->version][(frameHeader[2] & 0x0f) >> 2]; + + if (frameToFill->frequency == -1) + { + logFmsg (CONT_LOG_ERROR, "frequency was set to a reserved value"); + + return (false); + } + + frameToFill->padding = (frameHeader[2] & 0x02) >> 1; + + if (frameToFill->version == 1) + { + switch (frameToFill->layer) + { + case 1: + frameToFill->frame_byte_length = (384 * frameToFill->bitrate / 8 / frameToFill->frequency + frameToFill->padding) * 4; + frameToFill->frame_usec_length = 1000000L * 384 / frameToFill->frequency; + break; + case 2: + case 3: + frameToFill->frame_byte_length = 1152 * frameToFill->bitrate / 8 / frameToFill->frequency + frameToFill->padding; + frameToFill->frame_usec_length = 1000000L * 1152 / frameToFill->frequency; + break; + } + } + else + { + /* if we're not mpeg version 1 -- we don't know what to do */ + } + + frameToFill->private = frameHeader[2] & 0x01; + frameToFill->channel_mode = frameHeader[3] & 0xc0 >> 6; + frameToFill->channel_extension = frameHeader[3] & 0x30 >> 4; + frameToFill->copyright = frameHeader[3] & 0x08 >> 3; + frameToFill->original = frameHeader[3] & 0x04 >> 2; + frameToFill->emphasis = frameHeader[3] & 0x03; + + return (true); +} + +static int +mp3_reader_validate_sync_frame (const char *ptr) +{ + if ((ptr[0] & 0xff) == 0xff && (ptr[1] & 0xe0) == 0xe0) + { + return (0); + } + else + { + return (1); + } +} + +static bool +mp3_reader_get_next_frame (Mp3Reader *instance, struct mp3frame *frameToFill) +{ + ssize_t skippedBytes = 0; + char frameHeader[4]; + + while (true) + { + int thisSkippedBytes = instance->reader->seek_to_data_func (instance->reader, 2, mp3_reader_validate_sync_frame); + + if (thisSkippedBytes == -1) + { + /* we found the end of the file before we found the next sync frame */ + + return (false); + } + + skippedBytes += thisSkippedBytes; + + if (instance->reader->peek_bytes (instance->reader, frameHeader, sizeof (frameHeader)) == false) + { + /* + * we couldn't get all three bytes we needed.. we obviously got the + * end of the file early. + */ + + logFmsg (CONT_LOG_DEBUG, "mp3_reader: Reached the end of the file after finding the sync frame."); + + return (false); + } + + if (mp3_reader_parse_frame_header (instance, frameHeader, frameToFill) == false) + { + /* eat two bytes to progress on the stream */ + instance->reader->read_exact (instance->reader, frameHeader, 2); + + continue; + } + + if (frameToFill->version == 3) + { + /* logFmsg (CONT_LOG_ERROR, "not sure if we like version 2.5"); */ + + logFmsg (CONT_LOG_ERROR, "we don't support version 2.5"); + + /* eat two bytes to progress on the stream */ + instance->reader->read_exact (instance->reader, frameHeader, 2); + + continue; + } + + if (frameToFill->version != 1) + { + logFmsg (CONT_LOG_ERROR, "mp3_reader: Unknown mpeg version: %d", frameToFill->version); + + return (false); + } + + /* + * NOTE: we may not like: + * (frameToFill->version == 1 && frameToFill->layer == 1) + * either! + */ + + if (skippedBytes > 0) + { + logFmsg (CONT_LOG_DEBUG, "skipped %d bytes", skippedBytes); + } + + return (true); /* return offset */ + } +} + + +static bool +mp3_reader_add_next_frame (Mp3Reader *instance, MusicPacket *packet) +{ + struct mp3frame frame; + char frameBuffer[4096]; + + if (mp3_reader_get_next_frame (instance, &frame) == false) + { + return (false); + } + + assert (frame.frame_byte_length < 4096); + + if (instance->reader->read_exact (instance->reader, frameBuffer, frame.frame_byte_length) == true) + { + dynFappend (music_packet_data_get (packet), frameBuffer, frame.frame_byte_length); + + music_packet_time_length_add_usec (packet, frame.frame_usec_length); + + return (true); + } + else + { + return (false); + } +} + +MusicPacket * +mp3_reader_get_packet (Mp3Reader *instance, int requestedUsecs) +{ + MusicPacket *packet; + bool addedFrame = false; + + packet = music_packet_new(); + + while (music_packet_time_length_usecs_get (packet) < requestedUsecs) + { + if (mp3_reader_add_next_frame (instance, packet) == false) + { + break; + } + + addedFrame = true; + } + + if (addedFrame == false) + { + music_packet_destroy (packet); + + return (NULL); + } + else + { + return (packet); + } +} + diff --git a/mk4/modm3/src/music_packet.c b/mk4/modm3/src/music_packet.c new file mode 100644 index 0000000..42d0397 --- /dev/null +++ b/mk4/modm3/src/music_packet.c @@ -0,0 +1,83 @@ + +#include +#include + +#include "music_packet.h" + +struct s_MusicPacket +{ + dynTstring *data; + struct timeval timeLength; + int timestamp; +}; + +MusicPacket * +music_packet_new (void) +{ + MusicPacket *instance = (MusicPacket *) malloc (sizeof (MusicPacket)); + + instance->data = dynFinit(); + + instance->timeLength.tv_sec = 0; + instance->timeLength.tv_usec = 0; + + instance->timestamp = time (0); + + return (instance); +} + +void +music_packet_destroy (void *ptr) +{ + MusicPacket *instance = (MusicPacket *) ptr; + + dynFfree (instance->data); + + free (instance); +} + +MusicPacket * +music_packet_duplicate (MusicPacket *instance) +{ + MusicPacket *newInstance = (MusicPacket *) malloc (sizeof (MusicPacket)); + + newInstance->data = dynFinit(); + dynFappend_string (newInstance->data, instance->data); + + newInstance->timeLength = instance->timeLength; + + newInstance->timestamp = instance->timestamp; + + return (newInstance); +} + +dynTstring * +music_packet_data_get (MusicPacket *instance) +{ + return (instance->data); +} + +int +music_packet_timestamp_get (MusicPacket *instance) +{ + return (instance->timestamp); +} + +struct timeval +music_packet_time_length_get (MusicPacket *instance) +{ + return (instance->timeLength); +} + +int +music_packet_time_length_usecs_get (MusicPacket *instance) +{ + return ((instance->timeLength.tv_sec * 1000000L) + instance->timeLength.tv_usec); +} + +void +music_packet_time_length_add_usec (MusicPacket *instance, long usec) +{ + instance->timeLength.tv_sec += usec / 1000000L; + instance->timeLength.tv_usec += usec % 1000000L; +} diff --git a/mk4/modm3/src/order_playlist_engine.c b/mk4/modm3/src/order_playlist_engine.c new file mode 100644 index 0000000..54ee326 --- /dev/null +++ b/mk4/modm3/src/order_playlist_engine.c @@ -0,0 +1,81 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mecha.h" + +#include "playlist.h" +#include "file_entry.h" + +#include "order_playlist_engine.h" + +static FileEntry * order_playlist_engine_get_next (playlist *p); +static int order_playlist_engine_add_file (playlist *p, FileEntry *file); + +playlist_engine * +order_playlist_engine_init (void) +{ + playlist_engine *p; + + p = (playlist_engine *) malloc (sizeof (playlist_engine)); + + p->name = strFcopy ("order"); + p->type = PLAYLIST_TYPE_ORDER; + p->get_next = order_playlist_engine_get_next; + p->add_file = order_playlist_engine_add_file; + + return (p); +} + +static FileEntry * +order_playlist_engine_get_next (playlist *p) +{ + if (p->type != PLAYLIST_TYPE_ORDER) + return (0); + + if (lstFlist_size (p->filelist) == 0) + return (0); + + if (p->len == 0) + { + lstTlist_elem *ep; + int i; + + p->len = lstFlist_size (p->filelist); + + p->list = (FileEntry **) malloc (sizeof (FileEntry *) * p->len); + + for (ep = lstFlist_head (p->filelist), i = 0; ep; ep = lstFlist_next (ep)) + p->list[i++] = lstFlist_data (ep); + + p->offset = 0; + } + + if (p->offset >= p->len) + p->offset = 0; + + return (file_entry_duplicate (p->list[p->offset++])); +} + + +static int +order_playlist_engine_add_file (playlist *p, FileEntry *entry) +{ + if (p->len > 0) + { + p->list = realloc (p->list, sizeof (FileEntry *) * (p->len + 1)); + p->list[p->len] = entry; + p->len++; + } + + lstFlist_add_next (p->filelist, lstFlist_tail (p->filelist), entry); + + return (0); +} diff --git a/mk4/modm3/src/playlist.c b/mk4/modm3/src/playlist.c new file mode 100644 index 0000000..0aae564 --- /dev/null +++ b/mk4/modm3/src/playlist.c @@ -0,0 +1,311 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mecha.h" + +#include "playlist.h" +#include "queue_playlist_engine.h" +#include "order_playlist_engine.h" +#include "randomlist_playlist_engine.h" + +static lstTlist *g_playlists; +static lstTlist *g_engines; + +static playlist * get_playlist (const char *name); + +void +playlist_init() +{ + g_playlists = lstFlist_create (playlist_destroy); + g_engines = lstFlist_create (playlist_engine_destroy); + +#if 0 + lstFlist_add_next (g_engines, lstFlist_tail (g_engines), + randomlist_playlist_engine_init()); + + lstFlist_add_next (g_engines, lstFlist_tail (g_engines), + queue_playlist_engine_init()); + + lstFlist_add_next (g_engines, lstFlist_tail (g_engines), + order_playlist_engine_init()); +#endif +} + +void +playlist_destroy (void *ptr) +{ + playlist *p = ptr; + + free (p->name); + if (p->len) + free (p->list); + + lstFlist_free (p->filelist); + + free (p); +} + +void +playlist_engine_destroy (void *ptr) +{ + playlist_engine *p = ptr; + + free (p->name); + + free (p); +} + +static playlist_engine * +get_playlist_engine_by_name (const char *name) +{ + lstTlist_elem *el; + + for (el = lstFlist_head (g_engines); el; el = lstFlist_next (el)) + { + playlist_engine *e = (playlist_engine *) lstFlist_data (el); + + if (!strcmp (name, e->name)) + return (e); + } + + return (0); +} + +static playlist_engine * +get_playlist_engine_by_type (int type) +{ + lstTlist_elem *el; + + for (el = lstFlist_head (g_engines); el; el = lstFlist_next (el)) + { + playlist_engine *e = (playlist_engine *) lstFlist_data (el); + + if (e->type == type) + return (e); + } + + return (0); +} + +int +playlist_create (const char *name, const char *type) +{ + playlist *p; + playlist_engine *e; + + if (get_playlist (name)) + return (1); + + if (!(e = get_playlist_engine_by_name (type))) + return (2); + + p = (playlist *) malloc (sizeof (playlist)); + + p->name = strFcopy (name); + + p->len = 0; + + p->type = e->type; + p->filelist = lstFlist_create (file_entry_destroy); + + lstFlist_add_next (g_playlists, lstFlist_tail (g_playlists), p); + + return (0); +} + +int +playlist_delete (const char *name) +{ + lstTlist_elem *el; + + for (el = lstFlist_head (g_playlists); el; el = lstFlist_next (el)) + { + playlist *p = lstFlist_data (el); + if (strcmp (name, p->name) == 0) + { + lstFlist_remove (g_playlists, el, NULL); + playlist_destroy (p); + return (0); + } + } + + return (1); +} + +playlist * +get_playlist (const char *name) +{ + lstTlist_elem *el; + + for (el = lstFlist_head (g_playlists); el; el = lstFlist_next (el)) + { + playlist *p = lstFlist_data (el); + if (strcmp (name, p->name) == 0) + return (p); + } + + return (0); +} + +int +playlist_add_file (const char *playlistname, const char *file) +{ + playlist *p; + playlist_engine *pe; + struct stat sbuf; + + if (!(p = get_playlist (playlistname))) + return (1); + + if (!(pe = get_playlist_engine_by_type (p->type))) + return (2); + + if (!pe->add_file) + return (3); + + if (stat (file, &sbuf) != 0) + { + return (-errno); + } + + return (pe->add_file (p, file_entry_new (file))); +} + +int +playlist_add_fileglob (const char *playlistname, const char *fileglob) +{ + playlist *p; + playlist_engine *pe; + glob_t globbuf; + int e; + unsigned int i; + + if (!(p = get_playlist (playlistname))) + return (1); + + if (!(pe = get_playlist_engine_by_type (p->type))) + return (2); + + if (!pe->add_file) + return (3); + + if (glob (fileglob, 0, NULL, &globbuf) != 0) + { + e = errno; + globfree (&globbuf); + return (-e); + } + + for (i = 0; i < globbuf.gl_pathc; i++) + pe->add_file (p, file_entry_new (globbuf.gl_pathv[i])); + + globfree (&globbuf); + + return (0); +} + +int +playlist_add_filelist (const char *playlistname, const char *file) +{ + playlist_engine *pe; + playlist *p; + + if (!(p = get_playlist (playlistname))) + return (1); + + if (!(pe = get_playlist_engine_by_type (p->type))) + return (2); + + if (!pe->add_file) + return (3); + + { + struct stat sbuf; + FILE *fp; + char strbuf[NAME_MAX+1]; + + if (stat (file, &sbuf) != 0) + return (-errno); + + if (!(fp = fopen (file, "r"))) + { + logFmsg (CONT_LOG_ERROR, "couldn't open file %s", file); + fclose (fp); + return (1); + } + + while (fgets (strbuf, sizeof (strbuf), fp) != NULL) + { + char *nl; + + if (strlen (strbuf) > 0 && (nl = strpbrk (strbuf, "\n\r"))) + { + *nl = 0; + + if (strbuf[0] == '#') + continue; + + if (stat (strbuf, &sbuf) != 0) + { + logFmsg (CONT_LOG_ERROR, "%s: no such file or directory", strbuf); + continue; + } + + pe->add_file (p, file_entry_new (strbuf)); + } + } + + fclose (fp); + } + + return (0); +} + +int +playlist_reload_filelist (const char *playlistname, const char *file) +{ + playlist_engine *pe; + playlist *p; + + if (!(p = get_playlist (playlistname))) + return (1); + + if (!(pe = get_playlist_engine_by_type (p->type))) + return (2); + + if (!pe->set_to_filelist) + return (3); + + return (pe->set_to_filelist (p, file)); +} + +FileEntry * +playlist_get_next () +{ + FileEntry *fileEntry; + playlist *p; + playlist_engine *pe; + + if ((p = get_playlist ("preempt"))) + if ((pe = get_playlist_engine_by_type (p->type))) + if (pe->get_next) + if ((fileEntry = pe->get_next (p))) + return (fileEntry); + + if ((p = get_playlist ("general"))) + if ((pe = get_playlist_engine_by_type (p->type))) + if (pe->get_next) + if ((fileEntry = pe->get_next (p))) + return (fileEntry); + + return (0); +} + diff --git a/mk4/modm3/src/playlist_engine_factory.c b/mk4/modm3/src/playlist_engine_factory.c new file mode 100644 index 0000000..87377e9 --- /dev/null +++ b/mk4/modm3/src/playlist_engine_factory.c @@ -0,0 +1,69 @@ + +#include + +#include "mecha.h" + +#include "queue_playlist_engine.h" +#include "randomlist_playlist_engine.h" + +#include "playlist_engine_factory.h" + +struct s_PlaylistEngineFactory +{ + hshTvoid_list *playlistEngines; +}; + +typedef IPlaylist * (*IPlaylistConstructorDelegate) (const char *playlistName); + +static void playlist_engine_factory_add_playlist (PlaylistEngineFactory *instance, + const char *playlistType, IPlaylistConstructorDelegate delegate); + +PlaylistEngineFactory * +playlist_engine_factory_new (void) +{ + PlaylistEngineFactory *instance = (PlaylistEngineFactory *) malloc (sizeof (PlaylistEngineFactory)); + + instance->playlistEngines = hshFvoid_init (NULL); + + playlist_engine_factory_add_playlist (instance, "queue", + (IPlaylistConstructorDelegate) queue_playlist_engine_init); + + playlist_engine_factory_add_playlist (instance, "randomlist", + (IPlaylistConstructorDelegate) randomlist_playlist_engine_init); + + return (instance); +} + +void +playlist_engine_factory_destroy (void *ptr) +{ + PlaylistEngineFactory *instance = (PlaylistEngineFactory *) ptr; + + hshFvoid_destroy (instance->playlistEngines); + + free (instance); +} + +static void +playlist_engine_factory_add_playlist (PlaylistEngineFactory *instance, const char *playlistType, + IPlaylistConstructorDelegate delegate) +{ + hshFvoid_replace (instance->playlistEngines, playlistType, (void *) delegate); +} + +IPlaylist * +playlist_engine_factory_get_playlist (PlaylistEngineFactory *instance, const char *playlistType, const char *playlistName) +{ + IPlaylistConstructorDelegate constructor; + + constructor = (IPlaylistConstructorDelegate) hshFvoid_find (instance->playlistEngines, playlistType); + + if (constructor == NULL) + { + return (NULL); + } + else + { + return (constructor (playlistName)); + } +} diff --git a/mk4/modm3/src/playlist_manager.c b/mk4/modm3/src/playlist_manager.c new file mode 100644 index 0000000..edb2b03 --- /dev/null +++ b/mk4/modm3/src/playlist_manager.c @@ -0,0 +1,204 @@ + +#include + +#include "mecha.h" + +#include "playlist_engine_factory.h" +#include "file_catalog.h" + +#include "playlist_manager.h" + +/* NAME_MAX, quizzically, isn't everywhere. -aleigh */ +#ifndef NAME_MAX +#define NAME_MAX 255 +#endif + +struct s_PlaylistManager +{ + lstTlist *playlists; + + FileCatalog *fileCatalog; + + PlaylistEngineFactory *playlistFactory; +}; + +static void playlist_manager_destroy_engine (void *ptr); + + +PlaylistManager * +playlist_manager_new (void) +{ + PlaylistManager *instance = (PlaylistManager *) malloc (sizeof (PlaylistManager)); + + instance->playlists = lstFlist_create (playlist_manager_destroy_engine); + + instance->fileCatalog = file_catalog_new(); + + instance->playlistFactory = playlist_engine_factory_new(); + + return (instance); +} + +void +playlist_manager_destroy (void *ptr) +{ + PlaylistManager *instance = (PlaylistManager *) ptr; + + lstFlist_free (instance->playlists); + + playlist_engine_factory_destroy (instance->playlistFactory); + + file_catalog_destroy (instance->fileCatalog); + + free (instance); +} + +static void +playlist_manager_destroy_engine (void *ptr) +{ + IPlaylist *playlist = (IPlaylist *) ptr; + + playlist->destroy (playlist); +} + +static IPlaylist * +playlist_manager_get_engine (PlaylistManager *instance, const char *playlistName) +{ + lstTlist_elem *elem = lstFlist_head (instance->playlists); + + for (; elem; elem = lstFlist_next (elem)) + { + IPlaylist *playlist = (IPlaylist *) lstFlist_data (elem); + + if (strcmp (playlistName, playlist->get_name (playlist)) == 0) + { + return (playlist); + } + } + + return (NULL); +} + +bool +playlist_manager_add_playlist (PlaylistManager *instance, const char *playlistType, const char *playlistName) +{ + if (playlist_manager_get_engine (instance, playlistName) != NULL) + { + return (false); + } + + IPlaylist *playlist = playlist_engine_factory_get_playlist (instance->playlistFactory, + playlistType, playlistName); + + if (playlist == NULL) + { + return (false); + } + + lstFlist_add_next (instance->playlists, lstFlist_tail (instance->playlists), playlist); + + return (true); +} + +bool +playlist_manager_add_file (PlaylistManager *instance, const char *playlistName, const char *fileName) +{ + IPlaylist *playlist; + + playlist = playlist_manager_get_engine (instance, playlistName); + + if (playlist == NULL) + { + return (false); + } + + int fileId = file_catalog_get_fileid (instance->fileCatalog, fileName); + + return (playlist->add_file (playlist, fileId)); +} + +bool +playlist_manager_add_filelist (PlaylistManager *instance, const char *playlistName, const char *fileName) +{ + IPlaylist *playlist; + + playlist = playlist_manager_get_engine (instance, playlistName); + + if (playlist == NULL) + { + return (false); + } + + struct stat sbuf; + + if (stat (fileName, &sbuf) != 0) + { + logFmsg (CONT_LOG_ERROR, "mod/m3: Couldn't open file: %s", fileName); + + return (false); + } + + FILE *fp = fopen (fileName, "r"); + + if (fp == NULL) + { + logFmsg (CONT_LOG_ERROR, "mod/m3: Couldn't open file: %s", fileName); + + return (false); + } + + char strbuf[NAME_MAX+1]; + + while (fgets (strbuf, sizeof (strbuf), fp) != NULL) + { + char *nl; + + if (strlen (strbuf) > 0 && (nl = strpbrk (strbuf, "\n\r"))) + { + *nl = 0; + + if (strbuf[0] == '#') + continue; + + /* + * BUGBUG: We shouldn't be doing this check once we allow for + * transports other than local disk for reading mp3's. + */ + if (stat (strbuf, &sbuf) != 0) + { + logFmsg (CONT_LOG_ERROR, "mod/m3: No such file or directory: %s", strbuf); + continue; + } + + int fileId = file_catalog_get_fileid (instance->fileCatalog, strbuf); + + playlist->add_file (playlist, fileId); + } + } + + fclose (fp); + + return (true); +} + +FileEntry * +playlist_manager_get_next_file_entry (PlaylistManager *instance) +{ + lstTlist_elem *elem = lstFlist_head (instance->playlists); + + for (; elem; elem = lstFlist_next (elem)) + { + IPlaylist *playlist = (IPlaylist *) lstFlist_data (elem); + + int fileId = playlist->get_next (playlist); + + if (fileId != -1) + { + return (file_catalog_get_file_entry (instance->fileCatalog, fileId)); + } + } + + return (NULL); +} + + diff --git a/mk4/modm3/src/queue_playlist_engine.c b/mk4/modm3/src/queue_playlist_engine.c new file mode 100644 index 0000000..da16d6b --- /dev/null +++ b/mk4/modm3/src/queue_playlist_engine.c @@ -0,0 +1,148 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mecha.h" + +#include "iplaylist.h" +#include "playlist.h" + +#include "list_iterator.h" + +#include "queue_playlist_engine.h" + + +static void queue_playlist_engine_destroy (IPlaylist *inst); +static const char * queue_playlist_engine_get_name (IPlaylist *inst); +static const char * queue_playlist_engine_get_type (MECHA_UNUSED_ARGUMENT IPlaylist *inst); +static int queue_playlist_engine_get_next (IPlaylist *inst); +static bool queue_playlist_engine_add_file (IPlaylist *inst, int fileId); +static bool queue_playlist_engine_remove_file (IPlaylist *inst, int fileId); +static IIterator * queue_playlist_engine_get_list_iterator (IPlaylist *inst); + + +struct s_QueuePlaylistEngine +{ + IPlaylist interface; + + char *playlist_name; + + lstTlist *filelist; +}; + +QueuePlaylistEngine * +queue_playlist_engine_init (const char *playlistName) +{ + QueuePlaylistEngine *instance = (QueuePlaylistEngine *) malloc (sizeof (QueuePlaylistEngine)); + + instance->interface.destroy = queue_playlist_engine_destroy; + + instance->interface.get_name = queue_playlist_engine_get_name; + instance->interface.get_type = queue_playlist_engine_get_type; + + instance->interface.get_next = queue_playlist_engine_get_next; + instance->interface.add_file = queue_playlist_engine_add_file; + instance->interface.remove_file = queue_playlist_engine_remove_file; + + instance->interface.get_list_iterator = queue_playlist_engine_get_list_iterator; + instance->interface.get_next_iterator = queue_playlist_engine_get_list_iterator; + + instance->playlist_name = strFcopy (playlistName); + instance->filelist = lstFlist_create (NULL); + + return (instance); +} + +static void +queue_playlist_engine_destroy (IPlaylist *inst) +{ + QueuePlaylistEngine *instance = (QueuePlaylistEngine *) inst; + + free (instance->playlist_name); + + lstFlist_free (instance->filelist); + + free (instance); +} + +static const char * +queue_playlist_engine_get_name (IPlaylist *inst) +{ + QueuePlaylistEngine *instance = (QueuePlaylistEngine *) inst; + + return (instance->playlist_name); +} + +static const char * +queue_playlist_engine_get_type (MECHA_UNUSED_ARGUMENT IPlaylist *inst) +{ + return ("queue"); +} + +static int +queue_playlist_engine_get_next (IPlaylist *inst) +{ + QueuePlaylistEngine *instance = (QueuePlaylistEngine *) inst; + int retFileId; + + if (lstFlist_size (instance->filelist) == 0) + { + return (-1); + } + + lstFlist_remove (instance->filelist, lstFlist_head (instance->filelist), + (void **) &retFileId); + + return (retFileId); +} + +static bool +queue_playlist_engine_add_file (IPlaylist *inst, int fileId) +{ + QueuePlaylistEngine *instance = (QueuePlaylistEngine *) inst; + + lstFlist_add_next (instance->filelist, lstFlist_tail (instance->filelist), (void *) fileId); + + return (true); +} + +static bool +queue_playlist_engine_remove_file (IPlaylist *inst, int fileId) +{ + QueuePlaylistEngine *instance = (QueuePlaylistEngine *) inst; + + bool retRemoved = false; + + lstTlist_elem *elem = lstFlist_head (instance->filelist); + + while (elem) + { + lstTlist_elem *next = lstFlist_next (elem); + + if ((int) lstFlist_data (elem) == fileId) + { + lstFlist_remove (instance->filelist, elem, NULL); + + retRemoved = true; + } + + elem = next; + } + + return (retRemoved); +} + +static IIterator * +queue_playlist_engine_get_list_iterator (IPlaylist *inst) +{ + QueuePlaylistEngine *instance = (QueuePlaylistEngine *) inst; + + return ((IIterator *) list_iterator_new (instance->filelist)); +} diff --git a/modm3/randomlist_playlist_engine.c b/mk4/modm3/src/randomlist_playlist_engine.c similarity index 100% rename from modm3/randomlist_playlist_engine.c rename to mk4/modm3/src/randomlist_playlist_engine.c diff --git a/mk4/modm3/src/shoutcast_metadata_writer.c b/mk4/modm3/src/shoutcast_metadata_writer.c new file mode 100644 index 0000000..3eed9c3 --- /dev/null +++ b/mk4/modm3/src/shoutcast_metadata_writer.c @@ -0,0 +1,191 @@ + +#include + +#include "mecha.h" +#include "http.h" + +#include "shoutcast_metadata_writer.h" + +struct s_ShoutcastMetadataWriter +{ + httpTtrans *trans; + + bool writeMetadata; + + int bytesUntilNext; + + int metadataInterval; + + bool haveData; + + dynTstring *metadataTitle; + dynTstring *metadataUrl; +}; + + +static bool shoutcast_metadata_writer_write_http (ShoutcastMetadataWriter *instance, const char *buf, size_t len); +static bool shoutcast_metadata_writer_write_metadata (ShoutcastMetadataWriter *instance); + +ShoutcastMetadataWriter * +shoutcast_metadata_writer_new (httpTtrans *trans, bool writeMetadata, int metadataInterval) +{ + ShoutcastMetadataWriter *instance = (ShoutcastMetadataWriter *) malloc (sizeof (ShoutcastMetadataWriter)); + + instance->trans = trans; + + instance->writeMetadata = writeMetadata; + + instance->bytesUntilNext = metadataInterval; + instance->metadataInterval = metadataInterval; + + instance->haveData = false; + + instance->metadataTitle = dynFinit(); + instance->metadataUrl = dynFinit(); + + return (instance); +} + +void +shoutcast_metadata_writer_destroy (void *ptr) +{ + ShoutcastMetadataWriter *instance = (ShoutcastMetadataWriter *) ptr; + + dynFfree (instance->metadataTitle); + dynFfree (instance->metadataUrl); + + free (instance); +} + +void +shoutcast_metadata_writer_set_metadata (ShoutcastMetadataWriter *instance, const char *title, const char *url) +{ + dynFreset (instance->metadataTitle); + dynFreset (instance->metadataUrl); + + if (title != NULL) + { + dynFsappend (instance->metadataTitle, title); + } + + if (url != NULL) + { + dynFsappend (instance->metadataUrl, url); + } + + instance->haveData = true; +} + +bool +shoutcast_metadata_writer_write (ShoutcastMetadataWriter *instance, dynTstring *data) +{ + /* if we don't need to do anything special.. */ + if (instance->writeMetadata == false) + { + bool ret = shoutcast_metadata_writer_write_http (instance, dynFgetstr (data), + dynFgetlen (data)); + + return (ret); + } + else + { + bool ret; + const char *dataPtr = dynFgetstr (data); + int lenRemaining = dynFgetlen (data); + + while (lenRemaining > 0) + { + int writeLen; + + if (lenRemaining < instance->bytesUntilNext) + { + writeLen = lenRemaining; + } + else + { + writeLen = instance->bytesUntilNext; + } + + ret = shoutcast_metadata_writer_write_http (instance, dataPtr, writeLen); + + if (ret == false) + { + return (false); + } + + lenRemaining -= writeLen; + dataPtr += writeLen; + instance->bytesUntilNext -= writeLen; + + if (instance->bytesUntilNext == 0) + { + ret = shoutcast_metadata_writer_write_metadata (instance); + + if (ret == false) + { + return (false); + } + + instance->bytesUntilNext = instance->metadataInterval; + } + } + + return (true); + } +} + +static bool +shoutcast_metadata_writer_write_http (ShoutcastMetadataWriter *instance, const char *buf, size_t len) +{ + ssize_t ret = httpFwrite (instance->trans, buf, len); + + if (ret != (ssize_t) len) + { + return (false); + } + else + { + return (true); + } +} + +static bool +shoutcast_metadata_writer_write_metadata (ShoutcastMetadataWriter *instance) +{ + if (instance->haveData == true) + { + char *metabuf; + int padding, len; + int bufsize = dynFgetlen (instance->metadataTitle) + dynFgetlen (instance->metadataUrl) + 32; + bool ret; + + metabuf = (char *) malloc (bufsize); + + memset (metabuf, 0, bufsize); + + len = snprintf (metabuf + 1, bufsize - 1, "StreamTitle='%s';StreamUrl='%s';", + dynFgetstr (instance->metadataTitle), dynFgetstr (instance->metadataUrl)); + + padding = 16 - (len % 16); + + len += padding; + + metabuf[0] = len / 16; + + len += 1; + + ret = shoutcast_metadata_writer_write_http (instance, metabuf, len); + + free (metabuf); + + instance->haveData = false; + + return (ret); + } + else + { + char emptyByte = 0; + + return (shoutcast_metadata_writer_write_http (instance, &emptyByte, 1)); + } +} diff --git a/modm3/support.c b/mk4/modm3/src/support.c similarity index 100% rename from modm3/support.c rename to mk4/modm3/src/support.c diff --git a/mk4/modmobility/CVS/Entries b/mk4/modmobility/CVS/Entries new file mode 100644 index 0000000..2694307 --- /dev/null +++ b/mk4/modmobility/CVS/Entries @@ -0,0 +1,3 @@ +/Makefile/1.1/Fri May 14 17:53:17 2004//Tmk4_mod6_rc2 +D/include//// +D/src//// diff --git a/mk4/modmobility/CVS/Repository b/mk4/modmobility/CVS/Repository new file mode 100644 index 0000000..a430bc0 --- /dev/null +++ b/mk4/modmobility/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/modmobility diff --git a/mk4/modmobility/CVS/Root b/mk4/modmobility/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/modmobility/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/modmobility/CVS/Tag b/mk4/modmobility/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/modmobility/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/modmobility/Makefile b/mk4/modmobility/Makefile new file mode 100644 index 0000000..4c05afc --- /dev/null +++ b/mk4/modmobility/Makefile @@ -0,0 +1,13 @@ +CONTINUITY = ../continuity + +TARGET = mobility +TARGETTYPE = module + +SOURCES = src/mobility.c src/handler.c src/mobilitytable.c src/http_request.c \ + src/http_request_list.c src/http_message_handler.c + +INCLUDES += -Iinclude -I../lib/aura/include -I../lib/causality/include +STATIC_LIBS += $(CONTINUITY)/lib/libaura.a $(CONTINUITY)/lib/libcausality.a +#LOCAL_CFLAGS += + +include $(CONTINUITY)/lib/build.mk diff --git a/mk4/modmobility/include/CVS/Entries b/mk4/modmobility/include/CVS/Entries new file mode 100644 index 0000000..b7f4e02 --- /dev/null +++ b/mk4/modmobility/include/CVS/Entries @@ -0,0 +1,6 @@ +/http_message_handler.h/1.1/Thu May 13 21:15:33 2004//Tmk4_mod6_rc2 +/http_request.h/1.2/Fri May 14 16:51:26 2004//Tmk4_mod6_rc2 +/http_request_list.h/1.1/Thu May 13 21:15:33 2004//Tmk4_mod6_rc2 +/mobility.h/1.1/Thu May 13 21:15:33 2004//Tmk4_mod6_rc2 +/mobilitytable.h/1.1/Thu May 13 21:15:33 2004//Tmk4_mod6_rc2 +D diff --git a/mk4/modmobility/include/CVS/Repository b/mk4/modmobility/include/CVS/Repository new file mode 100644 index 0000000..a1ae984 --- /dev/null +++ b/mk4/modmobility/include/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/modmobility/include diff --git a/mk4/modmobility/include/CVS/Root b/mk4/modmobility/include/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/modmobility/include/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/modmobility/include/CVS/Tag b/mk4/modmobility/include/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/modmobility/include/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/modmobility/include/http_message_handler.h b/mk4/modmobility/include/http_message_handler.h new file mode 100644 index 0000000..6900a55 --- /dev/null +++ b/mk4/modmobility/include/http_message_handler.h @@ -0,0 +1,13 @@ +#ifndef __HTTP_MESSAGE_HANDLER_H__ +#define __HTTP_MESSAGE_HANDLER_H__ + +Message * http_message_handler_processWriteMessage (void *context, Message *requestMessage); +Message * http_message_handler_processFinishMessage (void *context, Message *requestMessage); +Message * http_message_handler_processReadEntityBody (void *context, Message *requestMessage); +Message * http_message_handler_handlePing (void *context, Message *requestMessage); + +extern CommandHandler command_HttpWrite; +extern CommandHandler command_HttpFinish; +extern CommandHandler command_HttpReadEntityBody; + +#endif diff --git a/mk4/modmobility/include/http_request.h b/mk4/modmobility/include/http_request.h new file mode 100644 index 0000000..3b0d679 --- /dev/null +++ b/mk4/modmobility/include/http_request.h @@ -0,0 +1,27 @@ +#ifndef __HTTP_REQUEST_H__ +#define __HTTP_REQUEST_H__ + +#include "http.h" +#include "processor.h" +#include "stringdictionary.h" + +typedef struct s_HttpRequest HttpRequest; + +HttpRequest * http_request_new (httpTtrans *trans, Processor *proc); +void http_request_destroy (void *ptr); + +const char * http_request_getToken (HttpRequest *resp); +int http_request_getResponse (HttpRequest *resp); +void http_request_setResponse (HttpRequest *resp, int response); + +bool http_request_sendRequestStart (HttpRequest *resp); + +bool http_request_write (HttpRequest *request, dynTstring *string); + +httpTtrans * http_request_getHttpTrans (HttpRequest *resp); + +void http_request_setResponseHeaders (HttpRequest *request, StringDictionary *responseHeaders); + +void http_request_setStatus (HttpRequest *request, int status, const char *reason); + +#endif diff --git a/mk4/modmobility/include/http_request_list.h b/mk4/modmobility/include/http_request_list.h new file mode 100644 index 0000000..1c465b6 --- /dev/null +++ b/mk4/modmobility/include/http_request_list.h @@ -0,0 +1,20 @@ +#ifndef __HTTP_REQUEST_LIST_H__ +#define __HTTP_REQUEST_LIST_H__ + +#include "http_request.h" + +#include "http.h" + +typedef struct s_HttpRequestList HttpRequestList; + +HttpRequestList * http_request_list_new (void); +void http_request_list_destroy (void *ptr); + +void http_request_list_addRequest (HttpRequestList *request_list, HttpRequest *resp); +void http_request_list_removeRequest (HttpRequestList *request_list, const char *token); + +HttpRequest * http_request_list_getRequest (HttpRequestList *request_list, const char *token); + +dynTstring * http_request_list_getDiag (HttpRequestList *request_list); + +#endif diff --git a/mk4/modmobility/include/mobility.h b/mk4/modmobility/include/mobility.h new file mode 100644 index 0000000..c6cf04c --- /dev/null +++ b/mk4/modmobility/include/mobility.h @@ -0,0 +1,20 @@ +#ifndef __MOBILITY_H_ +#define __MOBILITY_H_ + +#include "http.h" +#include "http_request.h" + +typedef struct s_Mobility Mobility; + +Mobility * mobility_new (const char *executable); +void mobility_destroy (void *ptr); + +int mobility_sendRequest (Mobility *mob, httpTtrans *trans); + +HttpRequest * mobility_getRequest (Mobility *mobility, const char *token); + +dynTstring *mobility_getRequestDiag (Mobility *mobility); + +int mobility_getPid (Mobility *mob); + +#endif diff --git a/mk4/modmobility/include/mobilitytable.h b/mk4/modmobility/include/mobilitytable.h new file mode 100644 index 0000000..12c30a9 --- /dev/null +++ b/mk4/modmobility/include/mobilitytable.h @@ -0,0 +1,17 @@ +#ifndef __MOBILITYTABLE_H_ +#define __MOBILITYTABLE_H_ + +#include "mobility.h" + +typedef struct s_MobilityTable MobilityTable; + +MobilityTable * mobilitytable_new (void); +void mobilitytable_destroy (void *ptr); + +Mobility * mobilitytable_getMobilityEntry (MobilityTable *mtable, const char *executable); + +Mobility * mobilitytable_getMobilityEntryByPid (MobilityTable *mtable, int pid); + +MobilityTable * mobilitytable_getTable(void); + +#endif diff --git a/mk4/modmobility/src/CVS/Entries b/mk4/modmobility/src/CVS/Entries new file mode 100644 index 0000000..ce21334 --- /dev/null +++ b/mk4/modmobility/src/CVS/Entries @@ -0,0 +1,7 @@ +/handler.c/1.1/Thu May 13 21:15:33 2004//Tmk4_mod6_rc2 +/http_message_handler.c/1.2/Fri May 14 16:51:27 2004//Tmk4_mod6_rc2 +/http_request.c/1.3/Sun May 16 20:31:59 2004//Tmk4_mod6_rc2 +/http_request_list.c/1.1/Thu May 13 21:15:33 2004//Tmk4_mod6_rc2 +/mobility.c/1.5/Wed May 19 18:19:53 2004//Tmk4_mod6_rc2 +/mobilitytable.c/1.1/Thu May 13 21:15:33 2004//Tmk4_mod6_rc2 +D diff --git a/mk4/modmobility/src/CVS/Repository b/mk4/modmobility/src/CVS/Repository new file mode 100644 index 0000000..909c29e --- /dev/null +++ b/mk4/modmobility/src/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/modmobility/src diff --git a/mk4/modmobility/src/CVS/Root b/mk4/modmobility/src/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/modmobility/src/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/modmobility/src/CVS/Tag b/mk4/modmobility/src/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/modmobility/src/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/modmobility/src/handler.c b/mk4/modmobility/src/handler.c new file mode 100644 index 0000000..6d5175d --- /dev/null +++ b/mk4/modmobility/src/handler.c @@ -0,0 +1,54 @@ + +#include +#include + +#include "http.h" + +#include "mobilitytable.h" +#include "mobility.h" + + +int mobility_init (void); +int mobility_handler (httpTtrans *t, lstTset *opts); + +int +mobility_init() +{ + return (STATUS_PROCEED); +} + +int +mobility_handler (httpTtrans *t, lstTset *opts) +{ + const char *handler; + const char *mimetype; + Mobility *mob; + + mimetype = lstFset_get (opts, "mimetype"); + + if (mimetype != NULL) + { + const char *this_mimetype = lstFset_get (t->res_hdrs, "Content-Type"); + + if (this_mimetype == NULL || strcmp (mimetype, this_mimetype) != 0) + { + return (STATUS_PROCEED); + } + } + + handler = lstFset_get (opts, "handler"); + + mob = mobilitytable_getMobilityEntry (mobilitytable_getTable(), handler); + + if (mob == NULL) + { + logFmsg (CONT_LOG_ERROR, "mobility: Couldn't get a mobility entry."); + + /* we couldn't function.. we'll just keep on going */ + return (STATUS_PROCEED); + } + else + { + return (mobility_sendRequest (mob, t)); + } +} diff --git a/mk4/modmobility/src/http_message_handler.c b/mk4/modmobility/src/http_message_handler.c new file mode 100644 index 0000000..9895326 --- /dev/null +++ b/mk4/modmobility/src/http_message_handler.c @@ -0,0 +1,253 @@ + +#include "message.h" +#include "http_request.h" +#include "mobility.h" + +#include "command.h" + +#include "serialization.h" + +Message * http_message_handler_processWriteMessage (void *context, Message *requestMessage); +Message * http_message_handler_processFinishMessage (void *context, Message *requestMessage); +Message * http_message_handler_processReadEntityBody (void *context, Message *requestMessage); +Message * http_message_handler_handlePing (void *context, Message *requestMessage); + + +static const char *command_HttpWrite_RequiredParameters[] = { "token", "data", NULL }; +static const char *command_HttpWrite_OptionalParameters[] = { "responseHeaders", "status", NULL }; +CommandHandler command_HttpWrite = { "HttpWrite", http_message_handler_processWriteMessage, + command_HttpWrite_RequiredParameters, command_HttpWrite_OptionalParameters }; + +static const char *command_HttpFinish_RequiredParameters[] = { "token", "returnStatus", NULL }; +static const char *command_HttpFinish_OptionalParameters[] = { NULL }; +CommandHandler command_HttpFinish = { "HttpFinish", http_message_handler_processFinishMessage, + command_HttpFinish_RequiredParameters, command_HttpFinish_OptionalParameters }; + +static const char *command_HttpReadEntityBody_RequiredParameters[] = { "token", NULL }; +static const char *command_HttpReadEntityBody_OptionalParameters[] = { NULL }; +CommandHandler command_HttpReadEntityBody = { "HttpReadEntityBody", http_message_handler_processReadEntityBody, + command_HttpReadEntityBody_RequiredParameters, command_HttpReadEntityBody_OptionalParameters }; + +static const char *command_HttpPing_RequiredParameters[] = { "token", NULL }; +static const char *command_HttpPing_OptionalParameters[] = { NULL }; +CommandHandler command_HttpPing = { "HttpPing", http_message_handler_processReadEntityBody, + command_HttpPing_RequiredParameters, command_HttpPing_OptionalParameters }; + + +static Message * +http_message_handler_createErrorMessage (Message *requestMessage, const char *message, const char *token) +{ + Message *response = message_makeErrorResponse (requestMessage); + + message_setParameter (response, "message", message); + + if (token != NULL) + { + message_setParameter (response, "token", token); + } + + return (response); +} + +Message * +http_message_handler_processWriteMessage (void *context, Message *requestMessage) +{ + Mobility *mobility = (Mobility *) context; + HttpRequest *request; + const char *token = message_getParameter (requestMessage, "token"); + + request = mobility_getRequest (mobility, token); + + if (request == NULL) + { + dynTstring *diag; + + Message *responseMessage = + http_message_handler_createErrorMessage (requestMessage, + "Could not find specified request.", token); + + diag = mobility_getRequestDiag (mobility); + + message_setParameterString (responseMessage, "hash_diag", diag); + + dynFfree (diag); + + return (responseMessage); + } + + { + dynTstring *serializedResponseHeaders; + + serializedResponseHeaders = message_getParameterString ( + requestMessage, "responseHeaders"); + + if (serializedResponseHeaders != NULL) + { + StringDictionary *responseHeaders; + + serialization_deserializeType ("StringDictionary", + &responseHeaders, serializedResponseHeaders); + + http_request_setResponseHeaders (request, responseHeaders); + + stringdictionary_destroy (responseHeaders); + } + } + + { + dynTstring *status = message_getParameterString ( + requestMessage, "status"); + + if (status != NULL) + { + int status_int = atoi (dynFgetstr (status)); + + /* currently not using the string */ + http_request_setStatus (request, status_int, NULL); + } + } + + { + Message *response; + dynTstring *data = message_getParameterString (requestMessage, "data"); + + if (http_request_write (request, data) == true) + { + response = message_makeResponse (requestMessage); + + message_setParameter (response, "message", "Data written."); + } + else + { + response = message_makeErrorResponse (requestMessage); + + message_setParameter (response, "message", "Did not send data."); + } + + return (response); + } +} + +Message * +http_message_handler_processFinishMessage (void *context, Message *requestMessage) +{ + Mobility *mobility = (Mobility *) context; + HttpRequest *request; + const char *token = message_getParameter (requestMessage, "token"); + + request = mobility_getRequest (mobility, token); + + if (request == NULL) + { + dynTstring *diag; + + Message *responseMessage = + http_message_handler_createErrorMessage (requestMessage, + "Could not find specified request.", token); + + diag = mobility_getRequestDiag (mobility); + + message_setParameterString (responseMessage, "hash_diag", diag); + + dynFfree (diag); + + return (responseMessage); + } + + { + Message *response; + const char *status = message_getParameter (requestMessage, "returnStatus"); + + http_request_setResponse (request, atoi (status)); + + response = message_makeResponse (requestMessage); + + message_setParameter (response, "message", "Data written."); + + return (response); + } +} + +Message * +http_message_handler_processReadEntityBody (void *context, Message *requestMessage) +{ + Mobility *mobility = (Mobility *) context; + HttpRequest *request; + const char *token = message_getParameter (requestMessage, "token"); + + if (token == NULL) + { + return (http_message_handler_createErrorMessage (requestMessage, + "Could not find required 'token' parameter.", NULL)); + } + + request = mobility_getRequest (mobility, token); + + if (request == NULL) + { + dynTstring *diag; + + Message *responseMessage = + http_message_handler_createErrorMessage (requestMessage, + "Could not find specified request.", token); + + diag = mobility_getRequestDiag (mobility); + + message_setParameterString (responseMessage, "hash_diag", diag); + + dynFfree (diag); + + return (responseMessage); + } + + { + Message *response; + httpTtrans *t = http_request_getHttpTrans (request);; + + if (httpFread_post (t) != -1) + { + response = message_makeResponse (requestMessage); + message_setParameter (response, "data", lstFset_get (t->vars, "post_query")); + } + else + { + response = http_message_handler_createErrorMessage (requestMessage, + "There was no data to retrieve.", token); + } + + return (response); + } +} + +Message * +http_message_handler_handlePing (void *context, Message *requestMessage) +{ + Mobility *mobility = (Mobility *) context; + const char *token = message_getParameter (requestMessage, "token"); + + if (mobility_getRequest (mobility, token) == NULL) + { + dynTstring *diag; + + Message *responseMessage = + http_message_handler_createErrorMessage (requestMessage, + "Could not find specified request.", token); + + diag = mobility_getRequestDiag (mobility); + + message_setParameterString (responseMessage, "hash_diag", diag); + + dynFfree (diag); + + return (responseMessage); + } + else + { + Message *responseMessage = message_makeResponse (requestMessage); + + message_setParameter (responseMessage, "message", "Request found."); + + return (responseMessage); + } +} + diff --git a/mk4/modmobility/src/http_request.c b/mk4/modmobility/src/http_request.c new file mode 100644 index 0000000..45a9662 --- /dev/null +++ b/mk4/modmobility/src/http_request.c @@ -0,0 +1,361 @@ + +#include +#include +#include +#include + +#include "mecha.h" + +#include "stringdictionary.h" +#include "http_request.h" +#include "message.h" +#include "processor.h" + +#include "http.h" + +#include "serialization.h" + +int g_pid = -1; +int g_sequence = 1; +pthread_mutex_t g_sequence_mutex = PTHREAD_MUTEX_INITIALIZER; + +static int http_request_getPid (void); +static int http_request_getNextSequence (void); + +struct s_HttpRequest +{ + dynTstring *token; + + httpTtrans *trans; + + pthread_cond_t cond; + pthread_mutex_t mutex; + + bool hasStarted; + + bool hasResponse; + + int response; + + Processor *processor; +}; + +static int +http_request_getPid() +{ + if (g_pid == -1) + { + g_pid = getpid(); + } + + return (g_pid); +} + +static int +http_request_getNextSequence() +{ + int ret; + + pthread_mutex_lock (&g_sequence_mutex); + + ret = ++g_sequence; + + pthread_mutex_unlock (&g_sequence_mutex); + + return (ret); +} + +HttpRequest * +http_request_new (httpTtrans *trans, Processor *proc) +{ + HttpRequest *resp = malloc (sizeof (HttpRequest)); + + resp->token = dynFinit(); + + dynFappend_print (resp->token, "0x%x-0x%x", http_request_getPid(), http_request_getNextSequence()); + + resp->trans = trans; + + pthread_cond_init (&resp->cond, NULL); + pthread_mutex_init (&resp->mutex, NULL); + + resp->hasResponse = false; + resp->hasStarted = false; + + resp->response = 0; + resp->processor = proc; + + httpFset_status (resp->trans, 200, "OK OK"); + + return (resp); +} + +void +http_request_destroy (void *ptr) +{ + HttpRequest *resp = (HttpRequest *) ptr; + + dynFfree (resp->token); + + pthread_cond_destroy (&resp->cond); + pthread_mutex_destroy (&resp->mutex); + + free (resp); +} + +const char * +http_request_getToken (HttpRequest *resp) +{ + return (dynFgetstr (resp->token)); +} + +httpTtrans * +http_request_getHttpTrans (HttpRequest *resp) +{ + return (resp->trans); +} + +static bool +http_request_pingRemote (HttpRequest *request) +{ + bool ret; + Message *responseMessage; + Message *startMessage = message_newRequest ("HttpRequestPing"); + + message_setParameter (startMessage, "token", + dynFgetstr (request->token)); + + ret = processor_sendMessage (request->processor, startMessage, &responseMessage); + + if (ret == false) + { + logFmsg (CONT_LOG_ERROR, "Could not send message."); + } + else + { + if (message_getType (responseMessage) == MessageTypeErrorResponse) + { + logFmsg (CONT_LOG_ERROR, "Could not find token %s - %s", dynFgetstr (request->token), + message_getParameter (responseMessage, "message")); + + ret = false; + } + else + { + ret = true; + } + + message_destroy (responseMessage); + } + + message_destroy (startMessage); + + return (ret); +} + +void +http_request_setResponseHeaders (HttpRequest *request, + StringDictionary *responseHeaders) +{ + hshTiterator *iter = stringdictionary_getIterator (responseHeaders); + + while (hshFiterator_next (iter) == 1) + { + const char *key = (const char *) hshFiterator_current_key (iter); + const dynTstring *value = (const dynTstring *) hshFiterator_current_value (iter); + + lstFset_update (request->trans->res_hdrs, key, dynFgetstr (value)); + } + + hshFiterator_free (iter); +} + +void +http_request_setStatus (HttpRequest *request, int status, const char *reason) +{ + httpFset_status (request->trans, status, reason); +} + +bool +http_request_write (HttpRequest *request, dynTstring *string) +{ + if (request->hasStarted == false) + { + httpFstart_response (request->trans); + + request->hasStarted = true; + } + + /* If we didn't have any data to send but want to send our headers */ + if (dynFgetlen (string) == 0) + { + return (true); + } + + if (httpFwrite (request->trans, dynFgetstr (string), dynFgetlen (string)) == -1) + { + http_request_setResponse (request, STATUS_ERROR); + + return (false); + } + else + { + return (true); + } +} + +int +http_request_getResponse (HttpRequest *resp) +{ + int response; + + pthread_mutex_lock (&resp->mutex); + + while (resp->hasResponse == false) + { + struct timespec waitTime = { 0, 0 }; + + waitTime.tv_sec = time(0) + 15; + + if (pthread_cond_timedwait (&resp->cond, &resp->mutex, &waitTime) == ETIMEDOUT) + { + if (http_request_pingRemote (resp) == false) + { + resp->response = STATUS_ERROR; + resp->hasResponse = true; + + logFmsg (CONT_LOG_DEBUG, "request no longer active: %s", dynFgetstr (resp->token)); + } + else + { + logFmsg (CONT_LOG_DEBUG, "request still active: %s", dynFgetstr (resp->token)); + } + } + } + + response = resp->response; + + pthread_mutex_unlock (&resp->mutex); + + return (response); +} + +void +http_request_setResponse (HttpRequest *resp, int response) +{ + pthread_mutex_lock (&resp->mutex); + + resp->hasResponse = true; + resp->response = response; + + pthread_mutex_unlock (&resp->mutex); + + pthread_cond_signal (&resp->cond); +} + +static void +http_request_serializeListSet (Message *message, const char *entryName, lstTset *list) +{ + int i; + StringDictionary *returnList = stringdictionary_new(); + + for (i = 0; i < lstFset_size (list); i++) + { + dynTstring *value_str; + const char *key; + const char *value; + int value_len; + + key = lstFset_get_key_index (list, i); + value = lstFset_get_index (list, i); + + if (value != NULL) + { + value_len = strlen (value); + + value_str = dynFinit(); + dynFappend (value_str, value, value_len); + + /* + dynFappend (value_str, lstFset_get_index (list, i), + lstFset_get_index (list, i)); + */ + + stringdictionary_setValue (returnList, key, value_str); + } + } + + { + dynTstring *ser = serialization_serializeType ("StringDictionary", &returnList); + + message_setParameterBinary (message, entryName, dynFgetstr (ser), dynFgetlen (ser)); + + dynFfree (ser); + } + + stringdictionary_destroy (returnList); +} + +static Message * +http_request_createRequestStartMessage (HttpRequest *resp) +{ + char ipBuf[20]; + + Message *startMessage = message_newRequest ("HttpRequestStart"); + + message_setParameter (startMessage, "token", + dynFgetstr (resp->token)); + + utlFip_to_str (resp->trans->cli_ipv4_addr, ipBuf, sizeof (ipBuf)); + + message_setParameter (startMessage, "remoteIP", ipBuf); + + /* serialize all transaction variables */ + http_request_serializeListSet (startMessage, "variables", + resp->trans->vars); + + /* serialize all request headers */ + http_request_serializeListSet (startMessage, "headers", + resp->trans->req_hdrs); + + return (startMessage); +} + +bool +http_request_sendRequestStart (HttpRequest *resp) +{ + Message *message; + Message *responseMessage; + bool ret; + + message = http_request_createRequestStartMessage (resp); + + ret = processor_sendMessage (resp->processor, message, &responseMessage); + + if (ret == false) + { + logFmsg (CONT_LOG_ERROR, "Could not send message."); + } + else + { + if (message_getType (responseMessage) == MessageTypeErrorResponse) + { + logFmsg (CONT_LOG_ERROR, "Error was returned."); + + message_print (responseMessage); + + ret = false; + } + else + { + ret = true; + } + + message_destroy (responseMessage); + } + + message_destroy (message); + + return (ret); +} + diff --git a/mk4/modmobility/src/http_request_list.c b/mk4/modmobility/src/http_request_list.c new file mode 100644 index 0000000..2de17bd --- /dev/null +++ b/mk4/modmobility/src/http_request_list.c @@ -0,0 +1,94 @@ + +#include +#include + +#include "http_request_list.h" + +#include "http.h" + +struct s_HttpRequestList +{ + hshTvoid_list *list; + + pthread_rwlock_t list_lock; +}; + +HttpRequestList * +http_request_list_new() +{ + HttpRequestList *request_list = malloc (sizeof (HttpRequestList)); + + request_list->list = hshFvoid_init (http_request_destroy); + + pthread_rwlock_init (&request_list->list_lock, NULL); + + return (request_list); +} + +void +http_request_list_destroy (void *ptr) +{ + HttpRequestList *request_list = (HttpRequestList *) ptr; + + pthread_rwlock_destroy (&request_list->list_lock); + + hshFvoid_destroy (request_list->list); + + free (request_list); +} + +void +http_request_list_addRequest (HttpRequestList *request_list, HttpRequest *resp) +{ + pthread_rwlock_wrlock (&request_list->list_lock); + + hshFvoid_add (request_list->list, http_request_getToken (resp), resp); + +#ifdef TRACE_REQUEST_LIST + printf (" -- added request %s\n", http_request_getToken (resp)); +#endif + + pthread_rwlock_unlock (&request_list->list_lock); +} + +void +http_request_list_removeRequest (HttpRequestList *request_list, const char *token) +{ + pthread_rwlock_wrlock (&request_list->list_lock); + +#ifdef TRACE_REQUEST_LIST + printf (" -- removed request %s\n", token); +#endif + + hshFvoid_del (request_list->list, token); + + pthread_rwlock_unlock (&request_list->list_lock); +} + +HttpRequest * +http_request_list_getRequest (HttpRequestList *request_list, const char *token) +{ + HttpRequest *request; + + pthread_rwlock_rdlock (&request_list->list_lock); + + request = (HttpRequest *) hshFvoid_find (request_list->list, token); + + pthread_rwlock_unlock (&request_list->list_lock); + + return (request); +} + +dynTstring * +http_request_list_getDiag (HttpRequestList *request_list) +{ + dynTstring *string; + + pthread_rwlock_rdlock (&request_list->list_lock); + + string = hshFdiag_output (request_list->list); + + pthread_rwlock_unlock (&request_list->list_lock); + + return (string); +} diff --git a/mk4/modmobility/src/mobility.c b/mk4/modmobility/src/mobility.c new file mode 100644 index 0000000..6ca0bff --- /dev/null +++ b/mk4/modmobility/src/mobility.c @@ -0,0 +1,266 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "processor.h" +#include "mobility.h" +#include "mobilitytable.h" + +#include "http_request.h" +#include "http_request_list.h" + +/* #include "capi.h" */ +#include "http.h" + +#include "http_message_handler.h" + +struct s_Mobility +{ + char *executable; + key_t ipcKey; + Processor *processor; + + HttpRequestList *requestList; + int pid; + + pthread_rwlock_t pid_lock; +}; + +static pthread_once_t g_setupChildWatcher_once_control = PTHREAD_ONCE_INIT; + +static void mobility_startChildProcess (Mobility *mob); + +Mobility * +mobility_new (const char *executable) +{ + Mobility *mob; + + mob = malloc (sizeof (Mobility)); + + mob->requestList = http_request_list_new(); + mob->executable = strdup (executable); + mob->pid = -1; + mob->ipcKey = rand(); + pthread_rwlock_init (&mob->pid_lock, NULL); + + /* start up the processor as a server */ + mob->processor = processor_new (mob->ipcKey, false); + + processor_addRequestHandler (mob->processor, &command_HttpWrite, mob); + processor_addRequestHandler (mob->processor, &command_HttpFinish, mob); + processor_addRequestHandler (mob->processor, &command_HttpReadEntityBody, mob); + + processor_finishedInit (mob->processor); + + mobility_startChildProcess (mob); + + return (mob); +} + +void +mobility_destroy (void *ptr) +{ + Mobility *mob = (Mobility *) ptr; + + http_request_list_destroy (mob->requestList); + + if (mob->pid != -1) + { + kill (mob->pid, SIGHUP); + } + + free (mob->executable); + + free (mob); +} + +int +mobility_getPid (Mobility *mob) +{ + return (mob->pid); +} + +static const char * +mobility_childExitReason (int si_code) +{ + switch (si_code) + { + case CLD_EXITED: + return ("exited"); + break; + case CLD_KILLED: + return ("was killed"); + break; + case CLD_DUMPED: + return ("terminated abnormally"); + break; + default: + return ("exited for an unknown reason"); + break; + } +} + +static void +mobility_sigChildHandler (int signum MECHA_UNUSED, siginfo_t *siginfo, void *data MECHA_UNUSED) +{ + Mobility *mob = mobilitytable_getMobilityEntryByPid ( + mobilitytable_getTable(), siginfo->si_pid); + + waitpid (siginfo->si_pid, NULL, WNOHANG); + + if (mob == NULL) + { + logFmsg (CONT_LOG_WARN, "Recieved termination of unknown child process: %d", + siginfo->si_pid); + + return; + } + + logFmsg (CONT_LOG_DEBUG, "Causality process (%d) %s.", siginfo->si_pid, + mobility_childExitReason (siginfo->si_code)); + + mob->pid = -1; +} + +static void +mobility_setupSigChildWatcher (void) +{ + struct sigaction action; + + action.sa_handler = NULL; + action.sa_sigaction = mobility_sigChildHandler; + action.sa_flags = SA_NOCLDSTOP | SA_SIGINFO; +#ifdef LINUX + action.sa_restorer = NULL; +#endif + + sigemptyset (&action.sa_mask); + + if (sigaction (SIGCHLD, &action, NULL) != 0) + { + int e = errno; + + logFmsg (CONT_LOG_ERROR, "Could not install signal handler for SIGCHLD: %s", + strerror (e)); + } +} + +static void +mobility_startChildProcess (Mobility *mob) +{ + int pid; + char commandLine[4096]; + const char *argv[4]; + + pthread_once (&g_setupChildWatcher_once_control, mobility_setupSigChildWatcher); + + pthread_rwlock_wrlock (&mob->pid_lock); + + if (mob->pid != -1) + { + /* we already got started by another thread */ + + pthread_rwlock_unlock (&mob->pid_lock); + + return; + } + + snprintf (commandLine, sizeof (commandLine), "%s %u", mob->executable, mob->ipcKey); + + argv[0] = "/bin/sh"; + argv[1] = "-c"; + argv[2] = commandLine; + argv[3] = NULL; + + if ((pid = fork()) == 0) + { + /* child */ + + execv (argv[0], (char *const *) argv); + + /* if we are still here.. we failed. */ + + perror ("execv"); + + exit (127); + } + else + { + /* parent */ + + mob->pid = pid; + + logFmsg (CONT_LOG_WARN, "%s executing with pid %d", mob->executable, mob->pid); + + pthread_rwlock_unlock (&mob->pid_lock); + } +} + +static void +mobility_checkChildProcessStatus (Mobility *mob) +{ + bool startChild = false; + + pthread_rwlock_rdlock (&mob->pid_lock); + + if (mob->pid == -1) + { + startChild = true; + } + + pthread_rwlock_unlock (&mob->pid_lock); + + if (startChild == true) + { + mobility_startChildProcess (mob); + } +} + +HttpRequest * +mobility_getRequest (Mobility *mobility, const char *token) +{ + return (http_request_list_getRequest (mobility->requestList, token)); +} + +dynTstring +*mobility_getRequestDiag (Mobility *mobility) +{ + return (http_request_list_getDiag (mobility->requestList)); +} + +int +mobility_sendRequest (Mobility *mob, httpTtrans *trans) +{ + HttpRequest *req = http_request_new (trans, mob->processor); + int response; + + /* spawn a new client process if needed */ + mobility_checkChildProcessStatus (mob); + + http_request_list_addRequest (mob->requestList, req); + + if (http_request_sendRequestStart (req) == false) + { + logFmsg (CONT_LOG_WARN, "Could not process request."); + response = STATUS_PROCEED; + } + else + { + response = http_request_getResponse (req); + } + + /* this should free the request object */ + http_request_list_removeRequest (mob->requestList, + http_request_getToken (req)); + + return (response); +} + diff --git a/mk4/modmobility/src/mobilitytable.c b/mk4/modmobility/src/mobilitytable.c new file mode 100644 index 0000000..c9d8d09 --- /dev/null +++ b/mk4/modmobility/src/mobilitytable.c @@ -0,0 +1,122 @@ + +#include +#include + +#include "mobility.h" +#include "mobilitytable.h" + + +static pthread_once_t g_table_once_control = PTHREAD_ONCE_INIT; +static MobilityTable *g_table = NULL; + +struct s_MobilityTable +{ + hshTvoid_list *list; + + pthread_rwlock_t list_lock; +}; + +MobilityTable * +mobilitytable_new() +{ + MobilityTable *mtable = malloc (sizeof (MobilityTable)); + + mtable->list = hshFvoid_init (mobility_destroy); + + pthread_rwlock_init (&mtable->list_lock, NULL); + + return (mtable); +} + +void +mobilitytable_destroy (void *ptr) +{ + MobilityTable *mtable = (MobilityTable *) ptr; + + hshFvoid_destroy (mtable->list); + + pthread_rwlock_destroy (&mtable->list_lock); + + free (mtable); +} + +static void +mobilitytable_createGlobalTable (void) +{ + g_table = mobilitytable_new(); +} + +MobilityTable * +mobilitytable_getTable() +{ + pthread_once (&g_table_once_control, mobilitytable_createGlobalTable); + + return (g_table); +} + +Mobility * +mobilitytable_getMobilityEntryByPid (MobilityTable *mtable, int pid) +{ + hshTiterator *iter; + Mobility *retMob = NULL; + + pthread_rwlock_rdlock (&mtable->list_lock); + + iter = hshFiterator_init (mtable->list); + + while (hshFiterator_next (iter) == 1) + { + Mobility *mob = (Mobility *) hshFiterator_current_value (iter); + + if (mobility_getPid (mob) == pid) + { + retMob = mob; + + break; + } + } + + hshFiterator_free (iter); + + pthread_rwlock_unlock (&mtable->list_lock); + + return (retMob); +} + +Mobility * +mobilitytable_getMobilityEntry (MobilityTable *mtable, const char *executable) +{ + Mobility *entry; + + pthread_rwlock_rdlock (&mtable->list_lock); + + entry = (Mobility *) hshFvoid_find (mtable->list, executable); + + if (entry == NULL) + { + pthread_rwlock_unlock (&mtable->list_lock); + pthread_rwlock_wrlock (&mtable->list_lock); + + entry = (Mobility *) hshFvoid_find (mtable->list, executable); + + if (entry == NULL) + { + entry = mobility_new (executable); + + if (entry != NULL) + { + hshFvoid_add (mtable->list, executable, entry); + } + else + { + printf ("-- couldn't find executable: %s\n", executable); + } + } + } + + pthread_rwlock_unlock (&mtable->list_lock); + + return (entry); +} + + diff --git a/mk4/modoracle/CVS/Entries b/mk4/modoracle/CVS/Entries new file mode 100644 index 0000000..be241f2 --- /dev/null +++ b/mk4/modoracle/CVS/Entries @@ -0,0 +1,6 @@ +/Makefile.blackwell/1.3/Wed May 12 13:56:07 2004//Tmk4_mod6_rc2 +/Makefile.chiba/1.5/Wed May 12 13:56:07 2004//Tmk4_mod6_rc2 +/Makefile.gorecki/1.1/Thu May 13 07:48:59 2004//Tmk4_mod6_rc2 +/ora.c/1.7/Fri Apr 2 16:05:45 2004//Tmk4_mod6_rc2 +/oracle.xml/1.2/Wed May 12 15:09:20 2004//Tmk4_mod6_rc2 +D diff --git a/mk4/modoracle/CVS/Repository b/mk4/modoracle/CVS/Repository new file mode 100644 index 0000000..49334f1 --- /dev/null +++ b/mk4/modoracle/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/modoracle diff --git a/mk4/modoracle/CVS/Root b/mk4/modoracle/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/modoracle/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/modoracle/CVS/Tag b/mk4/modoracle/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/modoracle/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/modoracle/Makefile.blackwell b/mk4/modoracle/Makefile.blackwell new file mode 100644 index 0000000..2f8f09c --- /dev/null +++ b/mk4/modoracle/Makefile.blackwell @@ -0,0 +1,60 @@ +# $Header: /san01/cvs/ashpool/csrc/modoracle/Attic/Makefile.blackwell,v 1.3 2004/05/12 13:56:07 aleigh Exp $ + +include ../continuity/lib/env.mk + +SRCS=ora.c +OBJS=ora.o + +# 64-bit or default install Oracle 9 +#ORALIBS = $(ORACLE_HOME)/lib/libclntst9.a $(ORACLE_HOME)/lib/libcore9.a \ +# $(ORACLE_HOME)/lib/libcommon9.a $(ORACLE_HOME)/lib/libgeneric9.a \ +# $(ORACLE_HOME)/lib/libclient9.a + +# 32-bit install Oracle 9 +#ORALIBS = $(ORACLE_HOME)/lib32/libclntst9.a $(ORACLE_HOME)/lib32/libcore9.a \ +# $(ORACLE_HOME)/lib32/libcommon9.a $(ORACLE_HOME)/lib32/libgeneric9.a \ +# $(ORACLE_HOME)/lib32/libclient9.a + +# 64-bit or default install oracle 8 +#ORALIBS = $(ORACLE_HOME)/lib/libclntst8.a $(ORACLE_HOME)/lib/libcore8.a \ +# $(ORACLE_HOME)/lib/libcommon8.a $(ORACLE_HOME)/lib/libgeneric8.a \ +# $(ORACLE_HOME)/lib/libclient8.a + +#ORALIBS=$(ORACLE_HOME)/lib/libclntsh.dylib + +#ORALIBS = -L$(ORACLE_HOME)/lib -lclntsh -lcore8 -lcommon8 -lgeneric8 -lclient8 +ORALIBS = -L$(ORACLE_HOME)/lib32 -lclntsh -lcore9 -lcommon9 -lgeneric9 -lclient9 +#ORALIBS = -L$(ORACLE_HOME)/lib -lclntsh -lcore9 -lcommon9 -lgeneric9 -lclient9 + +CFLAGS=-I../continuity/include $(CONT_FLAGS) \ + -I$(ORACLE_HOME)/rdbms/demo \ + -I$(ORACLE_HOME)/rdbms/public \ + -I$(ORACLE_HOME)/network/public \ + -I$(ORACLE_HOME)/plsql/public + +world: ../continuity/lib/oracle.so + +../continuity/lib/oracle.so: $(OBJS) + $(LD_SHARECMD) -o ../continuity/lib/oracle.so $(OBJS) $(ORALIBS) + cp oracle.xml ../continuity/lib + +../continuity/lib/oracle.a: $(OBJS) + $(RM) ora_objs/* + (cd ora_objs ; ar x $(ORACLE_HOME)/lib/libclntst8.a) + (cd ora_objs ; ar x $(ORACLE_HOME)/lib/libcore8.a) + (cd ora_objs ; ar x $(ORACLE_HOME)/lib/libcommon8.a) + (cd ora_objs ; ar x $(ORACLE_HOME)/lib/libclient8.a) +# (cd ora_objs ; ar x $(ORACLE_HOME)/lib32/libclntst9.a) +# (cd ora_objs ; ar x $(ORACLE_HOME)/lib32/libcore9.a) +# (cd ora_objs ; ar x $(ORACLE_HOME)/lib32/libcommon9.a) +# (cd ora_objs ; ar x $(ORACLE_HOME)/lib32/libclient9.a) + $(AR_CMD) ../continuity/lib/oracle.a $(OBJS) ora_objs/* + $(RM) ora_objs/* + +clean: + $(RM) $(OBJS) *~ ../continuity/lib/oracle.a ../continuity/lib/oracle.so + $(RM) ora_objs/* + +dep: depend +depend: + makedepend -I ../include $(SRCS) diff --git a/mk4/modoracle/Makefile.chiba b/mk4/modoracle/Makefile.chiba new file mode 100644 index 0000000..10ba850 --- /dev/null +++ b/mk4/modoracle/Makefile.chiba @@ -0,0 +1,60 @@ +# $Header: /san01/cvs/ashpool/csrc/modoracle/Attic/Makefile.chiba,v 1.5 2004/05/12 13:56:07 aleigh Exp $ + +include ../continuity/lib/env.mk + +SRCS=ora.c +OBJS=ora.o + +# 64-bit or default install Oracle 9 +#ORALIBS = $(ORACLE_HOME)/lib/libclntst9.a $(ORACLE_HOME)/lib/libcore9.a \ +# $(ORACLE_HOME)/lib/libcommon9.a $(ORACLE_HOME)/lib/libgeneric9.a \ +# $(ORACLE_HOME)/lib/libclient9.a + +# 32-bit install Oracle 9 +#ORALIBS = $(ORACLE_HOME)/lib32/libclntst9.a $(ORACLE_HOME)/lib32/libcore9.a \ +# $(ORACLE_HOME)/lib32/libcommon9.a $(ORACLE_HOME)/lib32/libgeneric9.a \ +# $(ORACLE_HOME)/lib32/libclient9.a + +# 64-bit or default install oracle 8 +#ORALIBS = $(ORACLE_HOME)/lib/libclntst8.a $(ORACLE_HOME)/lib/libcore8.a \ +# $(ORACLE_HOME)/lib/libcommon8.a $(ORACLE_HOME)/lib/libgeneric8.a \ +# $(ORACLE_HOME)/lib/libclient8.a + +#ORALIBS=$(ORACLE_HOME)/lib/libclntsh.dylib + +#ORALIBS = -L$(ORACLE_HOME)/lib -lclntsh -lcore8 -lcommon8 -lgeneric8 -lclient8 +#ORALIBS = -L$(ORACLE_HOME)/lib32 -lclntsh -lcore9 -lcommon9 -lgeneric9 -lclient9 +ORALIBS = -L$(ORACLE_HOME)/lib -lclntsh -lcore9 -lcommon9 -lgeneric9 -lclient9 + +CFLAGS=-I../continuity/include $(CONT_FLAGS) \ + -I$(ORACLE_HOME)/rdbms/demo \ + -I$(ORACLE_HOME)/rdbms/public \ + -I$(ORACLE_HOME)/network/public \ + -I$(ORACLE_HOME)/plsql/public + +world: ../continuity/lib/oracle.so + +../continuity/lib/oracle.so: $(OBJS) + $(LD_SHARECMD) -o ../continuity/lib/oracle.so $(OBJS) $(ORALIBS) + cp oracle.xml ../continuity/lib + +../continuity/lib/oracle.a: $(OBJS) + $(RM) ora_objs/* + (cd ora_objs ; ar x $(ORACLE_HOME)/lib/libclntst8.a) + (cd ora_objs ; ar x $(ORACLE_HOME)/lib/libcore8.a) + (cd ora_objs ; ar x $(ORACLE_HOME)/lib/libcommon8.a) + (cd ora_objs ; ar x $(ORACLE_HOME)/lib/libclient8.a) +# (cd ora_objs ; ar x $(ORACLE_HOME)/lib32/libclntst9.a) +# (cd ora_objs ; ar x $(ORACLE_HOME)/lib32/libcore9.a) +# (cd ora_objs ; ar x $(ORACLE_HOME)/lib32/libcommon9.a) +# (cd ora_objs ; ar x $(ORACLE_HOME)/lib32/libclient9.a) + $(AR_CMD) ../continuity/lib/oracle.a $(OBJS) ora_objs/* + $(RM) ora_objs/* + +clean: + $(RM) $(OBJS) *~ ../continuity/lib/oracle.a ../continuity/lib/oracle.so + $(RM) ora_objs/* + +dep: depend +depend: + makedepend -I ../include $(SRCS) diff --git a/mk4/modoracle/Makefile.gorecki b/mk4/modoracle/Makefile.gorecki new file mode 100644 index 0000000..1f195d8 --- /dev/null +++ b/mk4/modoracle/Makefile.gorecki @@ -0,0 +1,60 @@ +# $Header: /san01/cvs/ashpool/csrc/modoracle/Attic/Makefile.gorecki,v 1.1 2004/05/13 07:48:59 eric Exp $ + +include ../continuity/lib/env.mk + +SRCS=ora.c +OBJS=ora.o + +# 64-bit or default install Oracle 9 +#ORALIBS = $(ORACLE_HOME)/lib/libclntst9.a $(ORACLE_HOME)/lib/libcore9.a \ +# $(ORACLE_HOME)/lib/libcommon9.a $(ORACLE_HOME)/lib/libgeneric9.a \ +# $(ORACLE_HOME)/lib/libclient9.a + +# 32-bit install Oracle 9 +#ORALIBS = $(ORACLE_HOME)/lib32/libclntst9.a $(ORACLE_HOME)/lib32/libcore9.a \ +# $(ORACLE_HOME)/lib32/libcommon9.a $(ORACLE_HOME)/lib32/libgeneric9.a \ +# $(ORACLE_HOME)/lib32/libclient9.a + +# 64-bit or default install oracle 8 +#ORALIBS = $(ORACLE_HOME)/lib/libclntst8.a $(ORACLE_HOME)/lib/libcore8.a \ +# $(ORACLE_HOME)/lib/libcommon8.a $(ORACLE_HOME)/lib/libgeneric8.a \ +# $(ORACLE_HOME)/lib/libclient8.a + +#ORALIBS=$(ORACLE_HOME)/lib/libclntsh.dylib + +ORALIBS = -Wl,-rpath -Wl,$(ORACLE_HOME)/lib -L$(ORACLE_HOME)/lib -lclntsh -lcore8 -lcommon8 -lgeneric8 -lclient8 +#ORALIBS = -L$(ORACLE_HOME)/lib32 -lclntsh -lcore9 -lcommon9 -lgeneric9 -lclient9 +#ORALIBS = -L$(ORACLE_HOME)/lib -lclntsh -lcore9 -lcommon9 -lgeneric9 -lclient9 + +CFLAGS=-I../continuity/include $(CONT_FLAGS) \ + -I$(ORACLE_HOME)/rdbms/demo \ + -I$(ORACLE_HOME)/rdbms/public \ + -I$(ORACLE_HOME)/network/public \ + -I$(ORACLE_HOME)/plsql/public + +world: ../continuity/lib/oracle.so + +../continuity/lib/oracle.so: $(OBJS) + $(LD_SHARECMD) -o ../continuity/lib/oracle.so $(OBJS) $(ORALIBS) + cp oracle.xml ../continuity/lib + +../continuity/lib/oracle.a: $(OBJS) + $(RM) ora_objs/* + (cd ora_objs ; ar x $(ORACLE_HOME)/lib/libclntst8.a) + (cd ora_objs ; ar x $(ORACLE_HOME)/lib/libcore8.a) + (cd ora_objs ; ar x $(ORACLE_HOME)/lib/libcommon8.a) + (cd ora_objs ; ar x $(ORACLE_HOME)/lib/libclient8.a) +# (cd ora_objs ; ar x $(ORACLE_HOME)/lib32/libclntst9.a) +# (cd ora_objs ; ar x $(ORACLE_HOME)/lib32/libcore9.a) +# (cd ora_objs ; ar x $(ORACLE_HOME)/lib32/libcommon9.a) +# (cd ora_objs ; ar x $(ORACLE_HOME)/lib32/libclient9.a) + $(AR_CMD) ../continuity/lib/oracle.a $(OBJS) ora_objs/* + $(RM) ora_objs/* + +clean: + $(RM) $(OBJS) *~ ../continuity/lib/oracle.a ../continuity/lib/oracle.so + $(RM) ora_objs/* + +dep: depend +depend: + makedepend -I ../include $(SRCS) diff --git a/mk4/modoracle/ora.c b/mk4/modoracle/ora.c new file mode 100644 index 0000000..bb44cc3 --- /dev/null +++ b/mk4/modoracle/ora.c @@ -0,0 +1,895 @@ +/* + * $Header: /san01/cvs/ashpool/csrc/modoracle/Attic/ora.c,v 1.7 2004/04/02 16:05:45 aleigh Exp $ + * + * Copyright (c) 1994, 2001 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Disclosure, copying, distribution, or transmission of of this code without + * express permission is prohibited. + */ + +/* TODO: + Checkout needs to eval checkin_time and test the connection if it's old + Various oracle functions need to mark the connection as bad if there is an error + */ + +/* Define this if you want connection pooling to be in effect. */ +#define ORA_POOLING + +#include +#include +#include "db.h" +#include + +#define ORA_CONN_AUTOCOMMIT 0 +#define ORA_CONN_TRANSACTION 1 +#define ORA_DML 1 +#define ORA_ROWS 2 + +/* o/~ Words are very unescessary */ + +struct oraSfetch { + struct oraSconn *conn; + /* Oracle will tell us what type this column is */ + OCITypeCode type; + /* will be NULL unless this column happens to be one of the LOB types */ + OCILobLocator *lob; + /* generally used for INSERT and UPDATE; seldom used */ + OCIBind *bind; + /* generally used for SELECT; seldom used except for getting LOBs */ + OCIDefine *def; + /* how many bytes Oracle thinks we need to allocate */ + ub2 size; + /* how many bytes we allocated */ + unsigned buf_size; + /* the stuff above does not change as the rows are fetched */ + /* here's where the actual value from a particular row is kept */ + char *buf; + /* support for array DML: the array of values for this bind variable. */ + int array_count; + char **array_values; + /* 2-byte signed integer indicating null-ness; if null, value will be -1 */ + sb2 is_null; + /* how many bytes are in the buffer above, 0 would mean empty string */ + ub2 fetch_length; + /* these are only used for LONGs; the length of one piece */ + ub4 piecewise_fetch_length; + /* + * in order to implement the clob_dml API call, we need 1 LOB for every + * row/column intersection inserted. I.e., if we do an insert that + * results in 4 rows going into the db, with 3 CLOB columns then we need + * 12 LOBs. This struct is for one column only so we just need one array + * of lobs. + */ + OCILobLocator **lobs; + /* this tells us how many lobs we have above (i.e., only for clob_dml) */ + ub4 n_rows; + /* Whether we determined that this column is a LOB during processing. */ + int is_lob; +}; +typedef struct oraSfetch oraTfetch; + +struct oraSconn { + OCIEnv *envhp; + OCIError *errhp; + OCIServer *srvhp; + OCISvcCtx *svchp; + OCISession *usrhp; + + /* Statement that we are executing. */ + OCIStmt *stmthp; + int mode; + sb4 n_columns; + char padding[10]; + oraTfetch *fetch; + + /* These are used by the pooling functionality + and not otherwise needed. */ + char *name; /* do not free */ + char *service; /* do not free */ + unsigned int checkin_time; + int bad; /* If this is 1, the connection will be closed rather than checked in */ +}; +typedef struct oraSconn oraTconn; + +struct oraSpool { + lstTlist *conns; + char *user; + char *service; + int checked_in; + int checked_out; + struct oraSpool *next; +}; +typedef struct oraSpool oraTpool; + +oraTpool *oraGpools = NULL; +pthread_mutex_t oraLpools = PTHREAD_MUTEX_INITIALIZER; + +dvoid *tmp; + +static int lob_buffer_size = 16384; + +static int oraFerror(oraTconn * conn, sword status); +static void oraFalloc_fetch_bufs(oraTconn * conn); +lstTset *oraFbindrow(oraTconn * conn); +int oraFexec(oraTconn * conn, char *sql); +oraTconn *oraFconnect(char *user, char *password, char *service); +oraTconn *oraFpool_checkout(const char *name, const char *password, const char *service); +int oraFclose(oraTconn * conn); +lstTset *oraFselect(oraTconn * conn, const char *sql); +int oraFgetrow(oraTconn * conn, lstTset * row); +static void oraFfree_fetch_bufs(oraTconn * conn); +int oraFflush(oraTconn * conn); +oraTpool *oraFpool_get(char *name, char *service); + +/* + * Return an oracle connection pool entry. This always succeeds. + * because it will create an entry if one does not exist. The caller + * needs to hold oraLpools. + */ +oraTpool *oraFpool_get(char *name, char *service) +{ + oraTpool *pool; + + assert(name != NULL); + assert(service != NULL); + + for (pool = oraGpools; pool != NULL; pool = pool->next) { + if (strcmp((char *) pool->user, (char *) name) == 0 + && strcmp(pool->service, service) == 0) + return pool; + } + + pool = (oraTpool *) malloc(sizeof(oraTpool)); + assert(pool != NULL); + + bzero(pool, sizeof(oraTpool)); + + pool->user = strFcopy(name); + pool->service = strFcopy(service); + + assert(pool->user != NULL); + assert(pool->service != NULL); + + /* We are going to routinely remove elements from the list + when we check them out, so we don't want a desctructor. */ + +/* logFmsg(3,"mod/ora: Creating pool for %s / %s", name, service); */ + + pool->conns = lstFlist_create((void (*)(void *)) NULL); + + pool->next = oraGpools; + oraGpools = pool; + + return pool; +} + +void oraFpool_checkin(oraTconn * conn) +{ + oraTpool *pool; + + pthread_mutex_lock(&oraLpools); + + pool = oraFpool_get(conn->name, conn->service); + + assert(pool != NULL); + + if (conn->bad == 1) { + logFmsg(1, "ora: Connection to %s/%s was marked bad, destroying.", + pool->user, pool->service); + oraFclose(conn); + pool->checked_out--; + pthread_mutex_unlock(&oraLpools); + return; + } + + oraFflush(conn); + /* Set the checkin time. This will later be used when the connection + * is checked out to see if it needs to be tested or not. */ + conn->checkin_time = utlFtime(); + + lstFlist_add_next(pool->conns, lstFlist_tail(pool->conns), conn); + + pool->checked_out--; + pool->checked_in++; + + pthread_mutex_unlock(&oraLpools); + +/* logFmsg(0,"ora: Checked in connection to %s/%s.", pool->user, pool->service); */ +} + +oraTconn *oraFpool_checkout(const char *name, const char *password, const char *service) +{ + oraTpool *pool; + oraTconn *conn; + lstTlist_elem *el; + + assert(name != NULL); + assert(service != NULL); + + pthread_mutex_lock(&oraLpools); + + pool = oraFpool_get(name, service); + + assert(pool != NULL); + +/* logFmsg(3,"ora: checked in: %d for %s/%s ", pool->checked_in, pool->user, pool->service); */ + + if (pool->checked_in == 0) { + conn = oraFconnect(name, password, service); + if (conn == NULL) { +/* logFmsg(3,"oraFpool_checkout: oraFconnect() failed."); */ + pthread_mutex_unlock(&oraLpools); + return NULL; + } + +/* logFmsg(3,"ora: oraFpool_checkout: Created new connection to %s/%s.", pool->user, pool->service); */ + + conn->name = pool->user; + conn->service = pool->service; + + pool->checked_out++; + + pthread_mutex_unlock(&oraLpools); + return conn; + } + + el = lstFlist_head(pool->conns); + conn = lstFlist_data(el); + lstFlist_remove(pool->conns, el, 0); + pool->checked_in--; + + pthread_mutex_unlock(&oraLpools); + +/* logFmsg(3,"ora: oraFpool_checkout: Checked out connection to %s/%s.", pool->user, pool->service); */ + return conn; +} + +int oraFinit(void *p, lstTset * opts) +{ + dbTvector *vector; + +#ifdef ORA_POOLING + logFmsg(0, "mod/oracle: Oracle RDBMS Interface + Pooling (module)"); +#else + logFmsg(0, "mod/oracle: Oracle RDBMS Interface (module)"); +#endif + + logFmsg(0, "mod/oracle: Copyright (c) 2002, Alex Leigh"); + + OCIInitialize((ub4) OCI_THREADED | OCI_OBJECT, (dvoid *) 0, + (dvoid * (*)())0, (dvoid * (*)())0, (void (*)()) 0); + + vector = (dbTvector *) malloc(sizeof(dbTvector)); + + vector->init_fn = (void (*)(void)) oraFinit; + +#ifndef ORA_POOLING + vector->open_fn = (void *(*)(char *, char *, char *)) oraFconnect; + vector->close_fn = (int (*)(void *)) oraFclose; +#else + vector->open_fn = + (void *(*)(char *, char *, char *)) oraFpool_checkout; + vector->close_fn = (int (*)(void *)) oraFpool_checkin; +#endif + + vector->select_fn = (lstTset * (*)(void *, const char *)) oraFselect; + vector->getrow_fn = (int (*)(void *, lstTset *)) oraFgetrow; + vector->dml_fn = (int (*)(void *, char *)) oraFexec; + dbFvector_register(vector); + + return 0; +} + +/* + * -1 error + * 0 data + * 2 no data + */ +int oraFgetrow(oraTconn * conn, lstTset * row) +{ + sword status; + int i; + ub4 ret_len = 0; + + assert(conn != NULL); + assert(row != NULL); + assert(conn->stmthp != NULL); + assert(conn->errhp != NULL); + + status = + OCIStmtFetch(conn->stmthp, conn->errhp, 1, OCI_FETCH_NEXT, + OCI_DEFAULT); + + if (status == OCI_NO_DATA) { + oraFflush(conn); + return 2; + } + if (oraFerror(conn, status) != 0) { + oraFflush(conn); + return -1; + } + for (i = 0; i < conn->n_columns; i++) { + oraTfetch *fetchbuf = &conn->fetch[i]; + + switch (fetchbuf->type) { + default: + /* Add null termination and then add it to the set */ + if (fetchbuf->is_null == -1) { + fetchbuf->buf[0] = NULL; + } else if (fetchbuf->is_null != 0) { + oraFflush(conn); + return -1; + } + fetchbuf->buf[fetchbuf->fetch_length] = NULL; + + lstFset_add_value(row, i, fetchbuf->buf); +/* logFmsg(3, "value: %s", fetchbuf->buf); */ + break; + } + } + return 0; +} + +/* + * In cases where a "bad" error have occured, this function also will + * now mark the connection as bad. This means that it will be destroyed + * rather than be returned to the pool. + */ +static int oraFerror(oraTconn * conn, sword status) +{ + text errbuf[512]; + ub4 buflen; + ub4 errcode; + + switch (status) { + case OCI_SUCCESS: + return 0; + case OCI_SUCCESS_WITH_INFO: + logFmsg(1, "Error - OCI_SUCCESS_WITH_INFO"); + break; + case OCI_NEED_DATA: + logFmsg(1, "Error - OCI_NEED_DATA"); + break; + case OCI_NO_DATA: + logFmsg(1, "Error - OCI_NO_DATA"); + break; + case OCI_ERROR: + OCIErrorGet((dvoid *) conn->errhp, (ub4) 1, (text *) NULL, + (dvoid *) & errcode, errbuf, (ub4) sizeof(errbuf), + (ub4) OCI_HTYPE_ERROR); + strFstrip_crlf((char *) errbuf, strlen((const char *) errbuf)); + logFmsg(1, "%s", errbuf); + conn->bad = 1; + break; + case OCI_INVALID_HANDLE: + logFmsg(1, "Error - OCI_INVALID_HANDLE"); + conn->bad = 1; + break; + case OCI_STILL_EXECUTING: + logFmsg(1, "Error - OCI_STILL_EXECUTE"); + conn->bad = 1; + break; + case OCI_CONTINUE: + logFmsg(1, "Error - OCI_CONTINUE"); + break; + default: + break; + } + + return 1; +} + +static void oraFfree_fetch_bufs(oraTconn * conn) +{ + if (conn != NULL && conn->fetch != NULL) { + int i; + sword oci_status; + + for (i = 0; i < conn->n_columns; i++) { + /* + * oraTfetch *fetchbuf = (oraTfetch *) conn->fetch + + * (sizeof(oraTfetch) * i); + */ + oraTfetch *fetchbuf = &conn->fetch[i]; + + /* oraTfetch *fetchbuf = (oraTfetch *) & conn->fetch[i]; */ + /* logFmsg(3,"fetchbuf set to %d 0x%x", i, fetchbuf); */ + + + /* + * if (fetchbuf->lob != NULL) { oraFerror(conn, + * OCIDescriptorFree(fetchbuf->lob, OCI_DTYPE_LOB)); fetchbuf->lob = + * NULL; } + */ + /* + * fetchbuf->bind is automatically deallocated when its statement is + * deallocated. + * + * Same for fetchbuf->def, I believe, though the manual doesn't say. + */ + + if (fetchbuf->buf != NULL) { + free(fetchbuf->buf); + fetchbuf->buf = NULL; + fetchbuf->buf_size = 0; + } + /* + * if (fetchbuf->lobs != 0) { for (i = 0; i < fetchbuf->n_rows; i++) + * { oraFerror(conn, OCIDescriptorFree(fetchbuf->lobs[i], + * OCI_DTYPE_LOB)); } free(fetchbuf->lobs); fetchbuf->lobs = NULL; + * fetchbuf->n_rows = 0; } + */ + } + + free(conn->fetch); + conn->fetch = NULL; + } +} + + +static void oraFalloc_fetch_bufs(oraTconn * conn) +{ + int i; + + /* + * logFmsg(3, "alloc: allocating fetch buffers %d", conn->n_columns * + * sizeof(oraTfetch)); + */ + + conn->fetch = malloc(conn->n_columns * sizeof(struct oraSfetch)); + assert(conn->fetch != NULL); + + /* logFmsg(3, "Allocated fetchbuffers at 0x%x", conn->fetch); */ + + for (i = 0; i < conn->n_columns; i++) { + oraTfetch *fetchbuf = &conn->fetch[i]; + /* + * oraTfetch *fetchbuf = (oraTfetch *) conn->fetch + (sizeof(oraTfetch) * + * i); + */ + + bzero(fetchbuf, sizeof(oraTfetch)); + fetchbuf->conn = conn; + } +} + +lstTset *oraFbindrow(oraTconn * conn) +{ + sword status; + lstTset *set; + int i; + + assert(conn != NULL); + + set = lstFset_create("row"); + + if (conn->stmthp == NULL) { + logFmsg(1, "oraFbindrow: No active query statment."); + return NULL; + } + if (conn->fetch != NULL) { + logFmsg(1, "oraFbindrow: Query already bound."); + return NULL; + } + if (oraFerror(conn, OCIAttrGet(conn->stmthp, OCI_HTYPE_STMT, + (dvoid *) & conn->n_columns, NULL, + OCI_ATTR_PARAM_COUNT, + conn->errhp)) != 0) + return NULL; + + oraFalloc_fetch_bufs(conn); + + for (i = 0; i < conn->n_columns; i++) { + OCIParam *param; + char name[512]; + char *name1 = 0; + ub4 name1_size = 0; + + /* Set the current fetch buffer */ + oraTfetch *fetchbuf = &conn->fetch[i]; + /* + * oraTfetch *fetchbuf = (oraTfetch *) conn->fetch + (sizeof(oraTfetch) * + * i); + */ + /* logFmsg(3,"fetchbuf set to %d 0x%x", i, fetchbuf); */ + + /* fetchbuf = (oraTfetch *) & conn->fetch[i]; */ + + if (oraFerror(conn, OCIParamGet(conn->stmthp, OCI_HTYPE_STMT, + conn->errhp, (dvoid *) & param, + i + 1)) != 0) + return NULL; + + if (oraFerror + (conn, + OCIAttrGet(param, OCI_DTYPE_PARAM, (dvoid *) & name1, + &name1_size, OCI_ATTR_NAME, conn->errhp)) != 0) + return NULL; + + /* + * * Oracle gives us back a pointer to a string that is not + * null-terminated so we copy it into our local var and add a 0 at the + * end + */ + memcpy(name, name1, name1_size); + name[name1_size] = 0; + + /* logFmsg(3, "lstFset_add '%s' %s", name, "null"); */ + lstFset_add(set, name, "null"); + + /* Get the column type. */ + + if (oraFerror + (conn, + OCIAttrGet(param, OCI_DTYPE_PARAM, &fetchbuf->type, NULL, + OCI_ATTR_DATA_TYPE, conn->errhp)) != 0) + return NULL; + + + /* logFmsg(3, "type is %d", fetchbuf->type); */ + + switch (fetchbuf->type) { + /* we handle LOBs in the loop below */ + case OCI_TYPECODE_CLOB: + case OCI_TYPECODE_BLOB: + break; + + /* + * RDD is Oracle's happy fun name for ROWID (18 chars long but if + * you ask Oracle the usual way, it will give you a number that is + * too small) + */ + case SQLT_RDD: + fetchbuf->size = 18; + fetchbuf->buf_size = fetchbuf->size + 32; + fetchbuf->buf = malloc(fetchbuf->buf_size); + break; + + case SQLT_NUM: + /* + * OCI reports that all NUMBER values has a size of 22, the size of + * its internal storage format for numbers. We are fetching all + * values out as strings, so we need more space. Empirically, it + * seems to return 41 characters when it does the NUMBER to STRING + * conversion. + */ + fetchbuf->size = 41; + fetchbuf->buf_size = fetchbuf->size + 8; + fetchbuf->buf = malloc(fetchbuf->buf_size); + break; + + /* this might work if the rest of our LONG stuff worked */ + case SQLT_LNG: + fetchbuf->buf_size = lob_buffer_size; + fetchbuf->buf = malloc(fetchbuf->buf_size); + break; + default: + /* get the size */ + + if (oraFerror(conn, OCIAttrGet(param, + OCI_DTYPE_PARAM, + (dword *) & fetchbuf->size, + NULL, + OCI_ATTR_DATA_SIZE, + conn->errhp)) != 0) + return NULL; + + /* logFmsg(3, "column '%s' size '%d'", name, fetchbuf->size); */ + + /* + * this is the important part, we allocate buf to be 8 bytes more + * than Oracle says are necessary (for null termination) + */ + fetchbuf->buf_size = fetchbuf->size + 32; + fetchbuf->buf = malloc(fetchbuf->buf_size); + /* + * logFmsg(0, "Fetchbuf %d 0x%x -> buf = 0x%x", i, &fetchbuf->buf, + * fetchbuf->buf); + */ + + break; + } + } + + /* + * loop over the columns again; this could now be in the loop above but we + * originally did things this way to permit resizing of buffers + * + * Now we're telling Oracle to associate the buffers we just allocated with + * their respective columns + */ + for (i = 0; i < conn->n_columns; i++) { + oraTfetch *fetchbuf = &conn->fetch[i]; + /* + * oraTfetch *fetchbuf = (oraTfetch *) conn->fetch + (sizeof(oraTfetch) * + * i); + */ + /* logFmsg(3,"fetchbuf set to %d 0x%x", i, fetchbuf); */ + + + /* + * logFmsg(3, "2nd pass: conn->fetch[%d]->buf is 0x%x", i, + * fetchbuf->buf); logFmsg(3, "2nd pass: LOB is 0x%x", fetchbuf->lob); + */ + + switch (fetchbuf->type) { + case OCI_TYPECODE_CLOB: + case OCI_TYPECODE_BLOB: + /* + * we allocate descriptors for CLOBs; these are essentially + * pointers. We will not allocate any buffers for them until we're + * actually fetching data from individual rows. + */ + if (oraFerror(conn, OCIDescriptorAlloc(conn->envhp, + (void *) &fetchbuf->lob, + OCI_DTYPE_LOB, + 0, 0)) != 0) + return NULL; + + if (oraFerror(conn, OCIDefineByPos(conn->stmthp, + &fetchbuf->def, + conn->errhp, + i + 1, + (void *) &fetchbuf->lob, + -1, fetchbuf->type, + &fetchbuf->is_null, + 0, 0, OCI_DEFAULT)) != 0) + return NULL; + break; + + case SQLT_LNG: + if (oraFerror(conn, OCIDefineByPos(conn->stmthp, + &fetchbuf->def, + conn->errhp, + i + 1, + 0, + (sb4) SB4MAXVAL, + fetchbuf->type, + &fetchbuf->is_null, + &fetchbuf->fetch_length, + 0, OCI_DYNAMIC_FETCH)) != 0) + return NULL; + break; + + default: + + /* logFmsg(0, "definebypos %d 0x%x", i, fetchbuf->buf); */ + + if (oraFerror(conn, OCIDefineByPos(conn->stmthp, + &fetchbuf->def, + conn->errhp, + i + 1, + fetchbuf->buf, + fetchbuf->buf_size, + SQLT_STR, + &fetchbuf->is_null, + &fetchbuf->fetch_length, + NULL, OCI_DEFAULT)) != 0) + return NULL; + break; + } + } + + return set; +} + + +/* + * Returns 1 for select or 2 for DML + */ +int oraFexec(oraTconn * conn, char *sql) +{ + ub4 iters = 0; + ub2 type; + sword status; + + assert(conn != NULL); + assert(sql != NULL); + + status = + OCIHandleAlloc(conn->envhp, (dvoid **) & conn->stmthp, + OCI_HTYPE_STMT, 0, NULL); + if (oraFerror(conn, status) != 0) + return -1; + + status = + OCIStmtPrepare(conn->stmthp, conn->errhp, (text *) sql, + strlen(sql), OCI_NTV_SYNTAX, OCI_DEFAULT); + if (oraFerror(conn, status) != 0) + return -1; + + status = + OCIAttrGet(conn->stmthp, OCI_HTYPE_STMT, (dvoid *) & type, NULL, + OCI_ATTR_STMT_TYPE, conn->errhp); + if (oraFerror(conn, status) != 0) + return -1; + + /* + * Values returned for AttrGet OCI_HTYPE_STMT OCI_STMT_SELECT + * OCI_STMT_UPDATE OCI_STMT_DELETE OCI_STMT_INSERT OCI_STMT_CREATE + * OCI_STMT_DROP OCI_STMT_ALTER OCI_STMT_BEGIN OCI_STMT_DECLARE + */ + + if (type != OCI_STMT_SELECT) + iters = 1; + + status = + OCIStmtExecute(conn->svchp, conn->stmthp, conn->errhp, iters, 0, + NULL, NULL, OCI_DEFAULT); + if (oraFerror(conn, status) != 0) + return -1; + + if (type == OCI_STMT_SELECT) + return ORA_ROWS; + else { + OCITransCommit(conn->svchp, conn->errhp, OCI_DEFAULT); + return ORA_DML; + } +} + +/* + * TODO: Under error conditions thos code leaks any of the handles previously + * allocated when it frees conn. + */ +oraTconn *oraFconnect(char *user, char *password, char *service) +{ + oraTconn *conn = malloc(sizeof(oraTconn)); + + assert(user != NULL); + assert(password != NULL); + assert(service != NULL); + + assert(conn != NULL); + +/* logFmsg(3,"mod/oracle: oraFconnect() called. [u: %s] [s: %s]",user, service); */ + + bzero(conn, sizeof(oraTconn)); + + OCIHandleAlloc((dvoid *) NULL, (dvoid **) & conn->envhp, + (ub4) OCI_HTYPE_ENV, 52, (dvoid **) & tmp); + + OCIEnvInit(&conn->envhp, (ub4) OCI_DEFAULT, 21, (dvoid **) & tmp); + + OCIHandleAlloc((dvoid *) conn->envhp, (dvoid **) & conn->errhp, + (ub4) OCI_HTYPE_ERROR, 52, (dvoid **) & tmp); + + OCIHandleAlloc((dvoid *) conn->envhp, (dvoid **) & conn->srvhp, + (ub4) OCI_HTYPE_SERVER, 52, (dvoid **) & tmp); + + if (oraFerror + (conn, + OCIServerAttach(conn->srvhp, conn->errhp, (text *) service, + (sb4) strlen(service), (ub4) OCI_DEFAULT)) != 0) { + free(conn); + return NULL; + } + OCIHandleAlloc((dvoid *) conn->envhp, (dvoid **) & conn->svchp, + (ub4) OCI_HTYPE_SVCCTX, 52, (dvoid **) & tmp); + + /* set attribute server context in the service context */ + OCIAttrSet((dvoid *) conn->svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) conn->srvhp, (ub4) 0, + (ub4) OCI_ATTR_SERVER, (OCIError *) conn->errhp); + + /* allocate a user context handle */ + OCIHandleAlloc((dvoid *) conn->envhp, (dvoid **) & conn->usrhp, + (ub4) OCI_HTYPE_SESSION, (size_t) 0, (dvoid **) 0); + + OCIAttrSet((dvoid *) conn->usrhp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) user, (ub4) strlen(user), + OCI_ATTR_USERNAME, conn->errhp); + + OCIAttrSet((dvoid *) conn->usrhp, (ub4) OCI_HTYPE_SESSION, + (dvoid *) password, (ub4) strlen(password), + OCI_ATTR_PASSWORD, conn->errhp); + + if (oraFerror + (conn, + OCISessionBegin(conn->svchp, conn->errhp, conn->usrhp, + OCI_CRED_RDBMS, OCI_DEFAULT)) != 0) { + free(conn); + return NULL; + } + OCIAttrSet((dvoid *) conn->svchp, (ub4) OCI_HTYPE_SVCCTX, + (dvoid *) conn->usrhp, (ub4) 0, + OCI_ATTR_SESSION, conn->errhp); + + return conn; +} + +int oraFclose(oraTconn * conn) +{ + + /* these are basically redundant now, I think */ + oraFflush(conn); + + OCISessionEnd(conn->svchp, conn->errhp, conn->usrhp, + (ub4) OCI_DEFAULT); + OCIServerDetach(conn->srvhp, conn->errhp, (ub4) OCI_DEFAULT); + oraFerror(conn, + OCIHandleFree((dvoid *) conn->srvhp, + (ub4) OCI_HTYPE_SERVER)); + oraFerror(conn, + OCIHandleFree((dvoid *) conn->svchp, + (ub4) OCI_HTYPE_SVCCTX)); + oraFerror(conn, + OCIHandleFree((dvoid *) conn->errhp, (ub4) OCI_HTYPE_ERROR)); + + oraFerror(conn, + OCIHandleFree((dvoid *) conn->envhp, (ub4) OCI_HTYPE_ENV)); + + free(conn); + + return 0; +} + +lstTset *oraFselect(oraTconn * conn, const char *sql) +{ + + assert(conn != NULL); + assert(sql != NULL); + + oraFflush(conn); + + if (oraFexec(conn, sql) == ORA_ROWS) { + return oraFbindrow(conn); + } else { + return NULL; + } +} + +int oraFflush(oraTconn * conn) +{ + int i; + + assert(conn != NULL); + + if (conn->stmthp != NULL) { + if (oraFerror(conn, OCIHandleFree(conn->stmthp, OCI_HTYPE_STMT)) != + 0) + return -1; + conn->stmthp = NULL; + } + if (conn->fetch != NULL) { + for (i = 0; i < conn->n_columns; i++) { + oraTfetch *fetchbuf = &conn->fetch[i]; + /* + * oraTfetch *fetchbuf = (oraTfetch *) conn->fetch + + * (sizeof(oraTfetch) * i); + */ + + if (fetchbuf->lob != NULL) { + if (oraFerror + (conn, + OCIDescriptorFree(fetchbuf->lob, OCI_DTYPE_LOB)) != 0) + return -1; + fetchbuf->lob = NULL; + } + if (fetchbuf->buf != NULL) + free(fetchbuf->buf); + if (fetchbuf->array_values != NULL) + free(fetchbuf->array_values); + + if (fetchbuf->lobs != 0) { + int k; + for (k = 0; k < fetchbuf->n_rows; k++) { + if (oraFerror + (conn, + OCIDescriptorFree(fetchbuf->lobs[k], + OCI_DTYPE_LOB)) != 0) + return -1; + } + free(fetchbuf->lobs); + fetchbuf->lobs = NULL; + fetchbuf->n_rows = 0; + } + } + free(conn->fetch); + conn->fetch = NULL; + } + return 0; +} diff --git a/mk4/modoracle/oracle.xml b/mk4/modoracle/oracle.xml new file mode 100644 index 0000000..a5d00ef --- /dev/null +++ b/mk4/modoracle/oracle.xml @@ -0,0 +1,7 @@ + + oracle + oraFinit + + db + + diff --git a/mk4/modradius/CVS/Entries b/mk4/modradius/CVS/Entries new file mode 100644 index 0000000..cf02f62 --- /dev/null +++ b/mk4/modradius/CVS/Entries @@ -0,0 +1,5 @@ +/Makefile.in/1.3/Thu May 13 13:38:55 2004//Tmk4_mod6_rc2 +/radius.c/1.11/Wed May 19 18:34:08 2004//Tmk4_mod6_rc2 +/radius.h/1.2/Tue Mar 16 16:25:38 2004//Tmk4_mod6_rc2 +/radius.xml/1.1/Thu May 13 13:38:55 2004//Tmk4_mod6_rc2 +D diff --git a/mk4/modradius/CVS/Repository b/mk4/modradius/CVS/Repository new file mode 100644 index 0000000..7f2e0e8 --- /dev/null +++ b/mk4/modradius/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/modradius diff --git a/mk4/modradius/CVS/Root b/mk4/modradius/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/modradius/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/modradius/CVS/Tag b/mk4/modradius/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/modradius/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/modradius/Makefile.in b/mk4/modradius/Makefile.in new file mode 100644 index 0000000..12a0eae --- /dev/null +++ b/mk4/modradius/Makefile.in @@ -0,0 +1,24 @@ +# $Header: /san01/cvs/ashpool/csrc/modradius/Attic/Makefile.in,v 1.3 2004/05/13 13:38:55 aleigh Exp $ + +include ../continuity/lib/env.mk + +SRCS=radius.c +OBJS=radius.o + +CFLAGS=-I../continuity/include $(CONT_FLAGS) + +world: install + +radius.so: $(OBJS) + $(LD_SHARECMD) -o radius.so $(OBJS) +clean: + $(RM) $(OBJS) *~ radius.so + +install: radius.so radius.h + (rm -f ../continuity/lib/radius.so ; cp radius.so ../continuity/lib) + cp radius.h ../continuity/include + cp radius.xml ../continuity/lib + +depend: + $(MAKEDEPEND) $(DEPFLAGS) -I ../continuity/include $(SRCS) + diff --git a/mk4/modradius/radius.c b/mk4/modradius/radius.c new file mode 100644 index 0000000..4f8fcd8 --- /dev/null +++ b/mk4/modradius/radius.c @@ -0,0 +1,526 @@ +/* + * $Header: /san01/cvs/ashpool/csrc/modradius/Attic/radius.c,v 1.11 2004/05/19 18:34:08 aleigh Exp $ + */ + +/* + * Copyright (c) 2004 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Use, disclosure, copying, distribution, or transmission of this code without + * express permission is prohibited. + */ + +/* RFC 2865: Radius */ + +#include "radius.h" + +#include + +#define RAD_IPADDR 1 +#define RAD_STRING 2 +#define RAD_INTEGER 3 +#define RAD_TEXT 4 +#define RAD_TIME 5 + +/** Protocol Structures **/ +struct radSheader { + uint8_t code; + uint8_t id; + uint16_t len; + unsigned char resp_auth[16]; +}; +typedef struct radSheader radTheader; + +struct radSattrib_header { + uint8_t type; + uint8_t len; +}; +typedef struct radSattrib_header radTattrib_header; + +/** User Structures **/ +struct radSattrib_def { + int id; // The Radius protocol ID for this attribute. + int type; // The type for this attrib; RAD_IPADDR, RAD_INTEGER, etc + const char *name; // The english name for this attribute. +}; +typedef struct radSattrib_def radTattrib_def; + +struct radSrequest { + int req_code; // The request protocol packet type. + int req_id; // The request protocol sequence identifier. + int res_code; // The response protocol packet type + + unsigned char auth[16]; // The protocol authenticator + lstTset *req_set; + lstTset *res_set; +}; +typedef struct radSrequest radTtrans; + +static int radGsock = -1; +static dicTdictionary *radGattribs; + +static void radFconfig(void); +static void radFconfig_attribs(const xmlTtag *attribs); +static void radFdump(unsigned char *msg, ssize_t msg_len); +static void radFrunloop(void); +void radF_attrib_free(radTattrib_def *attrib); +static int radFtype_find(const char *type); +static int radFattrib_value_format(unsigned char *buf, size_t buf_len, + unsigned char *attrib, size_t attrib_len, + int type, size_t *value_len); +static void radFcalc_digest(unsigned char *digest, + unsigned char *secret, + unsigned char *vector); +static int radFdecrypt_password( + radTtrans *t, + unsigned char *buf, + size_t buf_len, + unsigned char *data, + size_t data_len); +static radTtrans *radFtrans_init(void); +static void radFtrans_free(radTtrans *r); + +/***/ + +static int radFtype_find(const char *type) { + if(strcasecmp(type,"ipaddr")==0) return RAD_IPADDR; + if(strcasecmp(type,"string")==0) return RAD_STRING; + if(strcasecmp(type,"integer")==0) return RAD_INTEGER; + if(strcasecmp(type,"text")==0) return RAD_TEXT; + if(strcasecmp(type,"time")==0) return RAD_TIME; + return -1; +} + +static radTtrans *radFtrans_init(void) { + radTtrans *r=(radTtrans *)malloc(sizeof(radTtrans)); + + assert(r!=NULL); + + bzero(r,sizeof(radTtrans)); + + r->req_set=lstFset_init(); + r->res_set=lstFset_init(); + + assert(r->req_set!=NULL); + assert(r->res_set!=NULL); + + return r; +} + +static void radFtrans_free(radTtrans *r) { + assert(r!=NULL); + assert(r->req_set!=NULL); + assert(r->res_set!=NULL); + + lstFset_free(r->req_set); + lstFset_free(r->res_set); + + free(r); +} + +/* Take a given attribute value and convert it into string form. + * This is intended to be used with the raw data from the radius + * packets, so it does perform network to host byte re-ordering. + * + * Returns 0 on success and -1 on error. + */ +static int radFattrib_value_format(unsigned char *buf, size_t buf_len, + unsigned char *attrib, size_t attrib_len, + int type, size_t *value_len) +{ + unsigned int value; + +// utlFhexdump(attrib,attrib_len); + + switch(type) { + case RAD_IPADDR: + if(buf_len<16) { + return -1; + } + + if(attrib_len!=4) { + return -1; + } + + value=1; + memFcopy(attrib,&value,4); + value=htonl(value); + + utlFip_to_str(value,buf,buf_len); + + *value_len=strlen(buf)+1; + + return 0; + + case RAD_STRING: + /* This really means a binary value */ + if(buf_len in config!"); + exit(5); + } + + child=xmlFfind_first_tag_children(tag,"attribs"); + if(child==NULL) { + logFmsg(2,"mod/radius: Unable to find section!"); + exit(5); + } + + radFconfig_attribs(child); +} + +static void radFconfig_attribs(const xmlTtag *attribs) +{ + xmlTiterator *it; + const xmlTtag *tag; + + assert(attribs!=NULL); + + logFmsg(3,"mod/radius: radFconfig_attribs: Called."); + + it=xmlFiterator_init(attribs); + + assert(it!=NULL); + + while((tag=xmlFiterator_next_name(it,"attrib"))!=NULL) { + const char *id; + const char *name; + size_t name_len; + const char *type; + size_t type_len; + + id=xmlFtag_get_attrib_value(tag,"id"); + + name=xmlFfirst_child_value(tag,"name",&name_len); + type=xmlFfirst_child_value(tag,"type",&type_len); + + if(id!=NULL && name!=NULL && type!=NULL) { + radTattrib_def *def; + + def=(radTattrib_def *)malloc(sizeof(radTattrib_def)); + assert(def!=NULL); + + def->name=name; + def->type=radFtype_find(type); + def->id=atoi(id); + + dicFuserdata_update(radGattribs,def->id,(void *)def); + + logFmsg(3,"mod/radius: %s - %s", id, name); + } + } + + xmlFiterator_free(it); +} + +static radTtrans *radFparse(unsigned char *msg, ssize_t msg_len) +{ + int code; + int id; + int len; + int type; + int i; + radTheader *header = (radTheader *) msg; + radTattrib_header *ah; + size_t attrib_offset=0; + radTtrans *req = radFtrans_init(); + + code = header->code; + id = header->id; + len = header->len; + + memFcopy(header->resp_auth,req->auth,16); + + utlFhexdump(msg,msg_len); + + logFmsg(3, "header is %d", sizeof(radTheader)); + + logFmsg(3,"my size was 0x%x", msg_len); + + logFmsg(3, "code was: %d", code); + logFmsg(3, "id was: %d", id); + logFmsg(3, "len was: %d", len); + + logFmsg(3,"head %d", sizeof(radTattrib_header)); + + for(attrib_offset=0;attrib_offsetlen-20;) { + logFmsg(3,"Offset is %d", attrib_offset); + + ah=(msg+20)+attrib_offset; + + logFmsg(3,"attrib: type %u len %u", ah->type, ah->len); + + radTattrib_def *ad=radFattrib_find_idx(ah->type); + + if(ad==NULL) { + logFmsg(3,"Unable to find attribute defenition."); + } else { + unsigned char buf[1024]; + size_t buf_len; + + if(radFattrib_value_format(buf,1024,(unsigned char *)ah+2, + ah->len-2,ad->type,&buf_len)==0) { + logFmsg(3,"value: %s len: %d", buf, buf_len); + + lstFset_badd(req->req_set, ad->name, strlen(ad->name), buf, buf_len); + } else { + logFmsg(3,"radFattrib_value_format() failed."); + } + logFmsg(3,"Attrib %s", ad->name); + } + attrib_offset+=ah->len; + } + + return req; +} + +static void radFrunloop(void) +{ + unsigned char msg[1024]; + struct sockaddr_in sa; + size_t sa_len; + int ret; + radTtrans *trans; + int radius_auth = dlFpipeline_getid("radius_auth"); + + while (1) { + ret = + netFudp_recv(radGsock, (void *) &msg, sizeof(msg), &sa, + &sa_len); + trans=radFparse(msg, ret); + + ret=dlFpipeline_exec(trans,radius_auth,NULL,NULL); + + radFtrans_free(trans); + } +} + +int radFinit(void *p, lstTset * opt) +{ + uint16_t my_port=0; + + radFconfig(); + + radGsock = netFudp_open(&my_port, 2550, "radius"); + + if (radGsock < 0) { + logFmsg(2, "mod/radius: Unable to open radius UDP socket."); + exit(1); + } + + logFmsg(3, "mod/radius: Opened UDP socket %d on port %d", radGsock, my_port); + + radFrunloop(); + + exit(1); +} + +#define AUTH_VECTOR_LEN 16 +#define AUTH_PASS_LEN 16 +#define AUTH_MAXPASS_LEN 48 + + +/* Given the authentication identifier in the protocol + * and the shared-secret, calculates a digest. + */ +static void radFcalc_digest( + unsigned char *digest, + unsigned char *secret, + unsigned char *vector) +{ + unsigned char buffer[128]; + int secretlen; + + logFmsg(3,"Vector is:"); + utlFhexdump(vector,AUTH_VECTOR_LEN); + + /* Use the secret to setup the decryption digest */ + memset(buffer, 0, sizeof(buffer)); + secretlen = strlen((char *)secret); + memcpy((char *)buffer, (char *)secret,secretlen); + memcpy(buffer + secretlen, vector, AUTH_VECTOR_LEN); + + logFmsg(3,"Calculated string to MD5:"); + utlFhexdump(buffer,secretlen+AUTH_VECTOR_LEN); + + md5_calc(digest, buffer, secretlen + AUTH_VECTOR_LEN); + + logFmsg(3,"Calculated MD5 value:"); + + utlFhexdump(digest,16); + + memset(buffer, 0, secretlen+AUTH_VECTOR_LEN); + + return; +} + +/* I am not entirely convinced that this function works properly + * for passwords that are >16 bytes long. + */ + +static int radFdecrypt_password( + radTtrans *t, + unsigned char *buf, + size_t buf_len, + unsigned char *data, + size_t data_len) +{ + + int i; + int j; + char hold_vector[AUTH_VECTOR_LEN]; + char vector[AUTH_VECTOR_LEN]; + char pw_digest[16]; + char *string; + char *ptr; + + bzero(pw_digest,16); + + radFcalc_digest(pw_digest,"foo",t->auth); + + if(buf_lenreq_set,"User-Name"); + + logFmsg(3,"Packet received."); + + if(un!=NULL) { + logFmsg(3,"Authorization request for user: %s", un); + } + + return STATUS_OK; +} + +int radiusFdecrypt_password(radTtrans *t, lstTset *o) { + const char *pw; + size_t pw_len; + char buf[64]; + + pw=lstFset_get(t->req_set,"Password"); + + if(pw==NULL) { + logFmsg(3,"Password not found?"); + return STATUS_ERROR; + } + + pw_len=lstFset_get_vsize(t->req_set,"Password"); + + utlFhexdump(pw,pw_len); + + radFdecrypt_password(t,buf,sizeof(buf),pw,pw_len); + + lstFset_update(t->req_set,"Password",buf); + + pw=lstFset_get(t->req_set,"Password"); + + logFmsg(3,"Final password is: %s", pw); + + return STATUS_OK; +} + +int radFsend_response(radTtrans *t) { + + +} + + + diff --git a/mk4/modradius/radius.h b/mk4/modradius/radius.h new file mode 100644 index 0000000..170ec36 --- /dev/null +++ b/mk4/modradius/radius.h @@ -0,0 +1,21 @@ +/* + * $Header: /san01/cvs/ashpool/csrc/modradius/Attic/radius.h,v 1.2 2004/03/16 16:25:38 aleigh Exp $ + */ + +/* + * Copyright (c) 1994, 2001 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Use, disclosure, copying, distribution, or transmission of this code without + * express permission is prohibited. + */ + +#ifndef _RADIUS_H +#define _RADIUS_H + +#include + +#endif diff --git a/mk4/modradius/radius.xml b/mk4/modradius/radius.xml new file mode 100644 index 0000000..16a96a9 --- /dev/null +++ b/mk4/modradius/radius.xml @@ -0,0 +1,4 @@ + + radius + radFinit + diff --git a/mk4/modsite/CVS/Entries b/mk4/modsite/CVS/Entries new file mode 100644 index 0000000..260dbc8 --- /dev/null +++ b/mk4/modsite/CVS/Entries @@ -0,0 +1,7 @@ +/Makefile.in/1.4/Tue May 25 14:37:43 2004//Tmk4_mod6_rc2 +/log.c/1.3/Tue May 25 14:47:55 2004//Tmk4_mod6_rc2 +/site.c/1.70/Tue Jun 22 15:55:49 2004//Tmk4_mod6_rc2 +/site.h/1.18/Tue Jun 22 14:31:28 2004//Tmk4_mod6_rc2 +/site.xml/1.2/Wed May 12 14:29:44 2004//Tmk4_mod6_rc2 +/siteerror.h/1.1/Tue Jun 1 15:11:35 2004//Tmk4_mod6_rc2 +D diff --git a/mk4/modsite/CVS/Repository b/mk4/modsite/CVS/Repository new file mode 100644 index 0000000..d5c0223 --- /dev/null +++ b/mk4/modsite/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/modsite diff --git a/mk4/modsite/CVS/Root b/mk4/modsite/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/modsite/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/modsite/CVS/Tag b/mk4/modsite/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/modsite/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/modsite/Makefile.in b/mk4/modsite/Makefile.in new file mode 100644 index 0000000..681e15a --- /dev/null +++ b/mk4/modsite/Makefile.in @@ -0,0 +1,24 @@ +# $Header: /san01/cvs/ashpool/csrc/modsite/Attic/Makefile.in,v 1.4 2004/05/25 14:37:43 aleigh Exp $ + +include ../continuity/lib/env.mk + +SRCS=site.c log.c +OBJS=site.o log.o + +CFLAGS=-I../continuity/include $(CONT_FLAGS) + +world: install + +site.so: $(OBJS) + $(LD_SHARECMD) -o site.so $(OBJS) +clean: + $(RM) $(OBJS) *~ site.so + +install: site.so site.h site.xml + (rm -f ../continuity/lib/site.so ; cp site.so ../continuity/lib) + cp site.h ../continuity/include + cp site.xml ../continuity/lib + + +depend: + $(MAKEDEPEND) -I../continuity/include $(DEPFLAGS) $(SRCS) diff --git a/mk4/modsite/log.c b/mk4/modsite/log.c new file mode 100644 index 0000000..095c074 --- /dev/null +++ b/mk4/modsite/log.c @@ -0,0 +1,433 @@ +#include "../continuity/include/csys.h" +#include "../continuity/mecha/dyn.h" +#include "../continuity/mecha/net.h" +#include "../continuity/include/continuity.h" +#include "../continuity/mecha/lst.h" +#include +#include +#include "site.h" + +static const char *logroot = NULL; /* Path to logging root */ + +#define LOG_AUX 1 +#define LOG_ACCESS 0 + +struct logSfile { + int day; + int month; + int year; + int hour; + int class; + FILE *fh; + unsigned int last_used; + + + struct logSfile *next; + +}; +typedef struct logSfile logTfile; + +static char hostname[64]; +static size_t hostlen; + +static logTfile *logGfile = NULL; + +static pthread_mutex_t logCfile = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t logCfopen = PTHREAD_MUTEX_INITIALIZER; + +int siteFlog_init(void); +static logTfile *logFopen_file(int m, int d, int y, int h, int class); +static logTfile *logFcur_file(int class); +static void logFfile_add(logTfile * f); +static void logFfile_free(logTfile * p); +static int logFreap(int delta); +void logFfile_remove(logTfile * f); +static FILE *logFget_cur_fh(int class); +static int logFwrite(int class, char *format, va_list ap); +int siteFaccess_log(httpTtrans * t, MECHA_UNUSED_ARGUMENT lstTset * opts); + +void siteFset_logroot(const char *lr) { + logroot=lr; +} + +int siteFlog_init(void) +{ + gethostname(hostname, sizeof(hostname)); + hostlen = strlen(hostname); + + return STATUS_OK; +} + +static logTfile *logFopen_file(int m, int d, int y, int h, int class) +{ + char buf[1024]; + logTfile *lf; + int trycount = 5; + + logFreap(3600); + + if (logroot == NULL) + return NULL; + + /* access-04.24.2002.10 */ + + if (class == 1) { + snprintf(buf, sizeof(buf), "%s/aux-%02d.%02d.%d.%02d", logroot, m, + d, y, h); + } else { + snprintf(buf, sizeof(buf), "%s/access-%02d.%02d.%d.%02d", logroot, + m, d, y, h); + } + + lf = (logTfile *) malloc(sizeof(logTfile)); + bzero(lf, sizeof(logTfile)); + + lf->month = m; + lf->day = d; + lf->year = y; + lf->hour = h; + lf->class = class; + lf->last_used = utlFtime(); + + while (trycount != 0) { + lf->fh = fopen(buf, "a"); + + if (lf->fh == NULL) { + logFmsg(2, + "logFopen_file: fopen failure (fn:%s) (er: %d) (tc: %d)", + buf, errno, trycount); + logFreap(0); + } else { + break; + } + + trycount--; + } + + if (lf->fh == NULL) { + logFmsg(2, "Unable to open log after 5 tries, giving up (fn:%s)", + buf); + free(lf); + return NULL; + } + return lf; +} + +/* + * The world was young, the mountains green, No stain yet on the Moon was + * seen, No words were laid on stream or stone When Durin woke and walked + * alone. He named the nameless hills and dells; He drank from yet untasted + * wells; He stooped and looked in Mirrormere And saw a crown of stars + * appear; As gems upon a silver thread; Above the shadow of his head. + * + * The world is grey, the mountains old, The forge's fire is ashen-cold; No harp + * is wrung, no hammer falls: The darkness dwells in Durin's halls; The + * shadow lies upon his tomb In Moria, in Khazad-d?m. But still the sunken + * stars appear In dark and windless Mirrormere; There lies his crown in + * water deep, Till Durin wakes again from his sleep. + */ + +static logTfile *logFcur_file(int class) +{ + logTfile *p; + const struct tm *tme; + + pthread_mutex_lock(&logCfile); + + if (logGfile == NULL) { + pthread_mutex_unlock(&logCfile); + return NULL; + } + p = logGfile; + tme = (const struct tm *) utlFlocaltime(); + + while (1) { + if ((p->month == (tme->tm_mon + 1)) && + (p->day == tme->tm_mday) && + (p->year == (tme->tm_year + 1900)) && + (p->hour == tme->tm_hour) && (p->class == class)) { + pthread_mutex_unlock(&logCfile); + return p; + } + if (p->next == NULL) { + pthread_mutex_unlock(&logCfile); + return NULL; + } + p = p->next; + } +} + +static void logFfile_add(logTfile * f) +{ + pthread_mutex_lock(&logCfile); + f->next = logGfile; + logGfile = f; + pthread_mutex_unlock(&logCfile); +} + +static void logFfile_free(logTfile * p) +{ + if (p != NULL) + free(p); +} + +/* + * logFreap - Close logfiles that haven't been used for some period of time. + */ +static int logFreap(int delta) +{ + logTfile *p, *next; + struct timeval tv; + int i; + + pthread_mutex_lock(&logCfile); + + if (logGfile == NULL) { + pthread_mutex_unlock(&logCfile); + return 0; + } + p = logGfile; + + while (p != NULL) { + gettimeofday(&tv, NULL); + + next = p->next; + + if ((tv.tv_sec - p->last_used) >= (unsigned int) delta) { + logGfile = p->next; + + fclose(p->fh); + + logFfile_free(p); + i++; + } + p = next; + } + + pthread_mutex_unlock(&logCfile); + + return i; +} + +#if 0 +/* + * logFfile_remove - Remove a logfile reference from the global list + * + * This function requires that the global list contain at least one entry and + * does not return an error if the argument entry is not found in the list. + */ + +void logFfile_remove(logTfile * f) +{ + logTfile *p; + + pthread_mutex_lock(&logCfile); + + p = logGfile; + + while (1) { + if (p == f) { + logGfile = p->next; + break; + } + p = p->next; + if (p == NULL) + break; + } + pthread_mutex_unlock(&logCfile); +} +#endif + +static FILE *logFget_cur_fh(int class) +{ + logTfile *file; + + pthread_mutex_lock(&logCfopen); + + file = logFcur_file(class); + + if (file == NULL) { + const struct tm *tme; + tme = (const struct tm *) utlFlocaltime(); + file = + (logTfile *) logFopen_file(tme->tm_mon + 1, tme->tm_mday, + tme->tm_year + 1900, tme->tm_hour, + class); + if (file == NULL) { + pthread_mutex_unlock(&logCfopen); + return NULL; + } + logFfile_add(file); + } + file->last_used = utlFtime(); + + pthread_mutex_unlock(&logCfopen); + return file->fh; +} + +int siteFaccess_log(httpTtrans * t, MECHA_UNUSED_ARGUMENT lstTset * opts) +{ + FILE *fh; + char buf[1024]; + dynTstring *logline; + int ret; + +#ifdef MODSITE_DEBUG + logFmsg(3,"siteFaccess_log: called"); +#endif + + fh = logFget_cur_fh(LOG_ACCESS); + + if (fh == NULL) { + logFmsg(2, "logFget_cur_fh failed (er: %d)", errno); + return STATUS_ERROR; + } + logline = dynFinit(); + + /* CLIENT IP */ + utlFip_to_str(t->cli_ipv4_addr, buf, sizeof(buf)); + dynFsappend(logline, buf); + dynFappend(logline, " ", 1); + + /* EPOCH */ + { + const char *bp = (const char *) utlFcommonlog_time(); + dynFappend(logline, bp, 29); + } + + /* REQUEST */ + dynFappend(logline, "\"", 1); + + { + + const lstTfield *clf = + lstFset_get_field(t->vars, "clf-request", 11); + if (clf != NULL) { + dynFappend(logline, lstFfield_value(clf), + lstFfield_value_len(clf)); + } else { + dynFappend(logline, "REQ_ERR", 7); + } + + dynFappend(logline, "\" ", 2); + } + + /* STATUS */ + /* + * snprintf(buf, sizeof(buf), "%d ", t->res_code); dynFappend(logline, + * buf, strlen(buf)); + */ + dynFappend_print(logline, "%d ", t->res_code); + + { + const lstTfield *length = + lstFset_get_field(t->res_hdrs, "Content-Length", 14); + + if (length != NULL) { + dynFappend(logline, lstFfield_value(length), + lstFfield_value_len(length)); + dynFappend(logline, " ", 1); + } else { + dynFappend(logline, "- ", 2); + } + } + + { + const lstTfield *referer = + lstFset_get_field(t->req_hdrs, "referer", 7); + + if (referer != NULL) { + dynFappend(logline, "\"", 1); + dynFappend(logline, lstFfield_value(referer), + lstFfield_value_len(referer)); + dynFappend(logline, "\" ", 2); + } else { + dynFappend(logline, "\"\" ", 3); + } + } + + { + const lstTfield *agent = + lstFset_get_field(t->req_hdrs, "user-agent", 10); + + if (agent != NULL) { + dynFappend(logline, "\"", 1); + dynFappend(logline, lstFfield_value(agent), + lstFfield_value_len(agent)); + dynFappend(logline, "\" ", 2); + } else { + dynFappend(logline, "\"\" ", 3); + } + } + + /* Country Code Placeholder */ + { + const lstTfield *ccode = lstFset_get_field(t->vars, "ccode", 5); + + if (ccode != NULL) { + dynFappend(logline, lstFfield_value(ccode), + lstFfield_value_len(ccode)); + + dynFappend(logline, " ", 1); + } else { + dynFappend(logline, "-1 ", 3); + } + } + + /* Referer target URL: http://host/URI */ + { + const lstTfield *uri = + lstFset_get_field(t->res_hdrs, "Location", 8); + + if (uri != NULL) { + dynFappend(logline, "\"", 1); + dynFappend(logline, lstFfield_value(uri), + lstFfield_value_len(uri)); + dynFappend(logline, "\" ", 2); + } else { + dynFappend(logline, "- ", 2); + } + } + + /* Response Time Placeholder */ + dynFappend(logline, "-1 ", 3); + + { + const lstTfield *user = lstFset_get_field(t->vars, "auth-user", 9); + if (user != NULL) { + dynFappend(logline, lstFfield_value(user), + lstFfield_value_len(user)); + dynFappend(logline, " ", 1); + } else { + dynFappend(logline, "- ", 2); + } + } + + { + const lstTfield *siteid = lstFset_get_field(t->vars, "siteid", 6); + + if (siteid != NULL) { + dynFappend(logline, lstFfield_value(siteid), + lstFfield_value_len(siteid)); + } else { + dynFappend(logline, "_SID_ERROR", 10); + } + } + + dynFappend(logline, " ", 1); + dynFappend(logline, hostname, hostlen); + + dynFappend(logline, "\n", 1); + + ret = fwrite(dynFgetstr(logline),dynFgetlen(logline),1,fh); + + if (ret < 0 || ret == EOF) { + logFmsg(1, "Log write unexpectadly returned %d/%d", ret, errno); + } + fflush(fh); + + dynFfree(logline); + + return ret; +} + diff --git a/mk4/modsite/site.c b/mk4/modsite/site.c new file mode 100644 index 0000000..ce541c3 --- /dev/null +++ b/mk4/modsite/site.c @@ -0,0 +1,1347 @@ +/* + * $Header: /cvsroot/csrc/modsite/site.c,v 1.51 2004/03/17 15:06:10 aleigh + * Exp $ + */ + +/* + * Copyright (c) 1994, 2001 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Disclosure, copying, distribution, or transmission of this code without + * express permission is prohibited. + */ + +#include "../continuity/include/csys.h" +#include "../continuity/mecha/dyn.h" +#include "../continuity/mecha/net.h" +#include "../continuity/include/continuity.h" +#include "../continuity/mecha/lst.h" +#include +#include +#include "site.h" +#include "siteerror.h" + +#undef MODSITE_DEBUG + +struct siteSacl { + unsigned int ip; + unsigned int netmask; + struct siteSacl *next; +}; +typedef struct siteSacl siteTacl; + +struct siteSsite { + const char *siteid; + size_t siteid_len; + const char *docroot; + size_t docroot_len; + const char *ip_restrict; + const xmlTtag *config; + lstTset *redirects; + hshTvoid_list *external; + hshTvoid_list *options; /* Used to store

%s error.

%s

%s
%s
\n", + error, serror, conFget_build(), hostname); + } else { + httpFwritef(t, + ERROR_FMT, err_string, err_string, err_rfc, err_txt, conFget_build(), hostname); + } + + return STATUS_EXIT; +} + +int siteFfind_mimetype(httpTtrans * t, MECHA_UNUSED_ARGUMENT lstTset * opt) +{ + const char *path, *ext_p, *type; + + path = lstFset_get(t->vars, "path"); + if (path == NULL) { + logFmsg(1, "find_mimetype: path is missing from t->vars!"); + return STATUS_PROCEED; /* Not really an error... */ + } + if ((t->statb.st_mode & S_IFMT) == S_IFDIR) { + lstFset_bupdate(t->res_hdrs, "Content-Type", 12, + "internal/directory", 18); + return STATUS_EXIT; + } + ext_p = strrchr(path, '.'); + + if (ext_p == NULL) + return STATUS_PROCEED; + + ext_p++; + + /* Check to see if the extension is blank */ + if (*ext_p == 0) + return STATUS_PROCEED; + + type = hshFvoid_find(siteGmime_types, ext_p); + + if (type == NULL) { + return STATUS_PROCEED; + } + lstFset_bupdate(t->res_hdrs, "Content-Type", 12, type, strlen(type)); + + return STATUS_EXIT; +} + +int siteFset_mimetype(httpTtrans * t, lstTset * opt) +{ + const lstTfield *type; + + type = lstFset_get_field(opt, "type", 4); + + if (type == NULL) { + logFmsg(2, "force_type: No default mime-type set!"); + return STATUS_ERROR; + } + lstFset_bupdate(t->res_hdrs, "Content-Type", 12, + lstFfield_value(type), lstFfield_value_len(type)); + + return STATUS_PROCEED; +} + +/* + * Send a file. By the time this is called, the current stat structure in the + * request is expected to point to the file that will be served. This file + * will 404 rather than serve a directory. + */ + +int siteFsend_file(httpTtrans * t, MECHA_UNUSED_ARGUMENT lstTset * opt) +{ + const char *path; + char modified[40]; + int ret; + + assert(t != NULL); + + tasFstat_counter_add("http_svc", 0, "siteFsend_file", 1); + + httpFmaterial_compare(t, t); + + if ((t->statb.st_mode & S_IFMT) == S_IFDIR) { + siteFdo_error(t, "404", "Directory found."); + return STATUS_EXIT; + } + if (t->statb.st_mtime == 0) { + /* + * invalid modification time, the stat was likely never done. The + * file is 404. + */ + siteFdo_error(t, "404", "File not found."); + return STATUS_EXIT; + } + path = lstFset_get(t->vars, "path"); + + /* Setup the last-modified time based on the filesystem */ + ret = + utlFhttp_time_print(t->statb.st_mtime, modified, sizeof(modified)); + lstFset_bupdate(t->res_hdrs, "Last-Modified", 13, modified, ret); + +#if WANT_IF_MODIFIED_CHECK + /* + * Check to see if we the client passed us a modified. If it did, check + * to see if we matched, and if we did, return an empty 304 response. The + * client has it cached. + */ + + { + char *hdr_modified; + + hdr_modified = lstFset_get(t->req_hdrs, "if-modified-since"); + + if (hdr_modified != NULL) { + if (t->has_statb == 1 + && t->statb.st_mtime == + utlFhttp_time_parse(hdr_modified)) { +#ifdef MODSITE_DEBUG + logFmsg(3, "sendfile: returning 304."); +#endif + lstFset_nadd(t->res_hdrs, "Content-Length", 0); + + httpFset_status(t, 304, NULL); + httpFstart_response(t); + + return STATUS_EXIT; + } + } + } +#endif + + /* Set the content length and return the file */ + lstFset_nadd(t->res_hdrs, "Content-Length", t->statb.st_size); + + httpFset_status(t, 200, NULL); + httpFstart_response(t); + httpFsend_response(t); + + xfrFmmap(t->conn, path, &t->statb); + + return STATUS_EXIT; +} + +int siteFip_restrict(httpTtrans * t, MECHA_UNUSED_ARGUMENT lstTset * opts) +{ + const char *siteid; + siteTsite *site; + + siteid = lstFset_get(t->vars, "siteid"); + assert(siteid != NULL); + + site = siteFget_by_siteid(siteid); + + assert(site != NULL); + + if (site->ip_restrict != NULL) { + if (siteFipacl_auth(site->ip_restrict, t->cli_ipv4_addr) == 0) { + httpFset_status(t, HTTP_FORBIDDEN, NULL); + httpFstart_response(t); + httpFsend_response(t); + httpFwritef(t, "Access Forbidden"); + return STATUS_EXIT; + } + } + return STATUS_PROCEED; +} + +int siteFredirect(httpTtrans *t, const char *target) { + const char *siteid = lstFset_get(t->vars,"siteid"); + + assert(siteid!=NULL); + + const char *preserve=siteFoption_get(siteid,"preserve_query_on_302"); + if(preserve==NULL) { + return httpFredirect(t,target); + } + + const char *query = lstFset_get(t->vars,"query"); + if(query==NULL) { + return httpFredirect(t,target); + } + + dynTstring *newurl = dynFinit(); + + assert(newurl!=NULL); + + // TODO PERF: This could be done by geting the values and using append rather + // than the more expensive _print() + + if(strstr(target,"?")==NULL) { + dynFappend_print(newurl,"%s?%s",target,query); + } else { + dynFappend_print(newurl,"%s&%s",target,query); + } + + int ret=httpFredirect(t,dynFgetstr(newurl)); + + dynFfree(newurl); + + return ret; +} + + diff --git a/mk4/modsite/site.h b/mk4/modsite/site.h new file mode 100644 index 0000000..27ffdbf --- /dev/null +++ b/mk4/modsite/site.h @@ -0,0 +1,56 @@ +/* $Header: /san01/cvs/ashpool/csrc/modsite/Attic/site.h,v 1.18 2004/06/22 14:31:28 aleigh Exp $ */ + +/* Copyright (c) 1994, 2001 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH + * The copyright notice above does not evidence any + * actual or intended publication of such source code. + * + * Disclosure, copying, distribution, or transmission of + * this code without express permission is prohibited. + */ + +#ifndef SITE_H +#define SITE_H + +#include "continuity.h" +#include "mecha.h" +#include "http.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Handlers */ +int siteFinit(void *p, const lstTset *opts); +int siteFset_siteid(httpTtrans *t, lstTset *opts); +int siteFset_userdir(httpTtrans *t, lstTset *opts); +int siteFfind_index(httpTtrans * t, lstTset * opt); +int siteFfind_mimetype(httpTtrans * t, lstTset * opt); +int siteFset_mimetype(httpTtrans * t, lstTset * opt); +int siteFsend_file (httpTtrans * t, lstTset * opt); +int siteFaccess_log(httpTtrans * t, lstTset *opts); +int siteFip_restrict(httpTtrans *t, lstTset *opts); +int siteFset_setup_path (httpTtrans * t, lstTset * opt); +int siteFset_path_info (httpTtrans * t, lstTset * opt); +int siteFredirects(httpTtrans *t, lstTset *opt); + +int siteFsite_data_set(const char *siteid, const char *name, void *data); +void *siteFsite_data_get(const char *siteid, const char *name); + +const xmlTtag *siteFconfig_get_by_siteid (const char *siteid); + +const char *siteFoption_get(const char *siteid, const char *name); +int siteFoption_set(const char *siteid, const char *name, const char *data); +int siteFredirect(httpTtrans *t, const char *target); + +/* depricated */ +int siteFset_pathinfo(httpTtrans *t, lstTset *opts); +int siteFset_path_translated(httpTtrans *t, lstTset *opts); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/mk4/modsite/site.xml b/mk4/modsite/site.xml new file mode 100644 index 0000000..12356e2 --- /dev/null +++ b/mk4/modsite/site.xml @@ -0,0 +1,8 @@ + + site + siteFinit + + cmd + http + + diff --git a/modsite/siteerror.h b/mk4/modsite/siteerror.h similarity index 100% rename from modsite/siteerror.h rename to mk4/modsite/siteerror.h diff --git a/mk4/modssl/CVS/Entries b/mk4/modssl/CVS/Entries new file mode 100644 index 0000000..0f0353a --- /dev/null +++ b/mk4/modssl/CVS/Entries @@ -0,0 +1,10 @@ +/LICENSE/1.1/Fri Mar 12 20:32:51 2004//Tmk4_mod6_rc2 +/Makefile/1.3/Fri Mar 26 21:04:45 2004//Tmk4_mod6_rc2 +/Makefile.osx/1.1/Fri Mar 12 21:07:20 2004//Tmk4_mod6_rc2 +/client.pem/1.1/Fri Mar 12 20:01:06 2004//Tmk4_mod6_rc2 +/dh1024.pem/1.1/Fri Mar 12 20:01:06 2004//Tmk4_mod6_rc2 +/root.pem/1.1/Fri Mar 12 20:01:06 2004//Tmk4_mod6_rc2 +/server.pem/1.1/Fri Mar 12 20:01:06 2004//Tmk4_mod6_rc2 +/ssl.c/1.7/Wed Apr 21 21:47:05 2004//Tmk4_mod6_rc2 +/ssl.h/1.3/Fri Mar 12 20:10:41 2004//Tmk4_mod6_rc2 +D diff --git a/mk4/modssl/CVS/Repository b/mk4/modssl/CVS/Repository new file mode 100644 index 0000000..d44d7ff --- /dev/null +++ b/mk4/modssl/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/modssl diff --git a/mk4/modssl/CVS/Root b/mk4/modssl/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/modssl/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/modssl/CVS/Tag b/mk4/modssl/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/modssl/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/modssl/LICENSE b/mk4/modssl/LICENSE new file mode 100644 index 0000000..72cd3f2 --- /dev/null +++ b/mk4/modssl/LICENSE @@ -0,0 +1,5 @@ + +This product includes software developed by the OpenSSL Project +for use in the OpenSSL Toolkit (http://www.openssl.org/) + + diff --git a/mk4/modssl/Makefile b/mk4/modssl/Makefile new file mode 100644 index 0000000..d8faa39 --- /dev/null +++ b/mk4/modssl/Makefile @@ -0,0 +1,23 @@ +# $Header: /san01/cvs/ashpool/csrc/modssl/Attic/Makefile,v 1.3 2004/03/26 21:04:45 aleigh Exp $ + +include ../continuity/lib/env.mk + +SRCS=ssl.c +OBJS=ssl.o +OPENSSL=/usr/local/ssl + +CFLAGS=-I../continuity/include $(CONT_FLAGS) -I $(OPENSSL)/include + +world: install + +ssl.so: $(OBJS) + $(LD_SHARECMD) -o ssl.so $(OBJS) -L$(OPENSSL)/lib -lssl -lcrypto + +clean: + $(RM) $(OBJS) *~ ssl.so + +install: ssl.so ssl.h + (rm -f ../continuity/lib/ssl.so ; cp ssl.so ../continuity/lib) + cp ssl.h ../continuity/include + + diff --git a/mk4/modssl/Makefile.osx b/mk4/modssl/Makefile.osx new file mode 100644 index 0000000..636cdda --- /dev/null +++ b/mk4/modssl/Makefile.osx @@ -0,0 +1,23 @@ +# $Header: /san01/cvs/ashpool/csrc/modssl/Attic/Makefile.osx,v 1.1 2004/03/12 21:07:20 aleigh Exp $ + +include ../continuity/lib/env.mk + +SRCS=ssl.c +OBJS=ssl.o +OPENSSL=/usr/local/ssl + +CFLAGS=-I../continuity/include $(CONT_FLAGS) -I $(OPENSSL)/include + +world: install + +ssl.so: $(OBJS) + $(LD_SHARECMD) -o ssl.so $(OBJS) -lssl -lcrypto + +clean: + $(RM) $(OBJS) *~ ssl.so + +install: ssl.so ssl.h + (rm -f ../continuity/lib/ssl.so ; cp ssl.so ../continuity/lib) + cp ssl.h ../continuity/include + + diff --git a/mk4/modssl/client.pem b/mk4/modssl/client.pem new file mode 100644 index 0000000..06f2e6c --- /dev/null +++ b/mk4/modssl/client.pem @@ -0,0 +1,32 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,6D3B09E4CA5421FF + +SaDJA2MhJ12ZmDxfGkSLhQgjYPEQYqVfs5b4DZTz+9pJqzuNxHrZZU43oArbWBdB +3DKc1THejbyHF2lY7xgPLk/5iax5r+CXesDKZroSliHyERBIOCUgDN6ecwvVGtYv +C8IhlwGPEXyxr59lyV37RjkSUVXYBqiRbLlNIcQtp5T6GkFe+yftOnv6/UADCLTS +Pu8xwkda1rf7dgPwYIKuk2SOTTe1VMDtWacRUGu8NteTJ4aiVaeeo9wdsKId5U2b +Z7NTJjOjvdXOLRonfkGvDXmrmN4eICks0bV0ZBtkULAfGjKNGs6riY+XNGKNRmjI +idRRB0za+EGorpiJ/vbe7n7uaFXIJlfqCwhTi4Up3mS8sR4tLHfmdjp85GV9P9B3 +xX3CHIeG5/EYDt0Qn1gRL5ODL/0O7nFGJslhcQUS6bMmcg9nSzhClTE2gREz0j9g +pwzvRpEkIl3Tw4niZLIX8fW2cEIyKTBMCCG2MDwHHgXRL3SUXkOGeitFefkcXN/z +/UWRS8XQcX7/lGWCiuEpgn+esoirjf8lFNVsx6OT0UXj3oBxGrz1iB/vpu/PMBVQ +JsbEPSh/ElHSDUItw2ytjJmkolRtM01b7cFj16ZxbHjinXWTIGZFWUYIlaeA2zHK +D/NRMFJwjrQYhjRgPqltvbw7M01Co7SNFBwSotARr36FBjsxbOH3F1jY6w+kXvJU +X5m83C9UONM2K7kkKYXbE2yW+kzJF2LFX0Uu4yDluxNG767/WwqiQSI63aIzNAPp +rSsaIMBSbVZia8q49gcvGyuvqBZpwm/PcZwr/PHJjvGs8hdU1ACmyQ== +-----END RSA PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIICFTCCAX4CAgECMA0GCSqGSIb3DQEBBAUAMFcxCzAJBgNVBAYTAlVTMRMwEQYD +VQQKEwpSVEZNLCBJbmMuMRkwFwYDVQQLExBXaWRnZXRzIERpdmlzaW9uMRgwFgYD +VQQDEw9UZXN0IENBMjAwMTA1MTcwHhcNMDEwNTE3MTYxMTM2WhcNMDQwMzA2MTYx +MTM2WjBOMQswCQYDVQQGEwJVUzETMBEGA1UEChMKUlRGTSwgSW5jLjEZMBcGA1UE +CxMQV2lkZ2V0cyBEaXZpc2lvbjEPMA0GA1UEAxMGY2xpZW50MIGfMA0GCSqGSIb3 +DQEBAQUAA4GNADCBiQKBgQCHNWSoNh6msUwYGGd7TYQDsdSG0ao6QXaYjk+78ZyM +QeZUBu2dZFjG4wnzkKwrD4rp/J5PLR9AdxR72lb9AavEOKL2UDHJGsscZkGVw/bz +ZbxrKF2rvdpZSvKP1OhV1MOds/WTpRm1gcmVSoV5vLOMqVjzjHoxQ/+1zpjzMxWL +0wIDAQABMA0GCSqGSIb3DQEBBAUAA4GBACTJhRR5tv8A7dc5+zmKR1Q/i8qE3Mrn +mp/MOXHfX+ifJ/w+twoc/yd4En+7pr+hGsiTofct1JOZDW9Akq/ZGu1+NpVRT7Cw +53EdMwpi7ArwZAsLIUBsKA7QmLTbdwjU5S7WlZ24eygZHyqZrK4Few+JuzlFkkoI +FIDCfinyz24m +-----END CERTIFICATE----- diff --git a/mk4/modssl/dh1024.pem b/mk4/modssl/dh1024.pem new file mode 100644 index 0000000..aa68d98 --- /dev/null +++ b/mk4/modssl/dh1024.pem @@ -0,0 +1,5 @@ +-----BEGIN DH PARAMETERS----- +MIGHAoGBANmAnfkETuKHOCWaE+W+F3kM/e7z5A8hZb7OqwGMQrUOaBEAr4BWeZBn +G/87hhwZgNP69/KUchm714qd/PpOspCaUJ20x6PcmKujpAgca/f19HGMBjRawQMk +R9oaBwazuQT0l0rTTKmvpMEcrQQIcVWii3CZI56I56oqF8biGPD7AgEC +-----END DH PARAMETERS----- diff --git a/mk4/modssl/root.pem b/mk4/modssl/root.pem new file mode 100644 index 0000000..db0c59f --- /dev/null +++ b/mk4/modssl/root.pem @@ -0,0 +1,14 @@ +-----BEGIN CERTIFICATE----- +MIICIjCCAYugAwIBAgIBADANBgkqhkiG9w0BAQQFADBXMQswCQYDVQQGEwJVUzET +MBEGA1UEChMKUlRGTSwgSW5jLjEZMBcGA1UECxMQV2lkZ2V0cyBEaXZpc2lvbjEY +MBYGA1UEAxMPVGVzdCBDQTIwMDEwNTE3MB4XDTAxMDUxNzE2MDExNFoXDTA2MTIy +NTE2MDExNFowVzELMAkGA1UEBhMCVVMxEzARBgNVBAoTClJURk0sIEluYy4xGTAX +BgNVBAsTEFdpZGdldHMgRGl2aXNpb24xGDAWBgNVBAMTD1Rlc3QgQ0EyMDAxMDUx +NzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAmkX40warmH0+lnwD9YjsJhRz +ZX6qXadFry0y2trZ6gMs8Mv33IKPwOu8TE7V+3PESEtjI2wr8juV9OkbIPOm+td5 +M8+6vXyIW+JBo3ch99i0QMTf5/jTgsW+3IjV8yEdiGcZFp2NWKLRvZPq2VRbuF7R +1pvgcaRuBJ0wGOohwnsCAwEAATANBgkqhkiG9w0BAQQFAAOBgQCUB8zMKIlX5io8 +TalbzH9Qke7BcvFAL+wp/5w1ToVsWkNrINSWKv6bl/jcqOD3aPhK7qhaeOU8ZWKL +PoPPCnRl9Wo+1JtsOO3qIgJP79Bl9ooLGahixF2v/gea5qNISjQvwYllLSa//APP +6kXHngO0RIRbiTBYHSkAzm6hDdsvVA== +-----END CERTIFICATE----- diff --git a/mk4/modssl/server.pem b/mk4/modssl/server.pem new file mode 100644 index 0000000..87376db --- /dev/null +++ b/mk4/modssl/server.pem @@ -0,0 +1,32 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,5772A2A7BE34B611 + +1yJ+xAn4MudcIfXXy7ElYngJ9EohIh8yvcyVLmE4kVd0xeaL/Bqhvk25BjYCK5d9 +k1K8cjgnKEBjbC++0xtJxFSbUhwoKTLwn+sBoJDcFzMKkmJXXDbSTOaNr1sVwiAR +SnB4lhUcHguYoV5zlRJn53ft7t1mjB6RwGH+d1Zx6t95OqM1lnKqwekwmotVAWHj +ncu3N8qhmoPMppmzEv0fOo2/pK2WohcJykSeN5zBrZCUxoO0NBNEZkFUcVjR+KsA +1ZeI1mU60szqg+AoU/XtFcow8RtG1QZKQbbXzyfbwaG+6LqkHaWYKHQEI1546yWK +us1HJ734uUkZoyyyazG6PiGCYV2u/aY0i3qdmyDqTvmVIvve7E4glBrtDS9h7D40 +nPShIvOatoPzIK4Y0QSvrI3G1vTsIZT3IOZto4AWuOkLNfYS2ce7prOreF0KjhV0 +3tggw9pHdDmTjHTiIkXqheZxZ7TVu+pddZW+CuB62I8lCBGPW7os1f21e3eOD/oY +YPCI44aJvgP+zUORuZBWqaSJ0AAIuVW9S83Yzkz/tlSFHViOebyd8Cug4TlxK1VI +q6hbSafh4C8ma7YzlvqjMzqFifcIolcbx+1A6ot0UiayJTUra4d6Uc4Rbc9RIiG0 +jfDWC6aii9YkAgRl9WqSd31yASge/HDqVXFwR48qdlYQ57rcHviqxyrwRDnfw/lX +Mf6LPiDKEco4MKej7SR2kK2c2AgxUzpGZeAY6ePyhxbdhA0eY21nDeFd/RbwSc5s +eTiCCMr41OB4hfBFXKDKqsM3K7klhoz6D5WsgE6u3lDoTdz76xOSTg== +-----END RSA PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIICGDCCAYECAgEBMA0GCSqGSIb3DQEBBAUAMFcxCzAJBgNVBAYTAlVTMRMwEQYD +VQQKEwpSVEZNLCBJbmMuMRkwFwYDVQQLExBXaWRnZXRzIERpdmlzaW9uMRgwFgYD +VQQDEw9UZXN0IENBMjAwMTA1MTcwHhcNMDEwNTE3MTYxMDU5WhcNMDQwMzA2MTYx +MDU5WjBRMQswCQYDVQQGEwJVUzETMBEGA1UEChMKUlRGTSwgSW5jLjEZMBcGA1UE +CxMQV2lkZ2V0cyBEaXZpc2lvbjESMBAGA1UEAxMJbG9jYWxob3N0MIGfMA0GCSqG +SIb3DQEBAQUAA4GNADCBiQKBgQCiWhMjNOPlPLNW4DJFBiL2fFEIkHuRor0pKw25 +J0ZYHW93lHQ4yxA6afQr99ayRjMY0D26pH41f0qjDgO4OXskBsaYOFzapSZtQMbT +97OCZ7aHtK8z0ZGNW/cslu+1oOLomgRxJomIFgW1RyUUkQP1n0hemtUdCLOLlO7Q +CPqZLQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBAIumUwl1OoWuyN2xfoBHYAs+lRLY +KmFLoI5+iMcGxWIsksmA+b0FLRAN43wmhPnums8eXgYbDCrKLv2xWcvKDP3mps7m +AMivwtu/eFpYz6J8Mo1fsV4Ys08A/uPXkT23jyKo2hMu8mywkqXCXYF2e+7pEeBr +dsbmkWK5NgoMl8eM +-----END CERTIFICATE----- diff --git a/mk4/modssl/ssl.c b/mk4/modssl/ssl.c new file mode 100644 index 0000000..d272c59 --- /dev/null +++ b/mk4/modssl/ssl.c @@ -0,0 +1,196 @@ +/* + * $Header: /san01/cvs/ashpool/csrc/modssl/Attic/ssl.c,v 1.7 2004/04/21 21:47:05 aleigh Exp $ + */ + +/* + * Copyright (c) 1994, 2001 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Use, disclosure, copying, distribution, or transmission of this code without + * express permission is prohibited. + */ + +#include +#include +#include "ssl.h" + +#define KEYFILE "server.pem" +#define PASSWORD "password" + +static SSL_CTX *ctx; +static const char *pass; +static int (*sslGhandler) (netTconn * conn, lstTset * o) = NULL; + +struct sslScontext { + SSL *ssl; + BIO *bio; +}; +typedef struct sslScontext sslTcontext; + +static int password_cb(char *buf, int num, int rwflag, void *userdata) +{ + if (num < strlen(pass) + 1) + return (0); + + strcpy(buf, pass); + return (strlen(pass)); +} + +static SSL_CTX *initialize_ctx(const char *keyfile, const char *password) +{ + SSL_METHOD *meth; + SSL_CTX *ctx; + BIO *bio_err = 0; + + if (!bio_err) { + /* Global system initialization */ + SSL_library_init(); + SSL_load_error_strings(); + + /* An error write context */ + bio_err = BIO_new_fp(stderr, BIO_NOCLOSE); + } + + /* Create our context */ + meth = SSLv23_server_method(); + ctx = SSL_CTX_new(meth); + + /* Load our keys and certificates */ + if (!(SSL_CTX_use_certificate_chain_file(ctx, keyfile))) { + logFmsg(2, "Can't read certificate file."); + exit(1); + } + pass = password; + SSL_CTX_set_default_passwd_cb(ctx, password_cb); + if (!(SSL_CTX_use_PrivateKey_file(ctx, keyfile, SSL_FILETYPE_PEM))) { + logFmsg(2, "Can't read key file."); + exit(1); + } +#if (OPENSSL_VERSION_NUMBER < 0x00905100L) + SSL_CTX_set_verify_depth(ctx, 1); +#endif + + return ctx; +} + +int sslFinit(void *p, lstTset * o) +{ + const char *password, *keyfile, *handler; + + logFmsg(0, "mod/ssl: Secure Sockets Layer (SSL) Engine"); + logFmsg(0, "Copyright (c) 2004, Alex Leigh."); + + password = lstFset_get(o, "cert_password"); + keyfile = lstFset_get(o, "cert_file"); + handler = lstFset_get(o, "handler"); + + if (!keyfile) { + logFmsg(2, "cert_file not specified!"); + exit(1); + } + + if (!password) { + logFmsg(2, "cert_password not specified!"); + exit(1); + } + + if (!handler) { + logFmsg(2, "handler not specified!"); + exit(1); + } + + sslGhandler = dlFget_addr(handler); + if (sslGhandler == NULL) { + logFmsg(2, "Could not map handler: %s", handler); + exit(1); + } + + /* Build our SSL context */ + ctx = initialize_ctx(keyfile, password); +} + +ssize_t sslFio_write(netTconn * conn, const void *buf, size_t len) +{ + sslTcontext *c = (sslTcontext *) conn->data; + ssize_t ret; + + ret = SSL_write(c->ssl, buf, len); + return ret; +} + +ssize_t sslFio_read(netTconn * conn, void *buf, size_t len) +{ + sslTcontext *c = (sslTcontext *) conn->data; + ssize_t ret; + + ret = SSL_read(c->ssl, buf, len); + return ret; +} + +int sslFio_close(netTconn * conn) +{ + sslTcontext *c = (sslTcontext *) conn->data; + int r; + + r = SSL_shutdown(c->ssl); + if (!r) { + shutdown(conn->sd, 1); + r = SSL_shutdown(c->ssl); + } + return close(conn->sd); +} + +ssize_t sslFio_writev(struct netSconn * conn, const struct iovec * iov, + int iovcnt) +{ + int i, r; + ssize_t written = 0; + sslTcontext *c = (sslTcontext *) conn->data; + + for (i = 0; i < iovcnt; i++) { + r = SSL_write(c->ssl, iov[i].iov_base, iov[i].iov_len); + if (r < 1) { + return written; + } + written += r; + } +} + +void sslFprivate_free(sslTcontext * c) +{ + free(c); +} + +int sslFhandler(void *p, const lstTset * arg) +{ + netTconn *conn = (netTconn *) p; + sslTcontext *private = (sslTcontext *) malloc(sizeof(sslTcontext)); + SSL *ssl; + BIO *sbio; + int r; + + sbio = BIO_new_socket(conn->sd, BIO_NOCLOSE); + ssl = SSL_new(ctx); + SSL_set_bio(ssl, sbio, sbio); + + SSL_set_accept_state(ssl); + + if (SSL_accept(ssl) < 1) { + conn->io_close(conn); + return STATUS_ERROR; + } + + private->ssl = ssl; + private->bio = sbio; + + conn->io_close = sslFio_close; + conn->io_write = sslFio_write; + conn->io_read = sslFio_read; + conn->data = private; + conn->data_free = sslFprivate_free; + + return (sslGhandler) (p, arg); +} diff --git a/mk4/modssl/ssl.h b/mk4/modssl/ssl.h new file mode 100644 index 0000000..244b5b3 --- /dev/null +++ b/mk4/modssl/ssl.h @@ -0,0 +1,30 @@ +/* + * $Header: /san01/cvs/ashpool/csrc/modssl/Attic/ssl.h,v 1.3 2004/03/12 20:10:41 aleigh Exp $ + */ + +/* + * Copyright (c) 1994, 2001 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Use, disclosure, copying, distribution, or transmission of this code without + * express permission is prohibited. + */ + +#ifndef _SSL_H +#define _SSL_H + +#include +#include + +int sslFinit(void *p, lstTset * o); +int sslFhandler(void *p, const lstTset * arg); + +ssize_t sslFio_write(netTconn * conn, const void *buf, size_t len); +ssize_t sslFio_read(netTconn * conn, void *buf, size_t len); +int sslFio_close(netTconn * conn); +ssize_t sslFio_writev(struct netSconn * conn, const struct iovec * iov, int iovcnt); + +#endif diff --git a/mk4/modtcl/CVS/Entries b/mk4/modtcl/CVS/Entries new file mode 100644 index 0000000..e0a8e87 --- /dev/null +++ b/mk4/modtcl/CVS/Entries @@ -0,0 +1,3 @@ +/Makefile.in/1.1/Wed May 19 19:48:27 2004//Tmk4_mod6_rc2 +D/src//// +D/tcl8.3.4//// diff --git a/mk4/modtcl/CVS/Repository b/mk4/modtcl/CVS/Repository new file mode 100644 index 0000000..358366a --- /dev/null +++ b/mk4/modtcl/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/modtcl diff --git a/mk4/modtcl/CVS/Root b/mk4/modtcl/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/modtcl/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/modtcl/CVS/Tag b/mk4/modtcl/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/modtcl/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/modtcl/Makefile.in b/mk4/modtcl/Makefile.in new file mode 100644 index 0000000..74a8440 --- /dev/null +++ b/mk4/modtcl/Makefile.in @@ -0,0 +1,17 @@ +# $Id: Makefile.in,v 1.1 2004/05/19 19:48:27 aleigh Exp $ + +world: tcl8.3.4/unix/libtcl8.3.a + (cd src;$(MAKE)) + +clean: + (cd src;$(MAKE) clean) + +realclean: clean + (cd tcl8.3.4/unix;make clean) + +tcl8.3.4/unix/libtcl8.3.a: + (cd tcl8.3.4/unix;./configure --disable-shared --enable-threads;make) +# cp tcl8.3.4/unix/libtcl83.a tcl8.3.4/unix/libtcl8.3.a + +depend: + echo No depend diff --git a/mk4/modtcl/src/CVS/Entries b/mk4/modtcl/src/CVS/Entries new file mode 100644 index 0000000..300a137 --- /dev/null +++ b/mk4/modtcl/src/CVS/Entries @@ -0,0 +1,6 @@ +/Makefile/1.6/Wed May 12 18:00:19 2004//Tmk4_mod6_rc2 +/cmds.c/1.5/Wed Apr 21 21:47:06 2004//Tmk4_mod6_rc2 +/modtcl.c/1.7/Wed Apr 21 21:47:06 2004//Tmk4_mod6_rc2 +/modtcl.h/1.3/Thu Mar 11 00:52:02 2004//Tmk4_mod6_rc2 +/modtcl.xml/1.1/Wed May 12 18:00:19 2004//Tmk4_mod6_rc2 +D diff --git a/mk4/modtcl/src/CVS/Repository b/mk4/modtcl/src/CVS/Repository new file mode 100644 index 0000000..41cf584 --- /dev/null +++ b/mk4/modtcl/src/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/modtcl/src diff --git a/mk4/modtcl/src/CVS/Root b/mk4/modtcl/src/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/modtcl/src/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/modtcl/src/CVS/Tag b/mk4/modtcl/src/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/modtcl/src/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/modtcl/src/Makefile b/mk4/modtcl/src/Makefile new file mode 100644 index 0000000..aed0fb8 --- /dev/null +++ b/mk4/modtcl/src/Makefile @@ -0,0 +1,22 @@ +# $Header: /san01/cvs/ashpool/csrc/modtcl/src/Attic/Makefile,v 1.6 2004/05/12 18:00:19 aleigh Exp $ + +include ../../continuity/lib/env.mk + +SRCS=modtcl.c cmds.c +OBJS=modtcl.o cmds.o + +CFLAGS=-I../../continuity/include -I../tcl8.3.4/generic/ $(CONT_FLAGS) + +world: install + +modtcl.so: $(OBJS) + $(LD_SHARECMD) -o modtcl.so $(OBJS) ../tcl8.3.4/unix/libtcl8.3.a +clean: + $(RM) $(OBJS) *~ modtcl.so + +install: modtcl.so modtcl.h + (rm -f ../../continuity/lib/modtcl.so ; cp modtcl.so ../../continuity/lib) + cp modtcl.h ../../continuity/include + cp ../tcl8.3.4/generic/tcl.h ../../continuity/include + cp ../tcl8.3.4/generic/tclDecls.h ../../continuity/include + cp modtcl.xml ../../continuity/lib diff --git a/mk4/modtcl/src/cmds.c b/mk4/modtcl/src/cmds.c new file mode 100644 index 0000000..cc6d37a --- /dev/null +++ b/mk4/modtcl/src/cmds.c @@ -0,0 +1,764 @@ +#pragma ident "$Header: /san01/cvs/ashpool/csrc/modtcl/src/Attic/cmds.c,v 1.5 2004/04/21 21:47:06 aleigh Exp $" + +/* + * Copyright (c) 1994, 2002 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Disclosure, copying, distribution, or transmission of this code without + * express permission is prohibited. + */ + +#include +#include "db.h" +#include "modtcl.h" + +struct tclSfn_vector { + void (*tclFbind_dyn_command) (char *name, Tcl_CmdProc * proc); +}; +typedef struct tclSfn_vector tclTfn_vector; + +static tclTcmd tclGcmds[] = { + {"ta_log", tclFta_log, NULL}, + {"ta_write", tclFta_write, NULL}, + {"ta_startresponse", tclFta_startresponse, NULL}, + {"ta_setstatus", tclFta_setstatus, NULL}, + {"ta_http_var_get", tclFta_http_vars_get, NULL}, + {"ta_http_res_get", tclFta_http_res_get, NULL}, + {"ta_http_req_get", tclFta_http_req_get, NULL}, + {"ta_http_query_get", tclFhttp_query_get, NULL}, + {"ta_http_var_set", tclFta_http_var_set, NULL}, + {"ta_http_res_set", tclFta_http_res_set, NULL}, + {"ta_http_req_set", tclFta_http_req_set, NULL}, + {"ta_http_query_value", tclFhttp_query_value, NULL}, + {"ta_pwd", tclFta_pwd, NULL}, + {"ta_list_get", tclFlist_get, NULL}, + {"ta_http_query_parse", tclFhttp_query_parse, NULL}, + {"ta_db_open", tclFdb_open, NULL}, + {"ta_db_select", tclFdb_select, NULL}, + {"ta_db_getrow", tclFdb_getrow, NULL}, + {"ta_db_close", tclFdb_close, NULL}, + {"ta_jpg_getsize", tclFjpg_getsize, NULL}, + {"ta_urldecode", tclFurl_decode, NULL}, + {"ta_urlencode", tclFurl_encode, NULL}, + {"tav_set", tclFtav_set, NULL}, + {"tav_get", tclFtav_get, NULL}, + {"tav_exists", tclFtav_exists, NULL}, + {NULL, NULL, NULL} +}; + +static tclTcmd *tclGdyn_cmds = NULL; +static int tclGdyn_count = 0; +/* TLS classes: */ +static int tclGtls_db; /* Database Connections */ + +static hshTvoid_list *tclGtav_hash; +static pthread_rwlock_t tclLtav_hash; + +void tclFbind_dyn_command(char *name, Tcl_CmdProc * proc) +{ + char *n; + + assert(name != NULL); + assert(proc != NULL); + + logFmsg(3, + "Bind external TCL command. cmd: %s addr: 0x%x", + name, proc); + + if (tclGdyn_cmds == 0) { + tclGdyn_cmds = malloc(sizeof(tclTcmd) * 2); + tclGdyn_cmds->name = NULL; + tclGdyn_count = 1; + } else { + tclGdyn_count++; + tclGdyn_cmds = + realloc(tclGdyn_cmds, sizeof(tclTcmd) * (tclGdyn_count + 1)); + } + + n = malloc(strlen(name) + 1); + strcpy(n, name); + + tclGdyn_cmds[tclGdyn_count - 1].name = n; + tclGdyn_cmds[tclGdyn_count - 1].proc = proc; + tclGdyn_cmds[tclGdyn_count].name = NULL; + + return; +} + +/* + * Setup various locals in this file. this is called from the + * initialization function in modtcl.c + */ +void tclFcmd_init(void) +{ + tclGtls_db = tlsFregister((void *(*)(void *)) dbFclose); + tclGtav_hash = hshFvoid_init((void (*)(void *)) lstFset_free); + pthread_rwlock_init(&tclLtav_hash, NULL); +} + +void tclFsetup_cmds(Tcl_Interp * interp) +{ + tclFcmds_register(interp, tclGcmds); + tclFcmds_register(interp, tclGdyn_cmds); +} + +void tclFcmds_register(Tcl_Interp * interp, tclTcmd * cmd) +{ + if (cmd == NULL) + return; + + while (cmd->name != NULL) { + /* + * logFmsg(3,"mod/tcl: tclFcmds_register: Binding proc %s to 0x%x", + * cmd->name, cmd->proc); + */ + Tcl_CreateCommand(interp, cmd->name, cmd->proc, cmd->clientData, + NULL); + ++cmd; + } +} + +int tclFta_log(ClientData ignored, Tcl_Interp * interp, int argc, + char **argv) +{ + if (argc != 3) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " loglevel string\"", NULL); + return TCL_ERROR; + } + logFmsg(atoi(argv[1]), "TCL: %s", argv[2]); + + return TCL_OK; +} + +int tclFta_write(ClientData ignored, Tcl_Interp * interp, int argc, + char **argv) +{ + httpTtrans *t; + + if (argc != 2) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " string\"", NULL); + return TCL_ERROR; + } + t = httpFthread_gettrans(); + assert(t != NULL); + + httpFwrite(t, argv[1], strlen(argv[1])); + + return TCL_OK; +} + +int tclFta_startresponse(ClientData ignored, Tcl_Interp * interp, int argc, + char **argv) +{ + httpTtrans *t; + + if (argc != 1) { + Tcl_AppendResult(interp, "wrong # args: No arguments", NULL); + return TCL_ERROR; + } + t = httpFthread_gettrans(); + assert(t != NULL); + + httpFstart_response(t); + + return TCL_OK; +} + +int tclFta_setstatus(ClientData ignored, Tcl_Interp * interp, int argc, + char **argv) +{ + httpTtrans *t; + + if (argc != 2) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " respcode\"", NULL); + return TCL_ERROR; + } + t = httpFthread_gettrans(); + assert(t != NULL); + + httpFset_status(t, atoi(argv[1]), NULL); + + return TCL_OK; +} + +int tclFta_http_vars_get(ClientData ignored, Tcl_Interp * interp, int argc, + char **argv) +{ + httpTtrans *t; + char *v; + + if (argc != 2) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " string\"", NULL); + return TCL_ERROR; + } + t = httpFthread_gettrans(); + assert(t != NULL); + + v = lstFset_get(t->vars, argv[1]); + + if (v != NULL) { + Tcl_SetResult(interp, v, TCL_VOLATILE); + return TCL_OK; + } + Tcl_SetResult(interp, "", TCL_STATIC); + return TCL_OK; +} + + +int tclFta_http_req_get(ClientData ignored, Tcl_Interp * interp, int argc, + char **argv) +{ + httpTtrans *t; + char *v; + + if (argc != 2) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " string\"", NULL); + return TCL_ERROR; + } + t = httpFthread_gettrans(); + assert(t != NULL); + + v = lstFset_get(t->req_hdrs, argv[1]); + + if (v != NULL) { + Tcl_SetResult(interp, v, TCL_VOLATILE); + return TCL_OK; + } + Tcl_SetResult(interp, "", TCL_STATIC); + return TCL_OK; +} + +int tclFhttp_query_get(ClientData ignored, Tcl_Interp * interp, int argc, + char **argv) +{ + httpTtrans *t; + char *v; + + if (argc != 2) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " string\"", NULL); + return TCL_ERROR; + } + t = httpFthread_gettrans(); + assert(t != NULL); + + v = lstFset_get(t->query, argv[1]); + + if (v != NULL) { + Tcl_SetResult(interp, v, TCL_VOLATILE); + return TCL_OK; + } + Tcl_SetResult(interp, "", TCL_STATIC); + return TCL_OK; +} + + +int tclFta_http_res_get(ClientData ignored, Tcl_Interp * interp, int argc, + char **argv) +{ + httpTtrans *t; + char *v; + + if (argc != 2) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " string\"", NULL); + return TCL_ERROR; + } + t = httpFthread_gettrans(); + assert(t != NULL); + + v = lstFset_get(t->res_hdrs, argv[1]); + + if (v != NULL) { + Tcl_SetResult(interp, v, TCL_VOLATILE); + return TCL_OK; + } + Tcl_SetResult(interp, "", TCL_STATIC); + return TCL_OK; +} + +int tclFta_pwd(ClientData ignored, Tcl_Interp * interp, int argc, + char **argv) +{ + httpTtrans *t; + char *path, *pb, *p; + int len; + + if (argc != 1) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + NULL); + return TCL_ERROR; + } + t = httpFthread_gettrans(); + assert(t != NULL); + + path = lstFset_get(t->vars, "path"); + if (path == NULL) { + Tcl_AppendResult(interp, "Could not get path.", NULL); + return TCL_ERROR; + } + len = strlen(path); + + pb = Tcl_Alloc(len + 1); + strncpy(pb, path, len + 1); + + p = (pb + len); + + while (1) { + if (*p == '/') { + *p = '\0'; + Tcl_SetResult(interp, pb, TCL_DYNAMIC); + return TCL_OK; + break; + } + if (p == pb) { + Tcl_SetResult(interp, "", TCL_STATIC); + return TCL_OK; + } + p--; + } +} + +int tclFta_http_var_set(ClientData ignored, Tcl_Interp * interp, int argc, + char **argv) +{ + httpTtrans *t; + + if (argc != 3) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + "name value", NULL); + return TCL_ERROR; + } + t = httpFthread_gettrans(); + if (t == NULL) { + Tcl_AppendResult(interp, "Could not find transaction.", NULL); + return TCL_ERROR; + } + lstFset_update(t->vars, argv[1], argv[2]); + + return TCL_OK; +} + +int tclFta_http_res_set(ClientData ignored, Tcl_Interp * interp, int argc, + char **argv) +{ + httpTtrans *t; + + if (argc != 3) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + "name value", NULL); + return TCL_ERROR; + } + t = httpFthread_gettrans(); + if (t == NULL) { + Tcl_AppendResult(interp, "Could not find transaction.", NULL); + return TCL_ERROR; + } + lstFset_update(t->res_hdrs, argv[1], argv[2]); + + return TCL_OK; +} + +int tclFta_http_req_set(ClientData ignored, Tcl_Interp * interp, int argc, + char **argv) +{ + httpTtrans *t; + + if (argc != 3) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + "name value", NULL); + return TCL_ERROR; + } + t = httpFthread_gettrans(); + if (t == NULL) { + Tcl_AppendResult(interp, "Could not find transaction.", NULL); + return TCL_ERROR; + } + lstFset_update(t->req_hdrs, argv[1], argv[2]); + + return TCL_OK; +} + +int tclFurl_decode(ClientData ignored, Tcl_Interp * interp, int argc, + char **argv) +{ + dynTstring *dyn; + + if (argc != 2) { + Tcl_AppendResult(interp, "bad argumentation: should be \"", + argv[0], "url\"", NULL); + return TCL_ERROR; + } + dyn = dynFinit(); + utlFurl_decode(dyn, argv[1]); + + Tcl_AppendResult(interp, dynFgetstr(dyn), NULL); + dynFfree(dyn); + return TCL_OK; +} + +int tclFurl_encode(ClientData ignored, Tcl_Interp * interp, int argc, + char **argv) +{ + dynTstring *dyn; + + if (argc != 2) { + Tcl_AppendResult(interp, "bad argumentation: should be \"", + argv[0], "url\"", NULL); + return TCL_ERROR; + } + dyn = dynFinit(); + utlFurl_encode(dyn, argv[1]); + + Tcl_AppendResult(interp, dynFgetstr(dyn), NULL); + dynFfree(dyn); + return TCL_OK; +} + + + +int tclFlist_get(ClientData ignored, Tcl_Interp * interp, int argc, + char **argv) +{ + lstTset *p; + char *d; + + if (argc != 3) { + Tcl_AppendResult(interp, "bad argumentation: should be \"", + argv[0], "list name\"", NULL); + return TCL_ERROR; + } + + p = tlsFget(argv[1], 0); + + if (p == NULL) { + Tcl_SetResult(interp, "", TCL_STATIC); + return TCL_OK; + } + d = lstFset_get(p, argv[2]); + if (d == NULL) { + Tcl_SetResult(interp, "", TCL_STATIC); + return TCL_OK; + } + Tcl_AppendResult(interp, d, NULL); + return TCL_OK; +} + +int tclFhttp_query_value(ClientData ignored, Tcl_Interp * interp, int argc, + char **argv) +{ + httpTtrans *t; + char *query, *value; + lstTset *set; + + if (argc != 2) { + Tcl_AppendResult(interp, "bad argumentation: should be \"", + argv[0], "name\"", NULL); + return TCL_ERROR; + } + + t = httpFthread_gettrans(); + if (t == NULL) { + Tcl_AppendResult(interp, "Could not find transaction.", NULL); + return TCL_ERROR; + } + + set = httpFget_query (t); + if (set == NULL) { + Tcl_SetResult(interp, "", TCL_STATIC); + return TCL_OK; + } + + value = lstFset_get(set, argv[1]); + if (value == NULL) { + Tcl_SetResult(interp, "", TCL_STATIC); + return TCL_OK; + } + + Tcl_AppendResult(interp, value, NULL); + + return TCL_OK; +} + + +int tclFhttp_query_parse(ClientData ignored, Tcl_Interp * interp, int argc, + char **argv) +{ + httpTtrans *t; + char *tlsid, *query; + lstTset *set; + + if (argc != 1) { + Tcl_AppendResult(interp, "bad argumentation: should be \"", + argv[0], "\"", NULL); + return TCL_ERROR; + } + t = httpFthread_gettrans(); + if (t == NULL) { + Tcl_AppendResult(interp, "Could not find transaction.", NULL); + return TCL_ERROR; + } + query = lstFset_get(t->vars, "query"); + if (query == NULL) { + Tcl_SetResult(interp, "", TCL_STATIC); + return TCL_OK; + } + set = qryFlst_parse(query); + if (set == NULL) { + Tcl_SetResult(interp, "", TCL_STATIC); + return TCL_OK; + } + tlsid = tlsFadd_makeid(set, 0); + Tcl_AppendResult(interp, tlsid, NULL); + + return TCL_OK; +} + +int tclFdb_close(ClientData ignored, Tcl_Interp * interp, int argc, + char **argv) +{ + void *db; + + if (argc != 2) { + Tcl_AppendResult(interp, "bad argumentation: should be \"", + argv[0], " db\""); + return TCL_ERROR; + } + /* Doing this will cause the close if it's a valid handle */ + tlsFdel(argv[1], tclGtls_db); + + return TCL_OK; +} + +int tclFdb_open(ClientData ignored, Tcl_Interp * interp, int argc, + char **argv) +{ + httpTtrans *t; + void *db; + char *tlsid, *query; + + assert(interp != NULL); + + if (argc != 4) { + Tcl_AppendResult(interp, "bad argumentation: should be \"", + argv[0], " user password service\"", NULL); + return TCL_ERROR; + } + t = httpFthread_gettrans(); + if (t == NULL) { + Tcl_AppendResult(interp, "Could not find transaction.", NULL); + return TCL_ERROR; + } + db = dbFopen(argv[1], argv[2], argv[3]); + if (db == NULL) { + Tcl_AppendResult(interp, "Database open failed.", NULL); + return TCL_ERROR; + } + tlsid = tlsFadd_makeid(db, tclGtls_db); + Tcl_AppendResult(interp, tlsid, NULL); + + return TCL_OK; +} + +int tclFdb_select(ClientData ignored, Tcl_Interp * interp, int argc, + char **argv) +{ + httpTtrans *t; + char *tlsid, *query; + void *db; + lstTset *set; + + if (argc != 3) { + Tcl_AppendResult(interp, "bad argumentation: should be \"", + argv[0], " conn sql\"", NULL); + return TCL_ERROR; + } + t = httpFthread_gettrans(); + if (t == NULL) { + Tcl_AppendResult(interp, "Could not find transaction.", NULL); + return TCL_ERROR; + } + db = tlsFget(argv[1], tclGtls_db); + if (db == NULL) { + Tcl_AppendResult(interp, "Invalid database handle.", NULL); + return TCL_ERROR; + } + set = dbFselect(db, argv[2]); + if (set == NULL) { + Tcl_AppendResult(interp, "dbFselect failed.", NULL); + return TCL_ERROR; + } + tlsid = tlsFadd_makeid(set, 0); + Tcl_AppendResult(interp, tlsid, NULL); + + return TCL_OK; +} + +int tclFdb_getrow(ClientData ignored, Tcl_Interp * interp, int argc, + char **argv) +{ + httpTtrans *t; + int res; + void *db; + lstTset *set; + + if (argc != 3) { + Tcl_AppendResult(interp, "bad argumentation: should be \"", + argv[0], " conn resultset\"", NULL); + return TCL_ERROR; + } + t = httpFthread_gettrans(); + if (t == NULL) { + Tcl_AppendResult(interp, "Could not find transaction.", NULL); + return TCL_ERROR; + } + db = tlsFget(argv[1], tclGtls_db); + if (db == NULL) { + Tcl_AppendResult(interp, "Invalid database handle.", NULL); + return TCL_ERROR; + } + set = tlsFget(argv[2], 0); + if (set == NULL) { + Tcl_AppendResult(interp, "Invalid resource set handle.", NULL); + return TCL_ERROR; + } + res = dbFgetrow(db, set); + + if (res == -1) { + Tcl_AppendResult(interp, "dbFgetrow failed.", NULL); + return TCL_ERROR; + } + if (res == 2) + Tcl_SetResult(interp, "0", TCL_STATIC); + else + Tcl_SetResult(interp, "1", TCL_STATIC); + + return TCL_OK; +} + +/* + * Return the height and width of a given jpeg file. This requires mod/image + * to work. Returns the string "width height" or "" on error. + */ +int tclFjpg_getsize(ClientData ignored, Tcl_Interp * interp, int argc, + char **argv) +{ + int h, w; + char buf[32]; + + if (argc != 2) { + Tcl_AppendResult(interp, "bad argumentation: should be \"", + argv[0], " filename\"", NULL); + return TCL_ERROR; + } + if (imgFjpeg_size(argv[1], &w, &h) == -1) { + Tcl_AppendResult(interp, "Invalid file.", NULL); + return TCL_ERROR; + } + snprintf(buf, 32, "%d %d", w, h); + + Tcl_AppendResult(interp, buf, NULL); + + return TCL_OK; +} + +/* + * tav_set array key value + */ +int tclFtav_set(ClientData ignored, Tcl_Interp * interp, int argc, + char **argv) +{ + lstTset *set; + + if (argc != 4) { + Tcl_AppendResult(interp, + "bad argumentation: should be tav_set array key value", + NULL); + return TCL_ERROR; + } + + pthread_rwlock_wrlock(&tclLtav_hash); + + set = (lstTset *) hshFvoid_find(tclGtav_hash, argv[1]); + + if (set == NULL) { + set = lstFset_create(argv[1]); + hshFvoid_add(tclGtav_hash, argv[1], set); + } + + lstFset_update(set, argv[2], argv[3]); + + pthread_rwlock_unlock(&tclLtav_hash); + + return TCL_OK; +} + +/* + * tav_get array key + */ +int tclFtav_get(ClientData ignored, Tcl_Interp * interp, int argc, + char **argv) +{ + lstTset *set; + + if (argc != 3) { + Tcl_AppendResult(interp, + "bad argumentation: should be tav_get array key", + NULL); + return TCL_ERROR; + } + + pthread_rwlock_wrlock(&tclLtav_hash); + + set = (lstTset *) hshFvoid_find(tclGtav_hash, argv[1]); + + if (set != NULL) + Tcl_AppendResult(interp, lstFset_get(set, argv[2]), NULL); + + pthread_rwlock_unlock(&tclLtav_hash); + + return TCL_OK; +} + +/* + * tav_exists array key + */ +int tclFtav_exists(ClientData ignored, Tcl_Interp * interp, int argc, + char **argv) +{ + lstTset *set; + char *value; + + if (argc != 3) { + Tcl_AppendResult(interp, + "bad argumentation: should be tav_exists array key", + NULL); + return TCL_ERROR; + } + + pthread_rwlock_wrlock(&tclLtav_hash); + + set = (lstTset *) hshFvoid_find(tclGtav_hash, argv[1]); + + if (set != NULL) { + if (lstFset_get(set, argv[2]) != NULL) { + Tcl_AppendResult(interp, "1", NULL); + } else { + Tcl_AppendResult(interp, "0", NULL); + } + } else { + Tcl_AppendResult(interp, "0", NULL); + } + + pthread_rwlock_unlock(&tclLtav_hash); + + return TCL_OK; +} diff --git a/mk4/modtcl/src/modtcl.c b/mk4/modtcl/src/modtcl.c new file mode 100644 index 0000000..a96f5b3 --- /dev/null +++ b/mk4/modtcl/src/modtcl.c @@ -0,0 +1,432 @@ +#pragma ident "$Header: /san01/cvs/ashpool/csrc/modtcl/src/Attic/modtcl.c,v 1.7 2004/04/21 21:47:06 aleigh Exp $" + +/* + * Copyright (c) 1994, 2002 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright + * notice above does not evidence any actual or intended publication of such + * source code. + * + * Disclosure, copying, distribution, or transmission of this code without + * express permission is prohibited. + */ + +/* + The biggest problem with the TCL system is the fact that TCL doesn't really + support a mechanism to *copy* an interpreter. This is too bad, too. Ideally + what really ought to happen is that we create an interpreter, run it through + all of it's init tcl scripts to load people's various library functions, and + then just clone it for each of the threads that happens to need one. That would + save having to constantly run through the script initialization for each time the + interpreter is created. +*/ + +#include +#include +#include +#include "../tcl8.3.4/generic/tclInt.h" +#include "modtcl.h" + +#define CLEANUP_PROC "_cont_cleanup" +#define GETINIT_PROC "_cont_getinit" + +static void tclFinterp_create(tclTthr_data * data); +static void tclFinterp_delete(tclTthr_data * data); + +/* + * The init interpreter which is used to create the init script. + */ +Tcl_Interp *tclGinterp = NULL; + +/* + * Init script contianing all the procs. This was generated after the + * libraries were loaded and it used by tclFinterp_create. + */ +char *tclGinit_script = NULL; + +/* pthread key used to hold tclTthr_data in TLS */ +pthread_key_t tclKdata; + +/* She shines, in a world full of ugliness */ + +static char tclGhard_procs[] = + "proc " CLEANUP_PROC " {{autoclose 0}} {\n" + " foreach g [info globals] {\n" + " if {![string match tcl* $g]\n" + " && ![string match error* $g]\n" + " && [string compare env $g] != 0} {\n" + " upvar #0 $g gv\n" + " if [info exists gv] {\n" + " unset gv\n" + " }\n" + " }\n" + " }\n" + "}\n" + "proc " GETINIT_PROC " {} {\n" + " set script {}\n" + " foreach p [info procs] {\n" + " set args {}\n" + " foreach a [info args $p] {\n" + " if [info default $p $a def] {\n" + " set a [list $a $def]\n" + " }\n" + " lappend args $a\n" + " }\n" + " append script [list proc $p $args [info body $p]]\n" + " append script \\n\n" " }\n" " return $script\n" "}\n"; + + +/* + * Output a TCL script error message to the log. + */ +void tclFerror(Tcl_Interp * interp) +{ + char *err; + + assert(interp != NULL); + + logFmsg(1, "TCL error: %s", interp->result); + + err = Tcl_GetVar(tclGinterp, "errorInfo", TCL_GLOBAL_ONLY); + if (err != NULL) + logFmsg(1, "%s", err); +} + +/* + * CAPI function to be called from module.cfg to initialize the TCL module. + * This function should initialize the master interpreters and run any + * required startup scripts. + */ +int tclFinit(void *p, lstTset * opts) +{ + char *initfile; + + logFmsg(0, "mod/tcl: TCL Script Engine (module)"); + logFmsg(0, + "Copyright (c) 2002, Alex Leigh. All Rights Reserved"); + logFmsg(0, + "TCL 8.3.4 Copyright (c) Regents of UC, Sun Microsystems, Scriptics"); + + tclFcmd_init(); + + /* She reads the minds of all the people that pass her by */ + + if (pthread_key_create(&tclKdata, &tclFdata_free) != 0) { + logFmsg(2, "Unable to create tclKdata."); + abort(); + } + + tclGinterp = Tcl_CreateInterp(); + + assert(tclGinterp != NULL); + + if (Tcl_Eval(tclGinterp, tclGhard_procs) != TCL_OK) { + tclFerror(tclGinterp); + logFmsg(2, "Tcl_Eval for hard procs failed."); + abort(); + } + + /* Bind all the continuity commands */ + tclFsetup_cmds(tclGinterp); + + /* Load .tcl library files here to setup the global init state. */ + initfile = lstFset_get(opts, "init"); + if (initfile != NULL) { + if (Tcl_EvalFile(tclGinterp, initfile) != TCL_OK) { + tclFerror(tclGinterp); + } else { + logFmsg(0, "Loaded %s", initfile); + } + } + + /* + * Create one proc that will be used to initialize future procs to this + * state. This is because there is no a mechanism in libtcl to actually + * copy an interpreter. + */ + + if (Tcl_Eval(tclGinterp, GETINIT_PROC) != TCL_OK) { + tclFerror(tclGinterp); + logFmsg(2, "Unable to create init interp. Aborting."); + abort(); + } + + tclGinit_script = (char *) malloc(strlen(tclGinterp->result) + 1); + assert(tclGinit_script != NULL); + + strcpy(tclGinit_script, tclGinterp->result); + + return STATUS_PROCEED; +} + +int tclFinterp_cleanup(tclTthr_data * data) +{ + Tcl_Interp *interp = data->interp; + Tcl_DString script; + + Tcl_ResetResult(interp); + + Tcl_DStringInit(&script); + Tcl_DStringAppendElement(&script, CLEANUP_PROC); + if (Tcl_Eval(interp, script.string) != TCL_OK) { + tclFerror(interp); + } + Tcl_DStringFree(&script); + + if (data->delete == 0) { + Tcl_ResetResult(interp); + } else { + /* Delete Function */ + } + return 0; +} + +/* + * Destructor for TLS memory to destroy the data structure. + */ +void tclFdata_free(void *p) +{ + tclTthr_data *data = (tclTthr_data *) p; + + assert(p != NULL); + + if (data->interp != NULL) + Tcl_DeleteInterp(data->interp); + free(data); +} + +tclTthr_data *tclFdata_get(void) +{ + tclTthr_data *data; + + data = pthread_getspecific(tclKdata); + if (data == NULL) { + data = malloc(sizeof(tclTthr_data)); + bzero(data, sizeof(tclTthr_data)); + pthread_setspecific(tclKdata, data); + } + return data; +} + +/* + * Allocate an interpreter, or, if one is already associated with this + * thread, return that one. + * + * Results: TCL Interpreter + * + * Side Effects; May create a new TCL interpreter. + */ +Tcl_Interp *tclFinterp_get(char *server) +{ + tclTthr_data *data; + + data = tclFdata_get(); + + assert(data != NULL); + +#ifdef TCL_DEBUG + if (data->interp == NULL) { + logFmsg(3, "No TCL interpreter previously allocated."); + } else { + logFmsg(3, "TCL Interpreter previously allocated."); + } +#endif + + /* Update times in thread data */ + + if (data->interp == NULL) { + tclFinterp_create(data); + } + return data->interp; +} + +/* + * Create a TCL Interpreter and initialize it + */ +static void tclFinterp_create(tclTthr_data * data) +{ + Tcl_Interp *interp; + + data->interp = interp = Tcl_CreateInterp(); + + tclFsetup_cmds(interp); + + /* Evaluate the script to create all procs. */ + Tcl_Eval(interp, tclGinit_script); +} + + + /* In the machina, you can hear her scream. */ + +/* + * tclFeval - Evaluate a TCL script in the current thread for the given + * server. + */ +int tclFeval(char *server, char *script) +{ + Tcl_Interp *interp; + + interp = tclFinterp_get(server); + + assert(interp != NULL); + +#ifdef TCL_DEBUG + logFmsg(3, "tclFeval: tclFinterp_get returned interp 0x%x", interp); +#endif + + if (Tcl_Eval(interp, script) != TCL_OK) { + logFmsg(3, "tclFeval: result is %s", interp->result); + } +} + +static void tclFinterp_delete(tclTthr_data * data) +{ + Tcl_DeleteInterp(data->interp); + data->interp = NULL; + data->delete = 0; +} + +/* + * Process a TCL script that is the entire file, IE, not an embedded TCL + * script. + */ +int tclFhandler(httpTtrans * t, lstTset * opts) +{ + Tcl_Interp *interp; + char *ppath = lstFset_get(t->vars, "path"); + + interp = tclFinterp_get("tessier"); + assert(interp != NULL); + + lstFset_update(t->res_hdrs, "Content-Type", "text/html"); + + if (Tcl_EvalFile(interp, ppath) != TCL_OK) { + tclFerror(interp); + httpFwrite(t, interp->result, strlen(interp->result)); + } + return STATUS_EXIT; +} + +static void tclFtext_chunk(dynTstring * dsPtr, char *text) +{ + dynFappend(dsPtr, "t", 1); + dynFappend(dsPtr, text, strlen(text) + 1); +} + +static void tclFpage_parse(dynTstring * dsPtr, char *page) +{ + register char *s, *e, *t = page; + + assert(page != NULL); + assert(dsPtr != NULL); + + while ((s = strstr(t, "<%")) != NULL && (e = strstr(s, "%>")) != NULL) { + + *s = '\0'; + tclFtext_chunk(dsPtr, t); + *s = '<'; + s += 2; + dynFappend(dsPtr, "s", 1); + if (*s == '=') { + ++s; + } + *e = '\0'; + dynFappend(dsPtr, s, e - s + 1); + *e = '%'; + t = e + 2; + } + tclFtext_chunk(dsPtr, t); +} + +/* + * Dyn should be a dynamic string that contains a chunked + * page, in this format; + * tSometexthere\0sAscript\0tMoretext\0\0 + */ +static void tclFpage_render(dynTstring * dyn, httpTtrans * t) +{ + char *p; + Tcl_Interp *interp; + + assert(dyn != NULL); + assert(t != NULL); + + interp = tclFinterp_get("tessier"); + + assert(interp != NULL); + + p = dynFgetstr(dyn); + + assert(p != NULL); + + while (1) { + if (*p == 't') { + p++; + httpFwrite(t, p, strlen(p)); + } else { + p++; + if (Tcl_Eval(interp, p) != TCL_OK) { + char *err; + logFmsg(2, "script failed: [%d] %s", + interp->errorLine, interp->result); + err = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY); + if (err != NULL) + logFmsg(2, "%s", err); + } + } + + p += strlen(p) + 1; + + if ((p - dynFgetstr(dyn)) >= dynFgetlen(dyn)) + break; + } +} + +/* + * Process an HTML file that may contain embedded TCL. + */ +int tclFembed_handler(httpTtrans * t, lstTset * opts) +{ + char *ppath; + char *map, *page; + dynTstring *script; + lstTset *query; + + assert(t != NULL); + + ppath = lstFset_get(t->vars, "path"); + + assert(ppath != NULL); + + script = dynFinit(); + + assert(script != NULL); + + map = (char *) mmcFmap(ppath, &t->statb, NULL); + if (map == NULL) { + logFmsg(1, "mmcFmap returned NULL for %s", + ppath); + dynFfree(script); + return STATUS_ERROR; + } + + if (map == (char *) 0x1) { + logFmsg(1, "map returned 0x1 for %s", ppath); + dynFfree(script); + return STATUS_ERROR; + } + + page = strFcopy(map); + + lstFset_update(t->res_hdrs, "Content-Type", "text/html"); + httpFset_status(t, 200, NULL); + httpFstart_response(t); + + tclFpage_parse(script, page); + tclFpage_render(script, t); + + dynFfree(script); + free(page); + + return STATUS_EXIT; +} diff --git a/mk4/modtcl/src/modtcl.h b/mk4/modtcl/src/modtcl.h new file mode 100644 index 0000000..01637fe --- /dev/null +++ b/mk4/modtcl/src/modtcl.h @@ -0,0 +1,73 @@ +/* Copyright (c) 1994, 2002 Alex Leigh, All Rights Reserved + * + * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH + * The copyright notice above does not evidence any + * actual or intended publication of such source code. + * + * Disclosure, copying, distribution, or transmission of + * this code without express permission is prohibited. + */ + +#ifndef MODTCL_H +#define MODTCL_H + +#ifndef __GNUC__ +#pragma ident "$Header: /san01/cvs/ashpool/csrc/modtcl/src/Attic/modtcl.h,v 1.3 2004/03/11 00:52:02 eric Exp $" +#endif + +#include +#include +#include + +struct tclSthr_data { + Tcl_Interp *interp; + int delete; +}; +typedef struct tclSthr_data tclTthr_data; + +struct tclScmd { + char *name; + Tcl_CmdProc *proc; + ClientData clientData; +}; +typedef struct tclScmd tclTcmd; + +void tclFdata_free(void *p); +int tclFinit(void *p, lstTset * opts); +tclTthr_data *tclFdata_get(void); +Tcl_Interp *tclFinterp_get(char *server); +int tclFeval(char *server, char *script); +int tclFinterp_cleanup(tclTthr_data *data); +void tclFerror(Tcl_Interp *interp); + +/* cmds.c */ +void tclFsetup_cmds(Tcl_Interp *interp); +void tclFcmds_register(Tcl_Interp *interp, tclTcmd *cmd); +int tclFta_log(ClientData ignored, Tcl_Interp *interp, int argc, char **argv); +int tclFta_write(ClientData ignored, Tcl_Interp *interp, int argc, char **argv); +int tclFta_startresponse(ClientData ignored, Tcl_Interp *interp, int argc, char **argv); +int tclFta_setstatus(ClientData ignored, Tcl_Interp *interp, int argc, char **argv); +void tclFbind_dyn_command(char *name, Tcl_CmdProc *proc); +int tclFta_http_vars_get(ClientData ignored, Tcl_Interp *interp, int argc, char **argv); +int tclFta_http_res_get(ClientData ignored, Tcl_Interp *interp, int argc, char **argv); +int tclFta_http_req_get(ClientData ignored, Tcl_Interp *interp, int argc, char **argv); +int tclFta_pwd(ClientData ignored, Tcl_Interp *interp, int argc, char **argv); +int tclFta_http_req_set(ClientData ignored, Tcl_Interp *interp, int argc, char **argv); +int tclFta_http_res_set(ClientData ignored, Tcl_Interp *interp, int argc, char **argv); +int tclFta_http_var_set(ClientData ignored, Tcl_Interp *interp, int argc, char **argv); +int tclFhttp_query_value(ClientData ignored, Tcl_Interp *interp, int argc, char **argv); +int tclFlist_get(ClientData ignored, Tcl_Interp *interp, int argc, char **argv); +int tclFhttp_query_parse(ClientData ignored, Tcl_Interp *interp, int argc, char **argv); +int tclFdb_open(ClientData ignored, Tcl_Interp *interp, int argc, char **argv); +int tclFdb_select(ClientData ignored, Tcl_Interp *interp, int argc, char **argv); +int tclFdb_getrow(ClientData ignored, Tcl_Interp *interp, int argc, char **argv); +int tclFjpg_getsize(ClientData ignored, Tcl_Interp *interp, int argc, char **argv); +int tclFurl_encode(ClientData ignored, Tcl_Interp *interp, int argc, char **argv); +int tclFurl_decode(ClientData ignored, Tcl_Interp *interp, int argc, char **argv); +int tclFdb_close(ClientData ignored, Tcl_Interp *interp, int argc, char **argv); +int tclFtav_set(ClientData ignored, Tcl_Interp * interp, int argc, char **argv); +int tclFtav_get(ClientData ignored, Tcl_Interp * interp, int argc, char **argv); +int tclFtav_exists(ClientData ignored, Tcl_Interp * interp, int argc, char **argv); +int tclFhttp_query_get(ClientData ignored, Tcl_Interp * interp, int argc, char **argv); +#endif + diff --git a/modtcl/modtcl.xml b/mk4/modtcl/src/modtcl.xml similarity index 100% rename from modtcl/modtcl.xml rename to mk4/modtcl/src/modtcl.xml diff --git a/mk4/modtcl/tcl8.3.4/CVS/Entries b/mk4/modtcl/tcl8.3.4/CVS/Entries new file mode 100644 index 0000000..84f1347 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/CVS/Entries @@ -0,0 +1,13 @@ +/ChangeLog/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/README/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/changes/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/license.terms/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +D/compat//// +D/doc//// +D/generic//// +D/library//// +D/mac//// +D/tests//// +D/tools//// +D/unix//// +D/win//// diff --git a/mk4/modtcl/tcl8.3.4/CVS/Repository b/mk4/modtcl/tcl8.3.4/CVS/Repository new file mode 100644 index 0000000..2f60d22 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/modtcl/tcl8.3.4 diff --git a/mk4/modtcl/tcl8.3.4/CVS/Root b/mk4/modtcl/tcl8.3.4/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/modtcl/tcl8.3.4/CVS/Tag b/mk4/modtcl/tcl8.3.4/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/modtcl/tcl8.3.4/ChangeLog b/mk4/modtcl/tcl8.3.4/ChangeLog new file mode 100644 index 0000000..4a2d4ba --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/ChangeLog @@ -0,0 +1,5515 @@ +2001-10-19 Jeff Hobbs + + ************************ + **** 8.3.4 TAGGED **** + ************************ + + * generic/tclInt.h: + * generic/tclObj.c: added -DPURIFY object allocation option. + + * unix/configure: + * unix/tcl.m4: added -lc to LIBS on AIX + +2001-10-19 Daniel Steffen + + * mac/tclMacFile.c: fix to glob -join, wasn't traversing aliased + folders + + * mac/tclMacLoad.c: : corrected utf8 handling, comparison of + package names to code fragment names changed to only match on the + length of package name, this allows for fragment names with version + numbers appended (backport from 8.4) + +2001-10-18 Jeff Hobbs + + * unix/configure: regend + * unix/tcl.m4 (SC_ENABLE_GCC): enabled better recognition of gcc. + + * tests/clock.test (clock-8.1): + * generic/tclDate.c (RelativeMonth): + * generic/tclGetDate.y (RelativeMonth): corrected off-by-one-day + error in clock scan with relative months and years during swing + hours. [Bug #413397, Patch #414024] (lavana) + +2001-10-17 Jeff Hobbs + + * unix/tclUnixPipe.c (PipeInputProc, PipeOutputProc): do immediate + retry when error is returned with errno == EINTR. + [Bug #415131] (leger) + +2001-10-17 Daniel Steffen + + * mac/tclMacProjects.sea.hqx: updated projects with new version + numbers and resource reorganization; included XML versions of + the projects for CW Pro5 or Pro7 users. + + * mac/tcltkMacBuildSupport.sea.hqx: updated build instructions + and readme's; MoreFiles 1.5.2 added; XML versions of projects. + +2001-10-17 Daniel Steffen + + Backport of mac specific changes added to 8.4 since 8.3.3: + + * generic/tcl.h: removed line continuation in #if clause as this + breaks the mac resource compiler (note that *.r files include tcl.h) + + * compat/strftime.c: + * mac/tclMacTime.c: + * mac/tclMacPort.h: + * generic/tclInt.decls: + * generic/tclIntPlatDecls.h: + * generic/tclStubInit.c: timezone support for mac via + TclpGetTZName() like on windows, using an inverse timezone table + adapted from tclDate.c to map gmtoffset in seconds gotten from + the MacOS APIs to a timezone string, as there is no good way to get + this info from MacOS. I had to make up some unusual timezones and + arbitrarily decide on the most standard of the multiple choices + + * generic/tclCmdAH.c: + * generic/tclDate.c: + * generic/tclGetDate.y: + * mac/tclMacInt.h: + * mac/tclMacFile.c: default mac epoch changed to standard unix + epoch and related mac time/date handling changes from TIP17. + + * mac/tclMacFile.c: glob -dir compatibility for unix style + relative paths, from TIP17 + + * mac/tclMacAppInit.c: support for WASTE text library using + temporary memory, setting has no effect if WASTE is not used. + + * tests/cmdAH.test: access time not available on the mac, skip the + atime touch test + + * mac/tclMacApplication.r: + * mac/tclMacLibrary.r: + * mac/tclMacOSA.r: + * mac/tclMacResource.r: updated copyrights/dates in version + strings; reorganized resources among these files to avoid + multiple copies in applications and shared libraries, the script + libraries are now no longer duplicated in Tclsh but are only + included in the resources of Tcl.shlb. + + * tests/cmdMZ.test: + * tests/exec.test: + * tests/fileName.test: added missing cleanups/tests/catches that + caused tests to fail on the mac. + + * doc/tclvars.n: documentation error, env(PWD) should be env(HOME) + +2001-10-17 Jeff Hobbs + + * unix/tclUnixFCmd.c: minor casts to prevent warnings + + * unix/configure: regened + * unix/configure.in: added preset CFLAGS check from HEAD to + prevent --enable-gcc from adding "-g -O2" + +2001-10-17 Don Porter + + * changes: First draft of Tcl changes for 8.3.4 release. + +2001-10-16 Don Porter + + * unix/Makefile.in: Restored install of tclConfig.sh file + to $TCL_EXEC_PREFIX/lib. It contains platform-dependent + definitions, and must not be installed under $TCL_PREFIX. + +2001-10-16 Jeff Hobbs + + * unix/tclLoadAout.c (TclGuessPackageName): removed unused vars + and fixed warnings. [Bug #446622] (lim) + +2001-10-16 Daniel Steffen + + * unix/Makefile.in: + * unix/configure.in: + * unix/tcl.m4: Added support for MacOSX / Darwin + * unix/configure: Autoconf + + * unix/mkLinks: + * unix/mkLinks.tcl: Added check for case-insensitive + filesystems and conditionalized links that only differ by + case (needed for MacOSX/Darwin on HFS+ FS) + + * unix/tclLoadDyld.c: change in binary extension format from + MachO bundles to standard .dylib dynamic libraries like on + other unices. **POTENTIAL INCOMPATIBILITY*** extensions + will have to be recompiled as .dylib's. + Improved error handling and use of DStrings and + Tcl_UtfToExternalDString instead of sprintf to build up + symbol and library names. [Patch 435258] + +2001-10-16 Don Porter + + * tests/trace.test (trace-18.1): Added test to demonstrate + memory corruption problems. [Bug 219393]. + + * unix/mkLinks: 'make mklinks' for Tcl_SetMainLoop. + + * unix/Makefile.in (dist: target): Removed copy of files + matching mac/*.exp; no such files. + +2001-10-15 Andreas Kupries + + * generic/tclInt.decls (TclExpandCodeArray,TclGetInstructionTable): + Added to internal stubs table. Tclcompiler (Tclpro project) + needs them if used as loadable package under Windows. Changed + signatures. We don't want to describe compiler internal + structures in "tclInt.h". + + * generic/tclCompile.h: S.a. Removed function declarations. + * generic/tclCompile.c: S.a. Adapted to changed signatures. + +2001-10-15 Jeff Hobbs + + * unix/configure: + * unix/configure.in: + * win/configure: + * win/configure.in: + * win/tcl.m4: reworked to be a little cleaner in comparison to + each other, and to AC_SUBST even empty vars for win/tclConfig.sh + + * generic/tcl.h: + * win/tclWinPort.h: moved #define of WIN32 to tcl.h where __WIN32__ + is defined and added #ifndef check. + +2001-10-12 Jeff Hobbs + + * tests/winPipe.test: removed obsolete cat16 tests, fixed + winpipe-1.22 to only run on Win9*. + + * tests/timer.test: slight skewing of after values to allow for + correct results on burdened machines. + + * tests/winFCmd.test: differentiated test results for win2k + versus not. + + * win/tclWinInit.c: cleanup back-ported from 8.4 HEAD. + + * win/tclWinPort.h: move winsock2.h include, header cleanup + back-ported from 8.4 HEAD. + + * library/encoding/ebcdic.enc: + * tools/encoding/ebcdic.txt: EBCDIC charset mapping. + [Patch #219323] (nijtmans) + + * library/encoding/tis-620.enc: + * tools/encoding/tis-620.txt: TIS-620 charset mapping. + [Patch #467423] (poonlap) + +2001-10-11 Miguel Sofer + + * generic/tclLiteral.c: (TclReleaseLiteral) insured that + self-referential bytecodes are properly cleaned up on interpreter + deletion [Bug 467523] (Ronnie Brunner) + +2001-10-10 Don Porter + + * tests/unixInit.test: Corrected restore of ::env(LANG). + +2001-10-10 Donal K. Fellows + + * generic/tclCmdMZ.c: Removed pointless #include and SCAN_* flags. + (Tcl_RegexpObjCmd): Fixed match area offset bug. + (Tcl_StringObjCmd): Fixed STR_INDEX and STR_REPEAT, and tidied up + STR_IS and STR_LENGTH. + +2001-10-09 Miguel Sofer + + * generic/tclObj.c: removed duplicate definition of tclObjsAlloced + and tclObjsFreed. These variables only exist when compiling with + TCL_COMPILE_STATS, and are already defined in generic/tclExecute.c + +2001-10-09 Jeff Hobbs + + * generic/tclFileName.c (ExtractWinRoot): corrected ABR error + + * doc/bgerror.n: back-port from 8.4 that indicates new behavior of + bgerror in Tk. + +2001-10-09 Miguel Sofer + + * generic/tclLiteral.c: (TclReleaseLiteral) reverted previous + patch for [Bug 467523] - cure is worse than the illness. + +2001-10-09 Donal K. Fellows + + * tests/io.test (io-32.8): Fixed typo. + +2001-10-08 Donal K. Fellows + + * tests/cmdIL.test: test improvement. + * doc/lsort.n: Doc improvement. + * generic/tclCmdIL.c (InfoBodyCmd): Strengthened bytecode + isolation [fix orig. by Miguel Sofer] + (Tcl_LsortObjCmd, SortCompare): Symbolic indexing values plus + correct handling of indexing relative to end in [lsort]. + +2001-10-05 Miguel Sofer + + * generic/tclLiteral.c: (TclReleaseLiteral) insured that + self-referential bytecodes are properly cleaned up on interpreter + deletion [Bug 467523] (Ronnie Brunner) + +2001-10-04 Jeff Hobbs + + * library/encoding/cp1250.enc: + * library/encoding/cp1251.enc: + * library/encoding/cp1252.enc: + * library/encoding/cp1253.enc: + * library/encoding/cp1254.enc: + * library/encoding/cp1255.enc: + * library/encoding/cp1256.enc: + * library/encoding/cp1257.enc: + * library/encoding/cp1258.enc: + * library/encoding/cp874.enc: + * library/encoding/cp936.enc: + * library/encoding/cp949.enc: + * library/encoding/cp950.enc: + * library/encoding/iso8859-10.enc: + * library/encoding/iso8859-13.enc: + * library/encoding/iso8859-14.enc: + * library/encoding/iso8859-15.enc: + * library/encoding/iso8859-16.enc: + * library/encoding/iso8859-6.enc: + * library/encoding/iso8859-7.enc: + * library/encoding/iso8859-8.enc: + * library/encoding/koi8-u.enc: + * library/encoding/macCroatian.enc: + * library/encoding/macCyrillic.enc: + * library/encoding/macGreek.enc: + * library/encoding/macIceland.enc: + * library/encoding/macRoman.enc: + * library/encoding/macTurkish.enc: + * tools/encoding/cp1250.txt: + * tools/encoding/cp1251.txt: + * tools/encoding/cp1252.txt: + * tools/encoding/cp1253.txt: + * tools/encoding/cp1254.txt: + * tools/encoding/cp1255.txt: + * tools/encoding/cp1256.txt: + * tools/encoding/cp1257.txt: + * tools/encoding/cp1258.txt: + * tools/encoding/cp874.txt: + * tools/encoding/cp932.txt: + * tools/encoding/cp936.txt: + * tools/encoding/cp949.txt: + * tools/encoding/cp950.txt: + * tools/encoding/iso8859-1.txt: + * tools/encoding/iso8859-10.txt: + * tools/encoding/iso8859-13.txt: + * tools/encoding/iso8859-14.txt: + * tools/encoding/iso8859-15.txt: + * tools/encoding/iso8859-16.txt: + * tools/encoding/iso8859-2.txt: + * tools/encoding/iso8859-3.txt: + * tools/encoding/iso8859-4.txt: + * tools/encoding/iso8859-5.txt: + * tools/encoding/iso8859-6.txt: + * tools/encoding/iso8859-7.txt: + * tools/encoding/iso8859-8.txt: + * tools/encoding/iso8859-9.txt: + * tools/encoding/koi8-r.txt: + * tools/encoding/macCentEuro.txt: + * tools/encoding/macCroatian.txt: + * tools/encoding/macCyrillic.txt: + * tools/encoding/macGreek.txt: + * tools/encoding/macIceland.txt: + * tools/encoding/macRoman.txt: + * tools/encoding/macTurkish.txt: + Updated encodings with latest mappings from www.unicode.org. This + did not include some Mac encodings that have special multi-unichar + translations now (like symbols, dingbats and japanese). Also does + not include big5, gb or euc* as those have different formats in + the latest Unicode version that need new conversion tools. Not + all related .enc files changed as some had been updated separately. + +2001-10-03 Jeff Hobbs + + * README: + * generic/tcl.h: + * mac/README: + * tools/tcl.hpj.in: + * tools/tcl.wse.in: + * unix/Makefile.in: + * unix/README: + * unix/configure: + * unix/configure.in: + * unix/tcl.m4: + * unix/tcl.spec: + * win/README: + * win/REAME.binary: updated patchlevel to 8.3.4. Changed urls to + point to www.tcl-tk.net where applicable. + + * win/configure: + * win/configure.in: + * win/tcl.m4: + * win/Makefile.in: added proper Win64 build support. + updated patchlevel to 8.3.4. + + * generic/tclEvent.c (Tcl_FinalizeThread): moved freeing of + tclLibraryPath to before the thread exit handlers are called. + Slight modification to change on 2001-09-24. + +2001-09-28 Miguel Sofer + + * doc/FindExec.3: added a comment not to change the working + directory before calling Tcl_GetNameOfExecutable [Bug 219215] + +2001-09-28 Andreas Kupries + + * generic/tclIO.c: added (on behalf of Kevin Kenny + ) two more '(ClientData)' casts + on calls to Tcl_Preserve and Tcl_Release -- ones that Vince + apparently missed. + +2001-09-27 Don Porter + + * generic/tclIO.c (ChannelTimerProc): Added Tcl_Preserve() + and Tcl_Release() to fix segfault introduced by the 2001-09-26 + changes. [Bug 465494] + + * doc/TCL_MEM_DEBUG.3: Updated out-of-date reference to + #define GUARD_SIZE. + +2001-09-26 Andreas Kupries + + * The changes below fix [Bug #462317] where Expect tried to read + more than was in the buffers and then blocked in the OS call as + its pty channel driver provides no blockmodeproc through which + the OS could be notified of blocking-behaviour. Because of this + the general I/O core has to take more care than usual to + preserve the semantics of non-blocking channels. + + * generic/tclIO.c (Tcl_ReadRaw): Do not read from the driver if + the channel is non-blocking and the fileevent causing the read + was generated by a timer. We do not know if there is data + available from the OS. Instead of going to the OS for more and + potentially blocking we simply signal EWOULDBLOCK to the higher + levels to cause the system to wait for true fileevents. + (GetInput): Same as before. + (ChannelTimerProc): Added set and clear of CHANNEL_TIMER_FEV. + + * generic/tclIO.h (CHANNEL_TIMER_FEV): New flag for channels. Is + set if a fileevent was generated by a timer, the channel is not + blocking and the driver did not provide a blockmodeproc. In that + case the I/O core has to be especially careful about going to + the driver for more data. + +2001-09-24 Andreas Kupries + + * The change below fixes [Bug #464380]. The bug was reported by + Ronnie Brunner . He also + provided the patch. + + * generic/tclEvent.c (Tcl_Finalize): Moved release of + 'tclLibraryPath' to Tcl_FinalizeThread. + (Tcl_FinalizeThread): See above, new place for release of + 'tclLibraryPath'. + +2001-09-20 Jeff Hobbs + + * win/makefile.vc: updated IA64 compile settings + + * win/tclWinInit.c: added extra processor definitions. (mstacy) + + * win/tclWinSock.c (SocketThread): corrected pointer cast for _WIN64. + + * win/tclWinNotify.c: removed unnecessary winsock include (it is + already in from tclWinPort.h). + + * win/tclWinPort.h: changed winsock.h include to winsock2.h. + Reverses change from 2000-11-16, but is necessary for WIN64. + Extensions should comply with defined OS words, or use #ifndef. + +2001-09-19 Jeff Hobbs + + * generic/tclTest.c (TestcmdtokenCmd): corrected pointer + storage/retrieval for 64bit machines. + + * generic/tclCmdAH.c (Tcl_FormatObjCmd): + * generic/tclScan.c (Tcl_ScanObjCmd): corrected handling of format + and scan on 64-bit machines. [Bug 219223, Patch #412696] (rmax) + + * unix/configure: regen'ed + * unix/tcl.m4: added --enable-64bit support for HP-11 with the + 64-bit kernel. + + * generic/tcl.h: removed forced #define USE_TCLALLOC 1 for + Windows. This means the native system allocator will be used by + default. This should be binary and source compatible with + extensions, as Tcl_Alloc is a properly stubbed function. + +2001-09-18 Don Porter + + * unix/configure: Regen. + * unix/tcl.m4 (SC_CONFIG_CFLAGS): On Linux, disable inlining when + one of the compat/*.c routines is to be linked in. [Patch 440891] + +2001-09-13 Jeff Hobbs + + * generic/tclUtf.c (Tcl_UtfPrev): corrected to return the proper + location when the middle of a UTF-8 byte was passed in. + [Tk Bug #450504] + +2001-09-13 Andreas Kupries + + * tests/ioCmd.test: Changed the computation of the result for + iocmd-8.1[123] so that the tests work for single- and + multi-process execution of the testsuite. Depending on the + choice of the user stdout is a tty or not and thus reports + different channel options. Fixes [460993] reported by Don + Porter. + +2001-09-12 Don Porter + + Backport several bug fixes from HEAD to core-8-3-1-branch: + + * tests/rename.test: + * tests/split.test: Corrected tests to better isolate tests in + one file from influencing tests in other files. [Bug 460591] + + * unix/tclLoadShl.c: Added #include of tclInt.h; access to Tcl + internals, notably TclpUnloadFile(), is required. Thanks to + Bob Techentin for report and patch. [Bug 459305] + + * generic/tclInitScript.h (initScript): + * win/tclWinInit.c (TCL_REGISTRY_KEY, TclpSetVariables): Removed + vestiges of Tcl's old initialization from registry variables. + [Bug 455645] + + * tests/unixInit.test (unixInit-3.2): Updated test to support + newer HP-UX releases that properly report euc-jp as the system + encoding for Japanese. Bug report and patch verification by Bob + Techentin. [Bug 453883] + + * compat/strtod.c (strtod): Fixed failure to handle expressions + like 3eq2 and failure to set errno on overflow. [Bug 440894] + +2001-09-10 Jeff Hobbs + + * generic/tclEvent.c (TclInExit): Corrected handling of tsd in + late stages of finalization. [Bug #419449] (darley) + + * tests/stack.test: + * generic/tclInterp.c (AliasObjCmd): Check the numLevels to ensure + that we aren't hitting some alias loop condition. [Bug #443184] + +2001-09-10 Andreas Kupries + + * generic/tclInt.decls: Added 'TclWinFlushDirtyChannels' to + the internal platform specific stub table. + +2001-09-06 Andreas Kupries + + * All the changes below serve to fix bug [219148] which reports a + 80x performance hit for file I/O on Win* systems. On my system + it was closer to a 120x hit. Problem report by Uwe Traum . + + The fix goes like this: The obstacle is 'FlushFileBuffers', + executed whenever Tcl writes data to the OS, as Tcl has to wait + for the disk to complete I/O, and disks are slow. We remove that + obstacle. This opens another problem, [file size] reports back + wrong numbers. So for [file size] we add the call back in. As + optimization we keep track of the channels which were written to + and flush only these. + + * win/tclWinFile.c (TclpObjStat): Added a call to + 'TclWinFlushDirtyChannels'. This ensures that [file size] and + related commands report the correct size of a file even if Tcl + has recently written to it. Unixoid OS's always report the + correct size even for files with pending data, but Win* + syssystem don't. They only report what is actually on disk. + + * win/tclWinInt.h: Added declaration of + 'TclWinFlushDirtyChannels', making it available to other parts + of the tcl core. + + * win/tclWinChan.c (TclWinFlushDirtyChannels): New, internal, + procedure. Goes through the list of open file channels and + forces the OS to flush its file buffers for all which were + written to since the last call of this function. This is an + expensive operation as Tcl has to wait for the OS to complete + actual writes to the disk. + + (FileInfo): Added dirty flag required by the procedure above. + + (FileOutputProc): Removed flushing of file buffers, setting the + dirty flag instead. This means that the previously incurred + delays do not happen anymore. + + (TclWinOpenFileChannel): Added initialization of 'dirty' flag. + +2001-09-06 Don Porter + + * doc/http.n: + * library/http/*.tcl: + * tools/tcl.wse.in: + * tools/tclmin.wse: + * unix/Makefile.in: + * win/{Mm}akefile.*: Updated http package to version 2.4, + reflecting the new features just added. + +2001-09-06 Jeff Hobbs + + * doc/http.n: noted -binary, charset and coding state keys. + * tests/http.test: + * library/http/pkgIndex.tcl: + * library/http/http.tcl (geturl): correctly get charset parameter + and convert text according to specified encoding (if known). + RFC iso8859-1 is used by default. Also recognize + Content-encoding to see if we should do binary translation. + Added a CYA -binary switch for the cases that were missed. [Bug + #219211 #219399] + + * tests/ioUtil.test: changed to make better use of constraints and + remove knownBug constraints that weren't valid. + +2001-09-01 David Gravereaux + + -=[ Tcl_Async* API merge from HEAD ]=- + + * generic/tclInt.decls: Removed TclpAsyncMark permanently and left + the hole not to upset the positions. + + * generic/tclDecls.h: + * generic/tclIntDecls.h: + * generic/tclIntPlatDecls.h: + * generic/tclPlatDecls.h: + * generic/tclStubInit.c: regen'd tables. + + * generic/tclAsync.c: Brought source to match -r1.6 on the HEAD + branch. + + * generic/tclEvent.c: + * generic/tclInt.h: Added prototype to and use of new + TclFinalizeAsync() found in tclAsync.c. + + * unix/tclUnixPort.h: + * mac/tclMacPort.h: removed #defines for TclpAsyncMark. + + * win/tclWinInit.c: Removed the TclpAsyncMark function and the + thread ID saving that was going on in TclpInitPlatform(). [the old + hack] + + * win/tclWinThread.c: TclpFinalizeCondition() and + TclpFinalizeMutex() are now properly returning the old + CriticalSection handle to the system. Tcl_CreateThread() is now + decrementing its handle reference, so the system will recover + resources when the thread closes (doh!). These changes are all + already up on the HEAD. + + * doc/Async.3: matches HEAD. + +2001-08-30 Jeff Hobbs + + * generic/tclIndexObj.c: fixed some casting problems that upset + Crays. [Bug #419528] (andreasen) + + * tests/httpd (httpdRespond): added response to timeout value in + query string. + +2001-08-30 Don Porter + + * generic/tcl.h: Silence warning from Sun compiler. [Bug 454374] + +2001-08-27 Jeff Hobbs + + * doc/Encoding.3: added note that tclPlatDecls.h must be included + for use of Tcl_WinTCharToUtf and Tcl_WinUtfToTChar. + + * doc/Tcl_Main.3: added docs for Tcl_SetMainLoop + + * generic/tclStubInit.c: + * generic/tclDecls.h: + * generic/tcl.decls: added Tcl_SetMainLoop proc that allows people + to set a main loop that will run for tclsh. + * generic/tcl.h: added Tcl_MainLoopProc typedef + * generic/tclMain.c (Tcl_SetMainLoop, StdinProc, Prompt): new + StdinProc and Prompt static procs and Tcl_SetMainLoop stubs proc. + The first two handle a fileevent based prompt (taken from + tkMain.c). Tcl_SetMainLoop enables the interactive setting of a + main loop procedure. This enables Tk to be a loadable package. + +2001-08-24 Don Porter + + * tests/unixInit.test (unixInit-2.9): Corrected expected result + to match Tcl's quirky construction of its init library path. + + * tests/ioUtil.test (ioUtil-3.*): Corrected errors in tests + revealed by fix of overagressive compiler. [Bug 451200] + + * doc/tclsh.1: Added note that the tclsh program is frequently + installed with the Tcl version numer as part of the name. + [Patch 402725] + + * generic/tclPkg.c: + * tests/pkg.test: [package forget] now forgets all of the + package arguments it receives, not stopping when a package is + not found. [Bug 415273] + + * doc/pkgMkindex.n: + * library/package.tcl: Corrected documentation and usage + message of [pkg_mkIndex]. + + * tests/unixInit.test (unixInit-2.8): Added extra constraint, + notInstalledInTmp, to stop this test from damaging installations + in /tmp; not much fun to have to reinstall the Tcl library every + time you run the test suite! + + * tests/unixInit.test (unixInit-2.9): + * unix/tclUnixInit.c (TclpInitLibraryPath): + * win/tclWinInit.c (TclpInitLibraryPath): Corrected buggy + construction of search path entries relative to executable. + Added test for bad construction. [Bug 438014] + + * tests/cmdMZ.test (cmdMZ-1.4): added notLinux constraint to test + to prevent failure message on Linux due to OS caching bug. + + * doc/library.n: + * library/init.tcl: + * tests/autoMkindex.t*: Modified [auto_import] to apply + pattern matching in the [namespace import] style. [Bug 420186] + ***POTENTIAL INCOMPATIBILITY*** for any callers of [auto_import] + from outside Tcl that expect the pattern matching to be like that + of [string match]. + + * tools/genStubs.tcl: Add a package require of Tcl 8 + at the beginning of the script so that the script + will print a descriptive error message when run + in an old Tcl 7 shell. + +2001-08-23 Andreas Kupries + + * win/tclWinPipe.c (BuildCommandLine): Fixed tcl Bug + [432499]. Part of the code used the non-absolute path to the + executable to determine quoting. This failed if the absolute + path contained spaces, but the application name itself not. This + bug caused no trouble on Win NT 5, but does for other variants + in the Win* family. Report and fix due to Ken Poole + . + +2001-08-23 Jeff Hobbs + + * unix/configure: + * unix/tcl.m4: added QNX-6 build support. [Bug #219410] (loverso) + +2001-08-20 Jeff Hobbs + + * library/http/http.tcl (geturl): added port number to Host: + header to comply with HTTP/1.1 spec (RFC 2068). [Bug #452217] + +2001-08-08 Don Porter + + * library/dde1.1/pkgIndex.tcl: + * library/reg1.0/pkgIndex.tcl: Package dependencies. [Patch 448931] + + * library/http/http.tcl: + * library/http/pkgIndex.tcl: Upgrade to http 2.3.2. + + * library/msgcat/msgcat.tcl: + * library/msgcat/pkgIndex.tcl: Upgrade to msgcat 1.1.1. + + * library/opt/optparse.tcl: + * library/opt/pkgIndex.tcl: Upgrade to opt 0.4.3. + + * library/tcltest/tcltest.tcl: + * library/tcltest/pkgIndex.tcl: Upgrade to tcltest 1.0.1. + +2001-08-07 Miguel Sofer + + * generic/tclExecute.c: Avoid panic when there are extra items in + the tcl stack [Bugs #406709 and 439843, Patch #414470] + * tests/foreach.test: test to exercise the patch + +2001-08-06 Jeff Hobbs + + * generic/tclCmdMZ.c (Tcl_RegexpObjCmd, Tcl_RegsubObjCmd): + reordered the retrieval of arguments to avoid shimmering bug when + the pattern and string referenced the same object. + + * unix/configure: regenerated + * unix/tcl.m4: added GNU (HURD) configuration target. (brinkmann) + [Patch: #442974] + +2001-08-03 Jeff Hobbs + + * win/configure: regenerated + * win/tcl.m4: fixed DLLSUFFIX definition to always be ${DBGX}.dll. + This is necessary for TEA compliant builds that build shared + against a static-built Tcl. + * win/Makefile.in ($(TCLSH)): added $(TCL_STUB_LIB_FILE) to build + target, otherwise it wouldn't get generated in a static build. + +2001-08-06 Andreas Kupries + + * generic/tclIOCmd.c (Tcl_GetsObjCmd): Applied patch from SF item + [442665] to fix the bug reported by it. The function can corrupt + a freed object if it is called with objc == 3. This is because + it retrieves resultPtr and does not increment its reference + count, but then calls Tcl_ObjSetVar2, which causes the retrieved + resultPtr object to be released. + +2001-07-18 Andreas Kupries + + * doc/bgerror.n: Fixed Tk! Bug #415757. + +2001-07-18 Andreas Kupries + + * generic/tclIO.c: Aftermath to [SF #427196]. Squash empty buffers + if they are smaller than the requested buffersize, to prevent + reusage of old buffers and to honor changes in the requested + buffersize made by the user. + +2001-07-17 Andreas Kupries + + * generic/tclIO.c (GetInput): Fixed [SF #427196]. Memory was + overwritten because a buffer was used after a change of the + requested buffersize together with that requested buffersize and + not its actual size, which was smaller. Note that the continous + reuse of the smaller buffer negatively impacts performance. The + system never allocates a buffer with the newly requested bigger + buffersize. + +2001-07-16 Jeff Hobbs + + * win/tclWinPipe.c (PipeClose2Proc): constrained the mutex lock to + just the TerminateThread call and waiting for termination. (jsmith) + +2001-07-02 Jeff Hobbs + + * tests/util.test: added util-4.6 + * generic/tclUtil.c (Tcl_ConcatObj): Corrected walking backwards + over utf-8 chars. [Bug #227512] + +2001-06-27 Jeff Hobbs + + * generic/tclUtf.c (Tcl_UtfBackslash): Corrected backslash + handling of multibyte utf-8 chars. [Bug #217987] + + * generic/tclCmdIL.c (InfoProcsCmd): fixed potential mem leak in + info procs that created objects without using them. + + * generic/tclCompCmds.c (TclCompileStringCmd): fixed mem leak when + string command failed to parse the subcommand. + +2001-05-22 Jeff Hobbs + + * generic/tclObj.c (TclAllocateFreeObjects): simplified + objSizePlusPadding to use sizeof(Tcl_Obj) (max) + +2001-05-04 Daniel Steffen + + ** Mac 8.3.3 binary release + + ** detailed change log for changes to mac code for 8.3.3 + ** (expands on log entries below marked 2001-04-04 Jeff Hobbs) + + * generic/tcl.h: MAC_TCL: addition of ConditionalMacros.h and use of + DLLIMPORT and DLLEXPORT like on other platforms. ( => no longer need + the .exp files and can remove use of #pragma export that never worked + well) + + * mac/tclMacShLib.exp: + * mac/tclMacOSA.exp: + * mac/tclMacMSLPrefix.h: removed files + + * mac/MW_TclBuildLibHeader.h: + * mac/MW_TclBuildLibHeader.pch: + * mac/MW_TclHeaderCommon.h: + * mac/MW_TclStaticHeader.h: + * mac/MW_TclStaticHeader.pch: new precompiled header files + + * mac/MW_TclAppleScriptHeader.pch: + * mac/MW_TclHeader.pch: + * mac/MW_TclTestHeader.pch: + * mac/tclMacCommonPch.h: revised precompiled header handling: now + include a common header file 'MW_TclHeaderCommon.h' from all .pch + files, the .pch files themselves now only setup #defines (e.g. + BUILD_tcl, STATIC_BUILD, TCL_DEBUG, TCL_THREADS) like in makefiles on + other platforms. + + * mac/tclMac.h: + * mac/tclMacPort.h: + * mac/tclMacInt.h: use of BUILD_tcl and TCL_STORAGE_CLASS like on other + platforms, standardize #include'd files to what's done on other + platforms, removed use of #pragma export. + + * mac/tcltkMacBuildSupport.sea.hqx: new archive of mac build support + files & suggested build environment directory hierarchy: + - 'Building MacTclTk' & 'CW Pro6 changes' readme's. + - projects for MoreFiles 1.5.1 static & shared libraries. + - project & sources for 'pseudoCarbonSupport', see below. + + * mac/tclMacProjects.sea.hqx: updated mac build project files: + - build support for CodeWarrior Pro6, UnivIntf 3.4 & shared runtime + libraries: the MSL libraries and MoreFiles are no longer compiled into + Tcl.shlb, all non-static binaries now use the Pro6 shared runtime + libraries and MoreFiles.shlb. These shlbs are merged into the standard + Wish and TclShell, but 3rd party applications linking with Tcl.shlb or + Tk.shlb need to setup access to them. (see the "(sh-ppc)" targets + for how to do this.) + - Merging the full MSL.shlb and the other shlbs into Wish & TclShell + makes them a bit larger than before, use unmerged binaries to avoid + copying the shared code with every application, e.g. when deploying + numerous Wish based droplets. + - Note that using CW Pro5 to compile extensions is in principle still + possible, but need to link with Pro6 runtime libraries. + - Tclapplescript now loads and runs on CFM68k. + - Highly experimental "pseudoCarbon" support for Tcl only on OS 8/9: + binaries in "Build:(Carbon):" link against CarbonLib instead of + InterfaceLib, however the actual code has not been carbonized! i.e. it + will not run on OSX and may not even run properly with CarbonLib. + This should in principle allow you to build & test OS9 CFM Carbon + binaries that need to link with Tcl.shlb. On OSX you can use the + native Tcl.framework, but you have to build a MachO binary as there + is no CFM glue lib for Tcl.framework. + the library pseudoCarbonSupport.shlb manually loads the symbols + from InterfaceLib that are not in CarbonLib but are needed by the + uncarbonized code in Tcl.shlb and TclShell. + + * generic/tclMain.c: MAC_TCL: workaround for broken/non-standard isatty + on MW Pro6, #include instead of defining isatty + + * mac/tclMacPort.h: MW Pro6 changes for MSL fcntl.h, stat.h & isatty + + * mac/tclMacAppInit.c: add EXTERN to InstallConsole to enable DLL + export via the TCL_STORAGE_CLASS mechanism. + + * mac/tclMacFCmd.c: fix for FSpDirectoryCopy API change + + * mac/tclMacLibrary.c: emit compile time error when + TCL_REGISTER_LIBRARY and USE_TCL_STUBS are both defined at the same + time in an extension, this use is not currently supported and will + result in a crash when dynamically loading the extension. + + * mac/tclMacApplication.r: + * mac/tclMacLibrary.r: + * mac/tclMacOSA.r: + * mac/tclMacResource.r: fixed obsolete copyrights/dates in version + strings; updated version strings to standard usage; added support for + '(Support Libraries)' subfolder for shared runtime libraries in + unmerged binaries; commented out demo setting of "Tcl Environment + Variables" + + * mac/tclMacChan.c: + * mac/tclMacSock.c: cast for *BlockMode + + * mac/tclMacUtil.c: + * mac/tclMacMath.h: removed obsolete hypot() definition + + * generic/tclIntPlatDecls.h: + * generic/tclInt.decls: + * generic/tclStubInit.c: + * mac/tclMacNotify.c: + * mac/tclMacOSA.c: + * mac/tclMacUtil.c: + * generic/tclThreadTest.c: renamed routines conflicting with standard + Apple or MoreFiles headers (at compile or link time): + GetGlobalMouse -> GetGlobalMouseTcl + FSpGetDirectoryID -> FSpGetDirectoryIDTcl + FSpOpenResFileCompat -> FSpOpenResFileCompatTcl + FSpCreateResFileCompat -> FSpCreateResFileCompatTcl + NewThread -> NewTestThread + the renamed MoreFiles *Tcl routines are just wrappers calling into the + MoreFiles DLL. + + * mac/tclMacCommonPch.h: + * mac/tclMacThrd.c: + * mac/tclMacPanic.c: removed OLDROUTINENAMES define, renamed obsolete + apple API names to modern equivalents; UH3.4 support: added #include + , updated New*Proc() calls to New*UPP(). + + * mac/tclMacUnix.c: added missing (Tcl_Obj ***) cast to + Tcl_ListObjGetElements call + + * mac/tclMacAlloc.c: modernized TclpSysAlloc() to use temporary + memory instead of system heap memory when available (MacOS + >= 7.5 and possibly earlier, use of system heap has been + discouraged for a long time and has many disadvantages, e.g. memory + isn't paged out, and errors can very easily bring the system down); + fixed crashing bug in TclpSysRealloc() and CleanUpExitProc() where + memory was being accessed after having been deallocated; fixed + memory leak in (de)allocation code (for every block ever allocated + with TclpSysAlloc, a Ptr was leaked), if temporary memory is + available, don't track allocated memory, instead use + RecoverHandle() to get Handle from Ptr, otherwise use doubly linked + list to correctly track memory and free all allocated memory; added + new option for ConfigureMemory: MEMORY_DONT_USE_TEMPMEM, disables + use of temporary memory even when it would be available, only + necessary when writing e.g. a driver (using tcl??); increased + fraction of application heap reserved for OS routines to 512K + +2001-04-06 Jeff Hobbs + + * unix/install-sh: added -S option + * unix/tcl.m4: added Rhapsody/Darwin target + * unix/tclLoadDyld.c (TclpLoadFile): + * unix/tclMtherr.c (matherr): added support for Mac OS X + +2001-04-05 Jeff Hobbs + + * generic/tclObj.c (TclAllocateFreeObjects): simplified + objSizePlusPadding to use sizeof(Tcl_Obj) (max) + + * win/README: + * win/README.binary: removed note about use of registry (hasn't + been used for loading since 8.0). + + * win/configure: + * win/tcl.m4: added -link50compat + + * mac/tclMacProjects.sea.hqx: fixed accidental swap with Tk + project files. + +2001-04-04 Jeff Hobbs + + ** Start changes for improved mac build (steffen) ** + + * mac/tclMacShLib.exp: + * mac/tclMacMSLPrefix.h: removed files + + * generic/tcl.h: addition of ConditionalMacros.h and use of + DLLIMPORT and DLLEXPORT. + + * generic/tclIntPlatDecls.h: + * generic/tclInt.decls: + * generic/tclMain.c: + * generic/tclStubInit.c: + * generic/tclThreadTest.c: NewThread -> NewTestThread + * mac/MW_TclAppleScriptHeader.pch: + * mac/MW_TclHeader.pch: + * mac/MW_TclTestHeader.pch: + * mac/tclMac.h: + * mac/tclMacAppInit.c: + * mac/tclMacApplication.r: + * mac/tclMacChan.c: cast for *BlockMode + * mac/tclMacCommonPch.h: + * mac/tclMacFCmd.c: + * mac/tclMacInt.h: + * mac/tclMacLibrary.c: + * mac/tclMacLibrary.r: + * mac/tclMacMath.h: + * mac/tclMacNotify.c: + * mac/tclMacOSA.c: + * mac/tclMacOSA.r: + * mac/tclMacPanic.c: + * mac/tclMacPort.h: + * mac/tclMacResource.r: + * mac/tclMacSock.c: cast for *BlockMode + * mac/tclMacThrd.c: + * mac/tclMacUnix.c: + * mac/tclMacUtil.c: changed mac declarations to use Tcl ending, + fixed copyrights, updated headers, fixed comments, updated + resource files. Mac builds are now meant to be build with + MetroWerks CW 6. + + * mac/MW_TclBuildLibHeader.h: + * mac/MW_TclBuildLibHeader.pch: + * mac/MW_TclHeaderCommon.h: + * mac/MW_TclStaticHeader.h: + * mac/MW_TclStaticHeader.pch: + * mac/tcltkMacBuildSupport.sea.hqx: new files + + * mac/tclMacProjects.sea.hqx: new mac build project files. + + ** End changes for improved mac build (steffen) ** + + * unix/configure: + * unix/tcl.m4: extended test of termios vs. termio vs. sgtty to + better detect result on Linux and when certain configure + redirections are being used. (max) [Patch #402923; Bug #227412, + #219194] + +2001-04-03 Jeff Hobbs + + * generic/tclListObj.c (Tcl_SetListObj): set objPtr->length = 0 in + empty object case to maintain sanctity of Tcl_Obj bytes/length + pairing. (porter) [Patch #405998] + + * README: + * mac/README: + * win/README: + * win/README.binary: + * unix/README: updated patchlevel information to 8.3.3 and + updated links and notes. + + * generic/tcl.h: + * tools/tcl.wse.in: + * win/configure.in (TCL_PATCH_LEVEL): + * win/configure: + * unix/configure: + * unix/configure.in (TCL_PATCH_LEVEL): + * unix/tcl.spec: updated patchlevel information to 8.3.3 + + *************************************************************** + ** START OF ASYNC BACKPORT LOG (8.4aCVS 2001-04-03 -> 8.3.3) ** + *************************************************************** + + * doc/CrtChannel.3: + * doc/CrtSlave.3: + * doc/DetachPids.3: + * doc/Eval.3: + * doc/ObjectType.3: + * doc/StrMatch.3: + * doc/after.n: + * doc/append.n: + * doc/bgerror.n: + * doc/binary.n: + * doc/break.n: + * doc/case.n: + * doc/cd.n: + * doc/close.n: + * doc/concat.n: + * doc/continue.n: + * doc/dde.n: + * doc/encoding.n: + * doc/eof.n: + * doc/error.n: + * doc/eval.n: + * doc/exec.n: + * doc/exit.n: + * doc/fblocked.n: + * doc/fileevent.n: + * doc/filename.n: + * doc/flush.n: + * doc/for.n: + * doc/foreach.n: + * doc/format.n: + * doc/gets.n: + * doc/glob.n: + * doc/global.n: + * doc/http.n: + * doc/if.n: + * doc/incr.n: + * doc/join.n: + * doc/lappend.n: + * doc/library.n: + * doc/lindex.n: + * doc/linsert.n: + * doc/list.n: + * doc/llength.n: + * doc/load.n: + * doc/lrange.n: + * doc/lreplace.n: + * doc/lsort.n: + * doc/man.macros: + * doc/memory.n: + * doc/open.n: + * doc/package.n: + * doc/packagens.n: + * doc/pid.n: + * doc/pkgMkIndex.n: + * doc/proc.n: + * doc/puts.n: + * doc/pwd.n: + * doc/read.n: + * doc/regexp.n: + * doc/regsub.n: + * doc/rename.n: + * doc/resource.n: + * doc/return.n: + * doc/scan.n: + * doc/seek.n: + * doc/set.n: + * doc/split.n: + * doc/string.n: + * doc/subst.n: + * doc/switch.n: + * doc/tclvars.n: + * doc/tell.n: + * doc/time.n: + * doc/unknown.n: + * doc/update.n: + * doc/uplevel.n: + * doc/upvar.n: + * doc/variable.n: + * doc/vwait.n: + * doc/while.n: doc clarifications and cleanup from 8.4aCVS docs + +2001-04-02 Jeff Hobbs + + * win/configure: + * win/tcl.m4 (SHLIB_LD): added -incremental:no. [Bug #219381] + +2001-03-30 Jeff Hobbs + + * generic/tclCkalloc.c (TclFinalizeMemorySubsystem): set curTagPtr + to NULL to allow for reuse. + * generic/tclEvent.c (Tcl_Finalize): moved the tsdPtr + initialization inside the subsystemsInitialized check to prevent + it potentially getting called twice during finalization. (wu) + [Patch #403532, Bug #219391] + + * win/tclWinSock.c (SocketEventProc): Fixed race condition in + readability of socket on Windows. + [Patch #410674, Bug #219205 #219333] + + * win/tcl.m4: added imm32.lib to LIBS_GUI for Tk IME support. + + * win/Makefile.in (install-doc): improved install-* targets to use + their base build dependency. + +2001-03-29 Mo DeJong + + * tests/interp.test: Print out warning when + testinterpdelete command is not defined. + Add tests that checks to make sure a + child interp inherits the parent's cwd. + +2001-03-29 Jeff Hobbs + + * unix/tclUnixPipe.c (TclpCreateTempFile): prevent potential race + condition and security leak in tmp filename creation. + (max) [Patch #402924] + + * unix/configure: + * unix/tcl.m4: corrected IRIX-5.x config to not use -n32. + (english) [Patch #403626] + + * unix/tclUnixThrd.c (Tcl_ConditionWait): fixed handling of + timeout for threads (corrects excessive CPU usage issue for Tk on + Unix in threaded Tcl environment). (ruppert) [Bug #411603] + +2001-03-26 Donal K. Fellows + + * win/tclWinInt.h (tclWinTCharEncoding): Removed as now a static + variable in win/tclWin32Dll.c instead. + +2001-03-23 Jeff Hobbs + + * generic/tclVar.c (Tcl_ArrayObjCmd): Corrected retrieval of + resultPtr to prevent possible corruption. + + * generic/tclNamesp.c (Tcl_Import): Correctly freed a DString. + (lavana) [Patch #403755] + +2001-03-14 Don Porter + * library/package.tcl (pkg_mkIndex): Added patch from Vince + Darley to make [pkg_mkIndex -verbose] even more verbose. + [Bug 219349, Patch 403529] + +2001-03-13 Donal K. Fellows + + * generic/tclCmdMZ.c (Tcl_StringObjCmd): A missing + {return TCL_OK;} was causing memory corruption. [Bug #408002] + + * generic/tclExecute.c (TclDeleteExecEnv, GrowEvaluationStack, + TclExecuteByteCode): Added some casts to ClientData that are + apparently needed on some architectures. + +2001-03-02 Donal K. Fellows + + * generic/tclExecute.c (TclExecuteByteCode): Fixed bug that could + pass pointers to freed memory to command implementations, which + most obviously caused some weird behaviour with [info level], but + could have caused problems with user code and command traces too. + [Bug 404865, Patch 405436] + +2001-02-15 Donal K. Fellows + + * generic/tclCmdMZ.c (Tcl_SplitObjCmd): Improved efficiency of + splitting strings into individual characters by adding hash so + that only one Tcl_Obj per character is created. Improves + performance of splitting of short strings and makes a huge + difference to splitting of long strings, such as is done in the + mime package in tcllib. [Bug #131523] + +2001-01-30 Don Porter + * generic/tclIO.c (CopyData): Moved code that updates the count + of how many bytes are left to copy. Corrects bug that when + writing occurs in the background, the copy loop could be + escaped without updating the count, causing CopyData() to try + to copy more bytes than the toRead value originally passed to + TclCopyChannel(), leading to hangs and misreporting of number + of bytes copied. [Bug 118203, Patch 103432] + +2001-01-04 Don Porter + * tests/unixInit.test: + * unix/tclUnixInit.c (TclpInitLibraryPath): + * win/tclWinInit.c (TclpInitLibraryPath): Several entries in + the library path ($tcl_libPath) are determined relative to the + absolute path of the executable. When the executable is + installed in or near the root directory of the file system, + relative pathnames were being incorrectly generated, and in + the worst case, memory access violations were crashing the program. + [Bug 119416, Patch 102972] + +2000-12-14 Don Porter + + * generic/tclExecute.c: + * tests/expr-old.test: Re-wrote Tcl's [expr rand()] and + [expr srand($seed)] implementations, fixing a range error + on some 64-bit platforms. Added tests that detect the bug. + The rewrite changes the seed -> sequence map on 64-bit + platforms, only for seed >= 2^31, a slight incompatibility. + [Bug 121072, Patch 102781] + +2000-12-10 Don Porter + + * library/init.tcl: + * library/msgcat/msgcat.tcl: + * library/msgcat/pkgIndex.tcl: + * library/opt/optparse.tcl: + * library/opt/pkgIndex.tcl: Where [uplevel] is used in a proc + to evaluate a Tcl built-in command in the caller's context, + the built-in commands are now fully namespace-qualified. This + prevents problems when the caller context is in a namespace where + the built-in command name has been used by a command in the + namespace. (For example, [::ns::set] might be called instead + of the intended [::set]). [Bug #119422, Patch #102545] + +2000-12-09 jeff hobbs + + * docs/scan.n: + * tests/scan.test: + * generic/tclScan.c (Tcl_ScanObjCmd): changed %o and %x to use + strtoul instead of strtol to correctly preserve scan<>format + conversion of large integers. [Patch #102663, Bug #124600] + + * generic/tclExecute.c (TclExecuteByteCode): Commited patch fixing + handling of {!} in expressions. [Patch #102702] + +2000-12-08 jeff hobbs + + * library/init.tcl: Added support for PATHEXT variable in + auto_execok, recognizing the proper set of executable extensions + on Windows. [Patch #102719] + +2000-12-08 Andreas Kupries + + * generic/tclEncoding.c (LoadTableEncoding): Changed dangerous + code to something less critical. This fixes bug 119417, part A + without affecting the speed when loading encodings. + +2000-11-24 Donal K. Fellows + + * generic/tclExecute.c (TclExecuteByteCode): Logical negation "!" + can now handle string booleans, provided those values are placed + in variables. + + * tests/expr.test (expr-13.17): Check that [expr {!$var}] can + negate the string-versions of booleans "yes", "false", etc. + + * library/tcltest/tcltest.tcl (getMatchingFiles, + getMatchingDirectories): + * tools/man2html.tcl (doDir): + * tools/man2help.tcl (doDir): + * library/package.tcl (tclPkgUnknown,tclMacPkgSearch): + * library/safe.tcl (AddSubDirs): [glob] uses -directory instead of + unsafe [file join] to fix Bug #123313 + + * generic/tclIndexObj.c: + * generic/tclTestObj.c (TestindexobjCmd): Changed internal + representation of index objects to fix Bug #119082; fix + shouldn't be visible to outside world... + + * generic/tclTest.c (TestGetIndexFromObjStructObjCmd): + * tests/indexObj.test: (indexObj-6.*) Added to test for presence + of Bug #119082. + +2000-11-23 Donal K. Fellows + + * generic/tclCmdIL.c (Tcl_LsortObjCmd): Fixed memory leak from Bug + #119398 + + * library/init.tcl (unknown): Added specific level parameters to + all uplevel invokations to boost performance; didn't dare touch + the "namespace inscope" stuff though, since it looks sensitive + to me! Should fix Bug #123217, though testing is tricky... + +2000-11-16 Andreas Kupries + + * win/tclWinPort.h (line 69): Changed reference to winsock2.h into + winsock.h. This was a leftover from a foray into using winsock + version 2 (History lesson from Scott Redman and Jeff + Hobbs). This code was no problem when compiling Tcl itself, but + could trip extensions. Fixes bug 122568. + +2000-11-02 David Gravereaux + + * generic/tclEvent.c: tclLibraryPath Tcl_Obj didn't have a way + to share its data among threads. This caused Tcl_Init() to + always fail in threads. Added a way to pass the data around + with a global char*. [BUG: 5301] + +2000-11-02 Jeff Hobbs + + * unix/configure: + * unix/dltest/configure: + * win/configure: + * tools/configure: checked in configure scripts so people doing + CVS checkouts aren't required to have autoconf. Changes to + configure.in in the future will require the corresponding + configure script to also be re-autoconf'ed and checked in. + + * win/makefile.vc: + * win/tcl.m4: makefile fixes for Win64 support + + * generic/tclIndexObj.c (Tcl_GetIndexFromObjStruct): minor cast + changes. + +2000-11-01 Jeff Hobbs + + * unix/tcl.m4: removed use of -lbsd and -ldl for AIX-5. + + * tests/subst.test: added tests for non-zero return code handling + by subst. + * generic/tclParse.c (Tcl_EvalEx): corrected handling of non-zero, + non-error return code cases for subst. [BUG: 119829] + + * generic/tclVar.c (TclVarTraceExists): Corrected excessive mem + use when info exists was called on a non-existent array element. + [BUG: 119213, 119336] + +2000-10-30 David Gravereaux + + * win/configure.in: + * win/Makefile.in: + * win/makefile.vc: + * win/tcl.rc: + * win/tclsh.rc: Added logic to derive filenames better in the resource + scripts based on compile options. + +2000-10-30 Jeff Hobbs + + * unix/tclUnixInit.c: added default encoding map from + "ja_JP.eucJP" to "euc-jp". (takahashi) + + * tests/clock.test: corrected clock-2.* test numbering + + * unix/configure.in (SC_TCL_LINK_LIBS): removed code that was + commented out (it had been moved to tcl.m4's SC_TCL_LINK_LIBS + already). + + * unix/tcl.m4: consolidated gettimeofday check for AIX. + +2000-10-27 Jeff Hobbs + + * unix/configure.in: + * unix/tcl.m4: added support for AIX-5. + + * generic/tclIO.c (Tcl_NotifyChannel): removed #ifdef around code + for old channel structures, placed preserve/release around statePtr + * generic/tclIO.c (CloseChannel): the statePtr for a channel was + not being freed when the last channel in a stack was freed, + causing a mem leak. + + * unix/tclUnixChan.c: updated channel types to strict + TCL_CHANNEL_VERSION_2 style to avoid compiler warnings. They work + either way, but this avoids compiler warnings (that worries people). + +2000-10-26 David Gravereaux + + * win/tclWinFile.c (TclpMatchFilesTypes): NULL was being set to + "attr" which was a DWORD. Changed NULL to zero because a 'void *' + can't be set to a DWORD to avoid the compiler warning. + +2000-10-20 Jeff Hobbs + + * win/tclWinFile.c (TclpMatchFilesTypes): made the stat call only + occur when necessary (for 'glob' command). Significantly speeds + up glob command from 8.3. [BUG: 6216] + +2000-10-06 David Gravereaux + + * win/tclWinChan.c: moved Win2K bug case test with GetStdHandle() + from TclpGetDefaultStdChannel into Tcl_MakeFileChannel to enable + a more general method in detecting invalid OS handles rather than + just a specific known case. [BUG: 5971] + +2000-10-06 Jeff Hobbs + + * tests/cmdAH.test: extra tests for 'file channels' that include + multiple interpreter tests and channel sharing + * generic/tclIO.c (Tcl_GetChannelNamesEx): corrected function (and + consequently 'file channels') to return channels that are actually + registered for this specific interp, rather than this thread. + +2000-09-29 Jeff Hobbs + + * win/tclWinSerial.c (SerialGetOptionProc): corrected reporting of + space parity on Windows (Eason) [Bug 6057]. + + * win/Makefile.in: commented use of TESTFLAGS + * unix/Makefile.in: added TESTFLAGS to test target to + conform with Windows makefile and TEA style. + + * tests/stack.test: prevented possible crash on systems with low + default stacksize (Tru64, AIX) in infinite recursion test. A + solution to check remaining stack space in the core is best, but + hard to do in a cross-platform manner. + + * generic/tclIOGT.c (FLUSH_DELAY): renamed DELAY define to + FLUSH_DELAY to avoid defn conflict using Tru64's cc. + +2000-09-28 Jeff Hobbs + + * tools/tcl.wse.in: added tclPlatDecls.h and tkPlatDecls.h to the + Windows .exe install. + + * tests/fCmd.test (fCmd-6.20): corrected test to remove + c:/tcl8975@ after creating it. + + * tests/fileName.test: cleaned up the testing of glob patterns for + c:/globTest (Windows) to directly create/remove directory. +2000-09-27 Jeff Hobbs + + * generic/tclIO.c (StopCopy): fixed a bug introduced by a partial + fix in 8.3.2 that didn't set nonBlocking correctly when resetting + the flags for the write side. [Bug: 6261] + + *************************************************************** + ** END OF ASYNC BACKPORT LOG (8.4aCVS 2001-04-03 -> 8.3.3) ** + *************************************************************** + +2000-08-08 Jeff Hobbs + + 8.3.2 RELEASE finalized + + * changes: updated for release notes version of ChangeLog + + * library/msgcat1.0/pkgIndex.tcl: + * library/msgcat1.0/msgcat.tcl: bumped msgcat version to 1.1. + +2000-08-07 Jeff Hobbs + + * doc/ChnlStack.3: + * doc/CrtChannel.3: updated the docs to be aware of the + TCL_CHANNEL_VERSION_2 style of Tcl channels. + + * generic/tclIO.c (Tcl_CreateChannel): added assertion to verify + that the new channel versioning will be binary compatible with + older channel drivers. + + * BACKPORTED FROM 8.4 (HEAD) BRANCH: + + * doc/memory.n: Man page for Tcl "memory" command, which is + created when TCL_MEM_DEBUG is defined at compile time. + + * doc/TCL_MEM_DEBUG.3: Man page with overall information about + TCL_MEM_DEBUG usage. + + * doc/DumpActiveMemory.3: Man page for Tcl_DumpActiveMemory, + Tcl_InitMemory, and Tcl_ValidateAllMemory [Bug: 1816, 1835]. + + * doc/Init.3: Man page for Tcl_Init [Bug: 1820]. + + * unix/Makefile.in: add tclsh.ico and tcl.spec to dist target + + * unix/mkLinks: Regen'd with new mkLinks.tcl. + * unix/mkLinks.tcl: Fixed indentation, made link setup more + intelligent (only do one existance test per man page, instead of + one per function). + + * doc/AddErrInfo.3: + * doc/ChnlStack.3: + * doc/Exit.3: + * doc/GetIndex.3: + * doc/Notifier.3: + * doc/Object.3: + * doc/RegExp.3: + * doc/SetResult.3: + * doc/SplitList.3: + * doc/Thread.3: Added missing entries to NAME section. + + * doc/AddErrInfo.3: + * doc/CrtObjCmd.3: + * doc/RecEvalObj.3: Changed Tcl_EvalObj to Tcl_EvalObjEx + + * doc/library.n: Added entries for auto_qualify and auto_import + [Bug: 1271]. + * doc/library.n: Fixed .SH NAME macro to include each function + documented on the page, so that mkLinks will know about the + functions listed there, and so that the Windows help file index + will get set up correctly [Bug: 1898, 5273]. + + * doc/expr.n: Added documentation for each of the math library + functions that expr supports [Bug: 1054]. + + * doc/regsub.n: correct regsub docs [Bug: 5346] + + * doc/scan.n: minor doc fixes [Bug: 5396] + + * doc/RegExp.3: Replaced instances of "Tcl_GetRegExpInfo" with + "Tcl_RegExpGetInfo", the correct name of the function [Bug: 5901]. + + * doc/package.n: Corrected information about [package forget] + arguments [Bug: 5418]. + + * generic/tclCkalloc.c: Fixed some function headers. + + * tests/clock.test: Added test for "2 days 2 hours ago" style + specifications. + + * generic/tclDate.c: Regenerated from tclGetDate.y. + + * generic/tclGetDate.y: Tweaked grammar to properly handle the + "ago" keyword when it follows multiple relative unit specifiers, + as in "2 days 2 hours ago". [Bug: 5497]. + + * generic/tclClock.c (FormatClock): correct code to handle locale + specific return values from strftime, if any. [Bug: 3345] + + * unix/tclUnixInit.c (TclpSetInitialEncodings): attempt to + correct setlocale calls for XIM support and locale issues. + [BUG: 5422 3345 4236 2522 2521] + + * library/init.tcl (auto_import): added check to see if a valid + pattern was coming in, to avoid simple error cases [Bug: 3326] + + * library/history.tcl: Corrected an off-by-one error in HistIndex, + which was causing [history redo] to start its search at the wrong + event index. [Bug: 1269]. + + * generic/tclPosixStr.c (Tcl_SignalMsg): clarified #defines for + Linux on Sparc to compile correctly. [Bug: 5364] + + * generic/tclEnv.c: cast cleanup [Bug: 5624] + * win/tclWinFCmd.c: cast cleanup [Bug: 5627] + + * generic/tclIndexObj.c (Tcl_GetIndexFromObjStruct): Corrected + caching of the index ptr to account for offsets != sizeof(char *). + [Bug: 5153] + + * tests/opt.test: + * library/opt0.4/optparse.tcl: Applied patch from [Bug: 5922], which + corrected an incorrect use of [string match]. + + * tests/stringObj.test: Tweaked tests to avoid hardcoded + high-ASCII characters (which will fail in multibyte locales); + instead used \uXXXX syntax. [Bug: 3842]. + +2000-08-05 Jeff Hobbs + + * generic/tclIOGT.c (TclChannelTransform): fixed segfault that + would occur when transforming a channel with a proc that did not + yet exist. (Kupries) + + * generic/tclTest.c (TestChannelCmd): added some lint init'ing of + statePtr and chan vars. + +2000-07-28 Mo DeJong + + * win/Makefile.in: + * win/configure.in: + * win/tcl.m4: + * win/tclConfig.sh.in: Back port of gcc for windows + build system from 8.4. + +2000-07-26 Jeff Hobbs + + * merged core-8-3-1-io-rewrite back into core-8-3-1-branch. + The core-8-3-1-io-rewrite branch should now be considered defunct. + + * generic/tclStubInit.c: + * generic/tclDecls.h: + * generic/tcl.decls: + * generic/tcl.h: + * generic/tclIO.c: moved the Tcl_Channel* macros from tcl.h to + tclIO.c and made them proper stubbed functions. These are: + Tcl_ChannelName, Tcl_ChannelVersion, Tcl_ChannelBlockModeProc, + Tcl_ChannelCloseProc, Tcl_ChannelClose2Proc, Tcl_ChannelInputProc, + Tcl_ChannelOutputProc, Tcl_ChannelSeekProc, Tcl_ChannelSetOptionProc, + Tcl_ChannelGetOptionProc, Tcl_ChannelWatchProc, + Tcl_ChannelGetHandleProc, Tcl_ChannelFlushProc, + and Tcl_ChannelHandlerProc. These should be used to access the + Tcl_ChannelType structure instead of direct pointer dereferencing. + + * unix/Makefile.in: undid 07-25 Makefile.in changes because we + don't really want to force all private makefiles on everyone. + This needs to be addressed again in the future. Best possible + solution is to create a tcl/ subdir in the installing include dir + (as is done already with the lib dir). + + * tests/iogt.test: added RCS string, marked tests 2.* to be + unixOnly due to underlying system differences. + + * tests/all.tcl: corrected additional sets by Kupries for testing. + +2000-07-25 Brent Welch + + * unix/Makefile.in: Need to install all the Tcl headers because + Itcl depends on internal headers. + +2000-07-25 Andreas Kupries + + * tests/iogt.test: (line 866f) New tests iogt-6.[01], highlighting + buffering trouble when stacking and unstacking transformations. + iogt-6.0 is solved, see the changes below. iogt-6.1 remains, for + now, due to the perceived complexity of solutions. + + * generic/tclIO.h: (line 139f) struct Channel, added a buffer + queue, to hold data pushed back when stacking a transformation. + + * generic/tclIO.c: + (line 91f, line 7434f) New internal function 'CopyBuffer'. + Derived from 'CopyAndTranslateBuffer', with translation + removed. + (line 1025f, line 1212f): Initialization of new queue. + (line 1164f, Tcl_StackChannel): Pushback of input queue. + (line 1293f, Tcl_UnstackChannel): Discard input and pushback. + (line 3748f, Tcl_ReadRaw): Modified to use data in the push back + area before going to the driver. Uses 'CopyBuffer', s.a. + (line 4702f, GetInput): Modified to use data in the push back + area before going to the driver. + (line 4867f, Tcl_Seek): Modified to take pushback of the topmost + channel in a stack into account. + (line 5620f, Tcl_InputBuffered): See above. Added + 'Tcl_ChannelBuffered'. Analogue to 'Tcl_InputBuffered' but for + the buffer area in the channel. + + * generic/tcl.decls: New public API 'Tcl_ChannelBuffered'. S.a. + +2000-07-19 Jeff Hobbs + + * tests/socket.test: removed doTestsWithRemoteServer constraint + from socket-12.*. It requires 'exec', not a remote server. + Cleaned up some coding errors. + +2000-07-18 Brent Welch + + * win/Makefile.in: Added rules for static tcldde and tclreg libraries. + +2000-07-17 Jeff Hobbs + + * README: + * win/README: + * win/README.binary: + * win/configure.in: + * unix/configure.in: + * unix/tcl.spec: + * tools/tcl.wse.in: + * generic/tcl.h (TCL_RELEASE_SERIAL): updated to patchlevel 8.3.2 + + * unix/Makefile.in: + * win/Makefile.in: + * win/makefile.vc: added tclIOGT.c to objects list to compile. + + * generic/tclStubInit.c: + * generic/tclIntDecls.h: + * generic/tclInt.decls: commented out internal decls for + TclTestChannelCmd and TclTestChannelEventCmd as they were moved to + tclTest.c. Added new decls for TclChannelEventScriptInvoker and + TclChannelTransform. + + * generic/tclIO.h: new file that contains the main internal + structures of Tcl_Channel code to allow for multiple files to + access them. + * generic/tclTest.c: + * generic/tclIO.c: broke into 3 files - tclIO.c core code, tclIO.h + header code, and tclIOGT.c - the giot test code from Kupries. The + channel test code also moved to tclTest.c. + * generic/tclIO.c (CloseChannel): stopped masking out of the + TCL_READABLE|TCL_WRITABLE bits from the state flags in + CloseChannel, instead adding extra intelligence to + CheckChannelErrors with a new CHANNEL_RAW_MODE bit for special + behavior when called from Raw channel APIs. + +2000-07-13 Jeff Hobbs + + * generic/tclIO.c (StackSetBlockMode): moved set of chanPtr + outside of blockModeProc check to avoid infinite loop when + blockModeProc was NULL (Kupries). updated TransformSeekProc to + not call Tcl_Seek directly (Kupries). + + * win/tclWinChan.c: updated fileChannelType to v2 channel struct + * win/tclWinConsole.c: updated consoleChannelType to v2 channel struct + * win/tclWinPipe.c: updated pipeChannelType to v2 channel struct + * win/tclWinSerial.c: updated serialChannelType to v2 channel struct + * win/tclWinSock.c: updated tcpChannelType to v2 channel struct + +2000-07-11 Brent Welch + + * win/tclConfig.sh.in: Cleaned up unix-specific autoconf variables. + +2000-07-11 Jeff Hobbs + + * tests/iogt.test: made tests [345].0 not run by default as they + were failing in the new design, but I'm not convinced that the + returned result isn't correct. + + * generic/tclDecls.h: + * generic/tclStubInit.c: + * generic/tcl.decls: added Tcl_GetTopChannel C API that returns + the current top channel of a channel stack. Tcl_GetChannel was + changed earlier to return the bottommost channel of a stack + because that is the one that is guaranteed to stay around the + longest, and this was needed to compensate for certain + operations that want to look at the state of the main channel. + Most channel APIs already compensate for grabbing the top, so it + shouldn't be needed often. + + * generic/tclIO.c (Tcl_StackChannel, Tcl_UnstackChannel): Added + flushing of buffers (Kupries), removed use of DownChannel macro, + added Tcl_GetTopChannel public API to get to the top channel of + the channel stack (necessary for TLS). Rewrote Tcl_NotifyChannel + for new channel design (Kupries). Did some code cleanup in the + transform code. tclIO.c must still be broken into bits (separate + out test code and giot code, create tclIO.h). + +2000-07-10 Andreas Kupries + + * tests/iogt.test: Reverted some earlier changes as a fix by Jeff + revived the original and correct behaviour. IOW, the tests showed + a genuine error and I didn't see it :(. + + * generic/tclIO.c (Tcl_Read|Write_Raw): Changed to directly use + the drivers and not DoRead|DoWrite. The latter use the buffering + system, encoding and eol-translation and this wreaks havoc with + the data going through the transformations. Both procedures use + CheckForchannelErrors and let it believe that there is no + background copy in progress or else stacked channels could not + be used for that. + + * generic/tclIO.c (TclCopyChannel, CopyData): Moved access to the + topmost channel from the first to the second procedure to make + the decision about that at the last possible time (Callbacks can + change the stacking). + + test suite: failures of iogt-[345].0 + +2000-07-06 Jeff Hobbs + + * tests/iogt.test: new tests for stacked channel stuff based off + new 'testchannel transform|unstack' code (Kupries IOGT extension). + * generic/tcl.decls: + * generic/tcl.h: + * generic/tclDecls.h: + * generic/tclStubsInit.c: + * generic/tclIO.c: complete rewrite of Tcl Channel code for + stacked channels. Channels are now designed to work in a more + stacked fashion with a shared ChannelState data structure. + +2000-06-02 Jeff Hobbs + + * generic/tclIO.c (CloseChannel): removed the &ing out of + (TCL_READABLE|TCL_WRITABLE) from the flags, as CloseChannel does + this on the next pass through for the top channel, and it appeared + to be causing hangs by not allowing the final flush. + +2000-06-01 Jeff Hobbs + + * generic/tclIO.c (CloseChannel): Rewrote CloseChannel code to + unstack a channel during the close process. Fixed a refcount bug + in Tcl_UnstackChannel. [Bug: 5623] + (CloseChannel): further extended CloseChannel in the stacked case + to effect certain operations on the next channel that would have + been done in Tcl_Close. Also added CHANNEL_CLOSED and removed + (TCL_READABLE|TCL_WRITABLE) bits from chanPtr->flags. Changed + final reset of the WatchProc to check the chanDownPtr's (next) + interestMask. + +2000-05-29 Sandeep Tamhankar + + * tests/http.test + * doc/http.n + * library/http2.3/http.tcl: Fixed bug 5741, where unsuccessful + geturl calls sometimes leaked memory and resources (sockets). + Also, switched around some of the logic so that http::wait never + throws an exception. This is because in an asynchronous geturl, + the command callback will probably end up doing all the error + handling anyway, and in an asynchronous situation, the user + expects to check the state when the transaction completes, as + opposed to being thrown an exception. For the http package, this + menas the user can check http::status for "error" and http::error + for the error message after doing the http::wait. + +2000-04-26 Jeff Hobbs + + 8.3.1 RELEASE + + * README: + * mac/README: + * tools/tcl.wse.in: + * unix/README: + * unix/tcl.spec: + * win/README: + * win/README.binary: Updating URLs to reference dev.scriptics.com + +2000-04-25 Jeff Hobbs + + * unix/Makefile.in: + * win/Makefile.in: + * win/makefile.vc: updated for http change and some cleanup + * library/http2.[13]: moved dir http2.1 to http2.3 to match version + + * doc/Utf.3: clarified docs for Tcl_(UniChar|Utf)AtIndex + + * unix/tclUnixThrd.c: removed {}s around PTHREAD_MUTEX_INITIALIZER + [Bug: 5254] + + * unix/tclLoadDyld.c (TclpLoadFile): removed use of interp->result + +2000-04-25 Eric Melski + + * unix/mkLinks: + * doc/AddErrInfo.3: Added information about Tcl_LogCommandInfo + [Bug: 1818]. + +2000-04-24 Eric Melski + + * unix/mkLinks: + * doc/OpenFileChnl.3: Added man entry for Tcl_Ungets [Bug: 1834]. + + * unix/mkLinks: + * doc/SourceRCFile.3: Man page for Tcl_SourceRCFile [Bug: 1833]. + + * unix/mkLinks: + * doc/ParseCmd.3: Added documentation for Tcl_ParseVar [Bug: 1828]. + +2000-04-24 Jeff Hobbs + + * unix/tclUnixNotfy.c (Tcl_FinalizeNotifier, NotifierThreadProc): + added write of 'q' into triggerPipe for notifier in threaded case, + so that Tcl doesn't hang when children are still running [Bug: 4139] + + * unix/tclUnixThrd.c (Tcl_MutexLock): minor comment fixes. + +2000-04-23 Jim Ingham + + These changes make some error handling marginally better for Mac + sockets. It is still somewhat flakey, however. + + * mac/tclMacSock.c (TcpClose): Add timeouts to the close - these + don't seem to be honored, however. + Use a separate PB for the release, since an async connect socket + will still be using the original buffer. + Make sure TCPRelease returns noErr before freeing the recvBuff. + If the call returns an error, then the buffer is not right. + * mac/tclMacSock.c (CreateSocket): Add timeouts to the async + create. These don't seem to trigger, however. Sigh... + * mac/tclMacSock.c (WaitForSocketEvent): If an TCP_ASYNC_CONNECT + socket errors out, then return EWOULDBLOCK & error out. + * mac/tclMacSock.c (NotifyRoutine): Added a NotifyRoutine for + experimenting with MacTCP. + +2000-04-22 Jim Ingham + + * library/package.tcl (tclPkgUnknown): Fixed a typo in the Mac package + search part of tclPkgUnknown. + +2000-04-21 Sandeep Tamhankar + + * library/http2.1/http.tcl: Fixed a newly introduced bug where if + there's a -command callback and something goes wrong, geturl threw + an exception, called the callback, and unset the token. I changed + it so that it will not call the callback when throwing an + exception (so the caller only finds out about a given error from + one place). Also, fixed http::ncode so that it actually gives you + back the http return code (i.e. 200, 404, etc.) instead of the + first digit of the version of HTTP being used (i.e. 1). + +2000-04-21 Brent Welch + + * library/http2.1/http.tcl: More thrashing with the "server closes + without reading post data" scenario. Reverted to the previous + filevent configuratiuon, which seems to work better with small + amounts of post data. + +2000-04-20 Jeff Hobbs + + * generic/tclAlloc.c: wrapped caddr_t define to not be done on Unix + * unix/tclUnixPort.h: added Tclp*Alloc defines to allow the use of + USE_TCLALLOC on Unix. [Bug: 4731] + +2000-04-19 Jeff Hobbs + + * library/dde1.1/pkgIndex.tcl: + * library/reg1.0/pkgIndex.tcl: + * win/tclWinChan.c: + * win/tclWinThrd.c: converted CRLF to LF the */tcl.hpj.in files + were not converted, as it confuses hcw locally. [Bug: 5096] + + * win/Makefile.in: expanded cleanup target for help files + + * doc/Thread.3: minor macro cleanup + + * generic/tclFileName.c (SplitUnixPath): added support for QNX + node ids. + +2000-04-18 Jeff Hobbs + + * README: + * generic/tcl.h: + * tools/tcl.wse.in: + * unix/configure.in: + * unix/tcl.spec: + * win/configure.in: + * win/README.binary: bumped version to 8.3.1 + + * win/tcl.hpj.in: updated copyright date + + * generic/tclEnv.c: environment support for Mac OS/X + * unix/tclUnixPort.h: environment support for Mac OS/X + * unix/tclLoadDyld.c: new file for Mac OS/X dl functions + * unix/Makefile.in: added install-strip target; bindir, libdir, + mandir, includedir vars; tclLoadDyld.c target [Bug: 2527] + + * unix/tclUnixChan.c (CreateSocket): force a socket back into + blocking mode (default state) after a -async connect succeeds. + [Bug: 4388] + + * generic/tclEvent.c (TclInitSubsystems): Moved tclLibraryPath to + thread-local storage to prevent thread-related race condition. + [Bug: 5033] + * unix/tclAppInit.c (main): removed #ifdef TCL_TEST that sets the + library path as it was unnecessary and conflicts with move of + tclLibraryPath to thread-local storage. + +2000-04-18 Scott Redman + + * win/Makefile.in: + * win/tcl.rc: + * win/tclsh.rc: + * win/tclsh.ico: Modified copyright dates in Windows resource + files. Added an icon for tclsh.exe. + +2000-04-17 Brent Welch + + * generic/tcl.h, generic/tclThreadTest.c, unix/tclUnixThrd.c, + win/tclWinThread.c, mac/tclMacThread.c: + Added Tcl_CreateThreadType and TCL_RETURN_THREAD_TYPE + macros for declaring the NewThread callback proc. + +2000-04-14 Jeff Hobbs + + * unix/tclUnixChan.c (TtyParseMode): Only allow setting mark/space + parity on platforms that support it [Bug: 5089] + + * generic/tclBasic.c (Tcl_GetVersion): adjusted use of major/minor + to not conflict with global decl on some systems [Bug: 2882] + + * doc/AppInit.3: + * doc/Async.3: + * doc/BackgdErr.3: + * doc/CrtChannel.3: + * doc/CrtInterp.3: + * doc/CrtMathFnc.3: + * doc/DString.3: + * doc/Eval.3: + * doc/ExprLong.3: + * doc/GetInt.3: + * doc/GetOpnFl.3: + * doc/Interp.3: + * doc/LinkVar.3: + * doc/OpenFileChnl.3: + * doc/OpenTcp.3: + * doc/PkgRequire.3: + * doc/RecordEval.3: + * doc/SetResult.3: + * doc/SplitList.3: + * doc/StaticPkg.3: + * doc/TraceVar.3: + * doc/Translate.3: + * doc/UpVar.3: + * doc/load.n: removed or updated references to interp->result use. + +2000-04-13 Jeff Hobbs + + * doc/regexp.n: doc clarification [Bug: 5037] + * doc/update.n: typo fix [Bug: 4996] + + * unix/tcl.m4 (SC_ENABLE_THREADS): enhanced the detection of + pthread_mutex_init [Bug: 4359] and (SC_CONFIG_CFLAGS) added + --enable-64bit-vis switch for Sparc VIS compilation [Bug: 4995] + +2000-04-12 Jeff Hobbs + + * doc/dde.n: corrected dde poke docs. [Bug: 4991] + +2000-04-11 Eric Melski + + * win/tclWinPipe.c: Added "CONST" keyword to declaration of char + *native in TclpCreateTempFile, to supress compiler warnings. + +2000-04-10 Brent Welch + + * generic/tcl.h: Fixed Tcl_CreateThread declaration. + * library/tcltest1.0/tcltest.tcl: Fixed the "mainThread" + initialization to work with either testthread or the thread extension + * unix/tclUnixThrd.c: Fixed compiler warning when compiling + with -DTCL_THREADS + +2000-04-10 Eric Melski + + * win/tclWinPipe.c (TclpCreateTempFile): Added conversion of + contents string from UTF to native encoding [Bug: 4030]. + + * tests/regexp.test: Added tests for infinite looping in [regexp + -all]. + + * generic/tclCmdMZ.c: Fixed infinite loop bug with [regexp -all] + [Bug: 4981]. + + * tests/*.test: Changed all occurances of "namespace import + ::tcltest" to "namespace import -force ::tcltest" [Bug: 3948]. + +2000-04-09 Brent Welch + + * lib/httpd2.1/http.tcl: Worked on the "server closes before + reading post data" case, which unfortunately causes different + error cases on Solaris, which can read the reply, and Linux + and Windows, which cannot read anything. This is all in the + loop-back case - client and server on the same host. Also + unified the error handling so the "ioerror" status goes away + and errors are reflected in a more uniform way. Updated the + man page to document the behavior. + +2000-04-09 Jeff Hobbs + + * tests/reg.test (matchexpected): corrected tests to use tcltest + constraint types to skip certain tests. + + * generic/tclBasic.c (Tcl_SetCommandInfo): comment fix + + * unix/tclUnixThrd.c (Tcl_CreateThread): moved TCL_THREADS ifdef + inside of func as it is declared for non-threads builds as well. + In the non-threads case, it always returns TCL_ERROR (couldn't + create thread). + +2000-04-08 Andreas Kupries + + * Overall change: Definition of a public API for the creation of + new threads. + + * generic/tclInt.h (line 1802f): Removed the definition of + 'TclpThreadCreate'. (line 793f) Removed the definition of + 'Tcl_ThreadCreateProc'. + + * generic/tcl.h (line 388f): Readded the definition of + 'Tcl_ThreadCreateProc'. Added Win32 stuff send in by David + Graveraux to that too (__stdcall, + ...). Added macros for the default stacksize and allowed flags. + + * generic/tcl.decls (line 1356f): Added definition of + 'Tcl_CreateThread', slot 393 of the stub table. Two new + arguments in the public API, for stacksize and flags. + + * win/tclWinThrd.c: + * mac/tclMacThrd.c: Renamed TclpThreadCreate to Tcl_CreateThread, + added handling of the stacksize. Flags are currently ignored. + + * unix/tclUnixThrd.c: See above, but handles joinable + flag. Ignores the specified stacksize if the macro + HAVE_PTHREAD_ATTR_SETSTACKSIZE is not defined. + + * generic/tclThreadTest.c (line 363): See below. + + * unix/tclUnixNotfy.c (line 210): Adapted to the changes + above. Uses default stacksize and no flags now. + + * unic/tcl.m4 (line 382f): Added a check for + 'pthread_attr_setstacksize' to detect platforms not implementing + this feature of pthreads. If it is implemented, configure will + define the macro HAVE_PTHREAD_ATTR_SETSTACKSIZE (See + unix/tclUnixThrd.c too). + + * doc/Thread.3: Added Tcl_CreateThread and its arguments to the + list of described functions. Removed stuff about not providing a + public C-API for thread-creation. + +2000-04-07 Jeff Hobbs + + * doc/binary.n: clarified docs on sign extension in binary scan + [Bug: 3466] + + * library/tcltest1.0/tcltest.tcl (initConstraints): removed win32s + references (no longer supported) + + * tests/fCmd.test: marked test 8.1 knownBug because it is + dangerous on poorly configured systems [Bug: 3881] + and added 8.2 to keep essence of 8.1 tested. + +2000-04-05 Andreas Kupries + + * generic/tclIO.c (Tcl_UnstackChannel, line 1831): Forcing + interest mask to the correct value after an unstack and + re-initialization of the notifier via the watchProc. Without this + the first fileevent after an unstack will come through and be + processed, but no more. [Bug: ??]. + +2000-03-04 Brent Welch + + * {win,unix}/Makefile.in: added dependency of tclStubInit.c on + tcl.decls and tclInt.decls + * generic/tclThread.c: Tweak so this compiles w/out TCL_THREADS + * generic/{tcl.decls,tclStubInit.c}: Just touched the tcl.decls and + regenerated the tclStubInit.c file + +2000-03-29 Sandeep Tamhankar + + * library/http2.1/http.tcl: For the -querychannel option, + fconfigure the socket to be binary so that we don't translate + anything while reading the data. This is because we determine the + content length of the data on the channel by using seek (to the end + of the file) and tell on the file handle, and we need the + content-length to match the amount of data actually sent, and + translation can affect the number of bytes posted. + +2000-04-03 Andreas Kupries + + * Overall change: Definition of public API's for the finalization + of conditions and mutexes. [Bug: 4199]. + + * generic/tclInt.h: Removed definitions of TclFinalizeMutex and + TclFinalizeCondition. + + * generic/tcl.decls: Added declarations of Tcl_MutexFinalize and + Tcl_ConditionFinalize. + + * generic/tclThread.c: Renamed TclFinalizeMutex to + Tcl_MutexFinalize. Renamed TclFinalizeCondition to + Tcl_ConditionFinalize. + + * generic/tclNotify.c: Changed usage of TclFinalizeMutex to + Tcl_MutexFinalize. + + * unix/tclUnixNotfy.c: + * generic/tclThreadTest.c: Changed usages of TclFinalizeCondition to + Tcl_ConditionFinalize. + + * generic/tcl.h: Added empty macros for Tcl_MutexFinalize and + Tcl_ConditionFinalize, to be used when the core is compiled + without threads. + + * doc/Thread.3: Added description the new API's. + +2000-04-03 Jeff Hobbs + + * generic/tclCmdIL.c (InfoVarsCmd): checked for non-NULL procPtr + to prevent itcl info override crash [Bug: 4064] + + * tests/foreach.test: + * tests/namespace.test: + * tests/var.test: Added lsorts to avoid random sorted return + problems. [Bug: 2682] + + * tests/fileName.test: fixed 14.1 test fragility [Bug: 1482] + + * tools/man2help2.tcl: fixed winhelp cross-linking error [Bug: 4156] + improved translation to winhelp [Bug: 3679] + + * unix/Makefile.in (MAN_INSTALL_DIR): patch to accept --mandir + correctly [Bug: 4085] + + * unix/dltest/pkg[a-e].c: Cleaned up test packages [Bug: 2293] + +2000-04-03 Eric Melski + + * unix/tclUnixFCmd.c (SetGroupAttribute): + * unix/tclUnixFCmd.c (SetOwnerAttribute): Added (uid_t) and (gid_t) + casts to avoid compiler warnings. + +2000-03-31 Eric Melski + + * generic/tclGet.c (Tcl_GetDouble): Added additional conditions to + error test (previously only errno was checked, but the return + value of strtod() should be checked as well). [Bug: 4118]. + + * tests/exec.test: Added test for proper conversion of UTF data + when used with "<< $dataWithUTF" on exec's. + + * unix/tclUnixPipe.c (TclpCreateTempFile): Added + Tcl_UtfToExternalDString call, so that if there is UTF content in + the string it will be properly converted to the system encoding + before being written [Bug: 4030]. + (TclpCreateTempFile): Added a check on the return value of tmpnam; + some systems (Linux, for example) will start to return NULL after + tmpnam has been called TMP_MAX times; not checking for this can + have bad results (overwriting temp files, core dumps, etc.) + +2000-03-30 Jeff Hobbs + + * generic/tclBasic.c (Tcl_DeleteCommandFromToken): Added comments + noting the need to pair ckalloc with ckfree. [Bug: 4262] + + * generic/tclInt.decls: + * generic/tclIntPlatDecls.h: + * generic/tclStubInit.c: + * win/tclWin32Dll.c: removed TclWinSynchSpawn (vestige of Win32s + support). + + * win/tclWinReg.c: made use of TclWinGetPlatformId instead of + getting info again + + * win/tclWinPort.h: + * win/Makefile.in: + * win/configure.in: + * win/tcl.m4: Added support for gcc/mingw on Windows [Bug: 4234] + +2000-03-29 Jeff Hobbs + + * generic/tclCompile.c (TclCleanupByteCode): made ByteCode cleanup + more aware of TCL_BYTECODE_PRECOMPILED flagged structs (gen'd by + tbcload), to correctly clean them up. + + * generic/tclClock.c (FormatClock): moved check for empty format + earlier, commented 0 result return value + +2000-03-29 Sandeep Tamhankar + + * library/http2.1/http.tcl: Removed an unnecessary fileevent + statement from the error processing part of the Write method. + Also, fixed two potential memory leaks in wait and reset, in which + the state array wasn't being unset before throwing an exception. + Prior to this version, Brent checked in a fix to catch a + fileevent statement that was sometimes causing a stack trace when + geturl was called with -timeout. I believe Brent's fix is + necessary because TLS closes bad sockets for secure connections, + and the fileevent was trying to act on a socket that no longer + existed. + +2000-03-27 Jeff Hobbs + + * tests/httpd: removed unnecessary 'puts stderr "Post Dispatch"' + + * tests/namespace.test: + * generic/tclNamesp.c (Tcl_Export): added a uniq'ing test to the + export list so only one instance of each export pattern would + exist in the list. + + * generic/tclExecute.c (TclExecuteByteCode): optimized case for + the empty string in ==/!= comparisons + +2000-03-27 Eric Melski + + * unix/tclUnixChan.c: Added (off_t) type casts in lseek() call + [Bug: 4409]. + + * unix/tclLoadAout.c: + * unix/tclUnixPipe.c: Added (off_t) type casts in lseek() calls + [Bug: 4410]. + +2000-03-22 Sandeep Tamhankar + + * library/http2.1/http.tcl: Fixed a bug where string query data + that was bigger than queryblocksize would get duplicate characters + at block boundaries. + +2000-03-22 Sandeep Tamhankar + + * library/http2.1/http.tcl: Fixed bug 4463, where we were getting + a stack trace if we tried to publish a project to a good host but + a port where there was no server listening. It turned out the + problem was a stray fileevent that needed to be cleared. Also, + fixed a bug where http::code could stack trace if called on a bad + token (one which didn't represent a successful geturl) by adding + an http element to the state array in geturl. + +2000-03-21 Eric Melski + + * tests/clock.test: Modified some tests that were not robust with + respect to the time zone in which they were run and were thus + failing. + + * doc/clock.n: Clarified meaning of -gmt with respect to -base + when used with [clock scan] (-gmt does not affect the + interpretation of -base). + +2000-03-19 Sandeep Tamhankar + + * library/http2.1/http.tcl: geturl used to throw an exception when + the connection failed; I accidentally returned a token with the + error info, breaking backwards compatibility. I changed it back + to throwing an exception, but unsetting the state array first + (thus still eliminating the original memory leak problem). + +2000-03-19 Sandeep Tamhankar + + * library/http2.1/http.tcl: Added -querychannel option and altered + some of Brent's modifications to allow asynchronous posts (via + -command). Also modified -queryprogress so that it calls the + query callback as + to be consistent with -progress. Added -queryblocksize option + with default 8192 bytes for post blocksize. Fixed a bunch of + potential memory leaks for the case when geturl receives bad args + or can't open a socket, etc. Overall, the package really rocks + now. + + * doc/http.n: Added -queryblocksize, -querychannel, and + -queryprogress. Also, changed the description of -blocksize, + which states that the -progress callback will be called for each + block, to now qualify that with an "if -progress is specified". + + * tests/http.test: Added a querychannel test for synchronous and + asynchronous posts, altered the queryprogress test such that the + callback conforms to the -progress format. Also, had to use the + -queryblocksize option to do the post 16K at a time to match + Brent's expected results (and to test that -queryblocksize works). + +2000-03-15 Brent Welch + + * library/http2.1/http.tcl: Added -queryprogress callback to + http::geturl and also changed it so that writing the post data + is event driven if the queryprogress callback or a timeout is given. + This allows a timeout to occur when writing lots of post data. + The queryprogress callback is called after each block of query + data is posted. It has the same signature as the -progress callback. + +2000-03-06 Eric Melski + + * library/package.tcl: Applied patch from Bug: 2570; rather than + setting geometry of slave interp to 0x0 when Tk was loaded, it now + does "wm withdraw .". Both remove the main window from the + display, but the former caused some internal structures to get + initialized to zero, which caused crashes with some extensions. + +2000-03-02 Jeff Hobbs + + * library/package.tcl (tclPkgUnknown): extended to allow + recognizes changes in the auto_path while sourcing in other + pkgIndex.tcl files + + * doc/FindExec.3: fixed doc for declaration of Tcl_FindExecutable + [Bug: 4275] + + * generic/tclFileName.c (Tcl_TranslateFileName): Applied patch + from Newman to significantly speedup file split/join on Windows + (replaces regexp with custom parser). [Bug: 2867] + + * win/README.binary: change mailing lists from @consortium.org + to @scriptics.com [Bug: 4173] + +2000-02-28 Eric Melski + + * tests/clock.test: Added test for ISO bases < 100000 + + * generic/tclDate.c: (generated on Solaris) + * generic/tclGetDate.y: Changed condition for deciding if a number + is an ISO 8601 base from number >= 100000 to numberOfDigits >= 6. + Previously it would fail to recognize 000000 as an ISO base. + +2000-02-14 Eric Melski + + * unix/Makefile.in: Added rpm target to generate Tcl binary RPM. + + * unix/tcl.spec: RPM specification file for a Tcl binary RPM for + Linux. + +2000-02-10 Jeff Hobbs + + 8.3.0 RELEASE + + * changes: updated for 8.3.0 release + + * doc/load.n: added notes about dll load errors on Windows + + * unix/README: + * unix/Makefile.in (dist): removed porting.notes and porting.old + from distribution and CVS. The information was very outdated. Now + refer to http://dev.scriptics.com/services/support/platforms.html + + * tests/unixInit.test: fixed japanese LANG encoding test [Bug: 3549] + + * unix/configure.in: + * unix/tcl.m4: correct CFLAG_WARNING setting, + fixed gcc config for AIX, + added -export-dynamic to LDFLAGS for FreeBSD-3+ [Bug: 2998] + + * win/tclWinLoad.c (TclpLoadFile): improved error message for load + failures, could perhaps be even more intelligent. + +2000-02-09 Jim Ingham + + * mac/tclMacSock.c: Don't panic when you get an error closing an async + socket. This doesn't seem to hurt anything, and we return the error so + the caller can do the right thing. + + New Files: + * mac/MW_TclHeader.h: + * mac/MW_TclTestHeader.h: + * mac/MW_TclTestHeader.pch: + * mac/MW_TclAppleScriptHeader.h: More convenient to use .h prefix files + in the preference panels... + + The above are curtesy of Daniel Steffen (steffen@math.mq.edu.au) + +2000-02-08 Eric Melski + + * tests/clock.test: Added tests for "next monthname" constructs. + * generic/tclDate.c: + * generic/tclGetDate.y (Message): Added a grammar rule for "next + monthname" so that we can handle "next january" and similar + constructs (bug #4146). + +2000-02-08 Jeff Hobbs + + * README: + * tools/tcl.wse.in: + * unix/configure.in: + * win/configure.in: + * win/README: + * win/README.binary: + * generic/tcl.h (TCL_RELEASE_SERIAL): Moved to 8.3.0 patchlevel + + * doc/library.n: + * library/auto.tcl: fixed crufty puts code and docs [Bug: 4122] + + * library/tcltest1.0/tcltest.tcl: correctly protected searchDirectory + list to allow dirnames with spaces + + * unix/tcl.m4: changed all -fpic to -fPIC + + * generic/tclDecls.h: + * generic/tcl.decls: change Tcl_GetOpenFile to use decl of 'int + forWriting' instead of 'int write' to avoid shadowing [Bug: 4121] + + * tests/httpold.test: changed test script to source in the httpd + server procs from httpd instead of having its own set. + + * tests/httpd: improved query support in test httpd to handle fix + in http.tcl. [Bug: 4089 change 2000-02-01] + + * unix/README: fixed notes about --enable-shared and add note + about --disable-shared. + +2000-02-07 Eric Melski + + * tests/package.test: + * library/tclIndex: + * library/package.tcl: Renamed ::package namespace to ::pkg. + +2000-02-03 Eric Melski + + * doc/Package.n: + * doc/packagens.n: Renamed Package.n -> packagens.n because Windows + can't deal with case-sensitive names. + +2000-02-02 Jeff Hobbs + + * tests/regexp.test: added tests for -all and -inline switches + * doc/regexp.n: added docs for -all and -inline switches + * generic/tclCmdMZ.c (Tcl_RegexpObjCmd): added extra comments for + new -all and -inline switches to regexp command + +2000-02-01 Eric Melski + + * library/init.tcl: Applied patch from rfe 1734 regarding + auto_load errors not setting error message and errorInfo properly. + +2000-02-01 Jeff Hobbs + + * win/Makefile.in (install-*): reduced verbosity of install + + * generic/tclFileName.c (Tcl_JoinPath): improved support for special + QNX node id prefixes in pathnames [Bug: 4053] + + * library/http1.0/http.tcl: + * library/http2.1/http.tcl: The query data POSTed was newline + terminated when it shouldn't be altered [Bug: 4089] + +2000-01-31 Eric Melski + + * tests/package.test: + * library/tclIndex: + * library/package.tcl: Added ::package namespace and + ::package::create function. + + * library/init.tcl: Fixed problem with auto_load and determining + if commands were loaded. + + * library/auto.tcl: "Fixed" issues with $ in files to be auto indexed. + + * doc/Package.n: New man page for package::create function. + + * doc/pkgMkIndex.n: Added additional information. + + * doc/library.n: Added additional qualification regarding auto_mkindex. + +2000-01-28 Eric Melski + + * tests/pkg/magicchar2.tcl: + * tests/autoMkindex.test: Test for auto loader fix (bug #2480). + + * library/init.tcl: auto_load was using [info commands $name] to + determine if a given command was available; if the command name + had * or [] it, this would fail because info commands uses + glob-style matching. This is fixed. (Bug #2480). + + * tests/pkg/spacename.tcl: + * tests/pkgMkIndex.test: Tests for fix for bug #2360. + + * library/package.tcl: Fixed to extract only the first element of + the list returned by auto_qualify (bug #2360). + + * tests/pkg/magicchar.tcl: + * tests/autoMkindex.test: Test for fix for bug #2611. + + * library/auto.tcl: Fixed the regular expression that performs $ + escaping before sourcing a file to index. It was erroneously + adding \ escapes even to $'s that were already escaped, + effectively "un-escaping" those $'s. (bug #2611). + +2000-01-27 Eric Melski + + * tests/autoMkindex.test: + * library/auto.tcl: Applied patch (with slight modification) from + bug #2701: auto_mkIndex uses platform dependent file paths. + Added test for fix. + +2000-01-27 Jennifer Hom + + * library/tcltest1.0/tcltest.tcl: Changed NormalizePath to + normalizePath and exported it as a public proc. This proc + creates an absolute path given the name of the variable containing + the path to modify. The path is modified in place. + * library/tcltest1.0/pkgIndex.tcl: Added normalizePath. + * tests/all.tcl: Changed code to use normalizePath. + +2000-01-27 Eric Melski + + * tests/pkg/samename.tcl: test file for bug #1983 + + * tests/pkgMkIndex.test: + * doc/pkgMkIndex.n: + * library/package.tcl: Per rfe #4097, optimized creation of direct + load packages to bypass computing the list of commands added by + the new package. Also made direct loading the default, and added + a -lazy option. + Fixed bug #1983, dealing with pkg_mkIndex incorrectly handling + situations with two procs by the same name but in different + namespaces (ie, foo::baz and bar::baz). + +2000-01-26 Eric Melski + + * generic/tclNamesp.c: Undid fix for #956, which broke backwards + compatibility. + + * doc/variable.n: + * doc/trace.n: + * doc/namespace.n: + * doc/info.n: Added further information about differences between + "namespace which" and "info exists". + + * doc/SetErrno.3: Added descriptions of ErrnoId() and ErrnoMsg() + functions. + +2000-01-25 Jeff Hobbs + + * unix/tcl.m4: modified EXTRA_CFLAGS to add -DHAVE_TZSET for + OSF1-V* and ULTRIX-4.* when not using gcc. Also added higher min + stack size for OSF1-V* when building with threads. [Bug: 4063] + + * generic/tclClock.c (FormatClock): inlined resultPtr, as it + conflicted with var creation for HAVE_TZSET #def [Bug: 4063] + + * generic/tclCmdIL.c (Tcl_LsortObjCmd): fixed potential leak + when calling lsort -command with bad command [Bug: 4067] + + * generic/tclFileName.c (Tcl_JoinPath): added support for special + QNX node id prefixes in pathnames [Bug: 4053] + + * doc/ListObj.3: clarified Tcl_ListObjGetElements docs [Bug: 4080] + + * doc/glob.n: clarified Mac path separator determination docs. + + * win/makefile.vc: added some support for building helpfile on Windows + +2000-01-23 Jeff Hobbs + + * library/init.tcl (auto_execok): added 'start' to list of + recognized built-in commands for COMSPEC on NT. [Bug: 2858] + + * unix/tclUnixPort.h: moved include of lower since some + systems (UTS) require sys/types.h to be included first [Bug: 4031] + + * unix/tclUnixChan.c (CreateSocketAddress): changed comparison + with -1 to 0xFFFFFFFF, to ensure 32 bit comparison even on 64 bit + systems. [Bug: 3878] + + * generic/tclFileName.c: improved guessing of path separator + for the Mac. (Darley) + + * generic/tclInt.h: + * generic/tcl.decls: moved Tcl_ProcObjCmd to stubs table [Bug: 3827] + and removed 'register' from stub definition of + Tcl_AppendUnicodeToObj [Bug: 4038] + +2000-01-21 Eric Melski + + * unix/mkLinks: + * doc/GetHostName.3: Man page for Tcl_GetHostName (bug #1817). + + * doc/lreplace.n: Corrected man page with respect to treatment of + empty lists, and "prettied up" the page. (bug #1705). + +2000-01-20 Eric Melski + + * tests/namespace.test: Added test for undefined variables with + namespace which (bug #956). + + * generic/tclNamesp.c: Added check for undefined variables in + NamespaceWhichCmd (bug #956). + + * tests/var.test: Added tests for corrected variable behavior + (bug #981). + + * doc/upvar.n: Expanded explanation of upvar behavior with respect to + variable traces. (bugs 3917 1433 2110). + + * generic/tclVar.c: Changed behavior of variable command when name + refers to an element in an array (ie, "variable foo(x)") to always + return an error, regardless of existance of that element in the + array (now behavior is consistant with docs too) (bug #981). + +2000-01-20 Jeff Hobbs + + * generic/tclCmdIL.c (InfoBodyCmd): made [info body] return a + string if the body has been bytecompiled. + * generic/tclBasic.c (Tcl_EvalObjEx): added pedantic check for + originating proc body of bytecompiled code, #def'd out as the + change for [info body] should make it unnecessary + + * unix/tclUnixNotfy.c (Tcl_InitNotifier): added cast for tsdPtr + + * tests/set.test: added test for complex array elem name compiling + * generic/tclCompCmds.c (TclCompileSetCmd): Fixed parsing of array + elements during compiling, and slightly optimised same [Bug: 3889] + + * doc/tclvars.n: added definitions for tcl_(non)wordchars + + * doc/vwait.n: added notes about requirement for vwait var being + globally scoped [Bug: 3329] + + * library/word.tcl: changed tcl_(non)wordchars settings to use + new unicode regexp char class escapes instead of char sequences + +2000-01-14 Eric Melski + + * tests/var.test: Added a test for the array multiple delete + protection in Tcl_UnsetVar2. + + * generic/tclVar.c: Added protection in Tcl_UnsetVar2 against + attempts to multiply delete arrays when unsetting them (bug + #3453). This could happen if there was an unset trace on an array + element and the trace proc made a global or upvar link to the + array, and then the array was unset at the global level. See the + bug reference for more information. + + * unix/tclUnixTime.c: New clock format format. + + * compat/strftime.c: New clock format format. + + * generic/tclGetDate.y: New clock scan format. + +2000-01-13 Jeff Hobbs + + * changes: updated changes file to reflect 8.3b2 mods + + * README: + * generic/tcl.h: + * tools/tcl.wse.in: + * unix/configure.in: + * unix/tcl.m4: + * win/README.binary: + * win/configure.in: updated to patchlevel 8.3b2 + + * generic/regexec.c: added var initialization to prevent compiler + warning + +2000-01-13 Eric Melski + + * tests/cmdIL.test: Added tests for lsort -dictionary with + characters that occur between Z and a in ASCII. + + * generic/tclCmdIL.c: Modified DictionaryCompare function (used by + lsort -dictionary) to do upper/lower case equivalency before doing + character comparisons, instead of after. This fixes bug #1357, in + which lsort -dictionary [list ` AA c CC] and lsort -dictionary + [list AA c ` CC] gave different (and both wrong) results. + +2000-01-12 Eric Melski + + * tests/clock.test: Added tests for "next " and + "" + Added tests for "monday 1 week ago", etc, from RFE #3671. + + * doc/tests/clock.test: Added numerous tests for clock scan. + + * doc/generic/tclGetDate.y: Fixed some shift/reduce conflicts in + clock grammar. + + * doc/doc/clock.n: Added documentation for new supported clock + scan formats and additional explanation of daylight savings time + correction algorithm. + +2000-01-12 Jeff Hobbs + + * doc/file.n: + * tests/unixFCmd.test: + * unix/tclUnixFCmd.c: added support for symbolic permissions + setting in SetPermissionsAttribute (file attr $file -perm ...) + [Bug: 3970] + + * generic/tclClock.c: fixed support for 64bit handling of clock + values [Bug: 1806] + + * generic/tclThreadTest.c: upped a buffer size to hold double + + * tests/info.test: + * generic/tclCmdIL.c: fixed 'info procs ::namesp::*' behavior (Dejong) + + * generic/tclNamesp.c: made imported commands also import their + compile proc [Bug: 2100] + + * tests/expr.test: + * unix/Makefile.in: + * unix/configure.in: + * unix/tcl.m4: recognize strtod bug on Tru64 v5.0 [Bug: 3378] + and added tests to prevent unnecessary chmod +x in sources while + installing, as well as more intelligent setsockopt/gethostbyname + checks [Bug: 3366, 3389] + + * unix/tclUnixThrd.c: added compile time support (through use of + the TCL_THREAD_STACK_MIN define) for increasing the default stack + size for a thread. [Bug: 3797, 1966] + +2000-01-11 Eric Melski + + * generic/tclGetDate.y: Added comments for the Convert function. + Added a fix for daylight savings time handling for relative time + spans of days, weeks or fortnights. (bug 3441, 3868). + + * generic/tclDate.c: Fixed compiler warning issues. + +2000-01-10 Jeff Hobbs + + * compat/waitpid.c: use pid_t type instead of int [Bug: 3999] + + * tests/utf.test: fixed test that allowed \8 as octal value + * generic/tclUtf.c: changed Tcl_UtfBackslash to not allow + non-octal digits (8,9) in \ooo substs. [Bug: 3975] + + * generic/tcl.h: noted need to change win/tcl.m4 and + tools/tclSplash.bmp for minor version changes + + * library/http2.1/http.tcl: trim value for $state(meta) key + + * unix/tclUnixFile.c: fixed signature style on functions + + * unix/Makefile.in: made sure tcl.m4 would be installed with dist + + * unix/tcl.m4: added ELF support for NetBSD [Bug: 3959] + +2000-01-10 Eric Melski + + * generic/tclGetDate.y: Added rules for ISO 8601 formats (BUG #847): + CCYY-MM-DD + CCYYMMDD + YY-MM-DD + YYMMDD + CCYYMMDDTHHMMSS + CCYYMMDD HHMMSS + CCYYMMDDTHH:MM:SS + Fixed "clock scan " to scan the number as an hour for the + current day, rather than a minute after 00:00 for the current day + (bug #2732). + + +2000-01-07 Eric Melski + + * generic/tclClock.c: Changed switch in Tcl_ClockObjCmd to use + enumerated values instead of constants. (ie, COMMAND_SCAN instead + of 3). + +1999-12-22 Jeff Hobbs + + * changes: updated changes file + * tools/tclSplash.bmp: updated to show 8.3 + +1999-12-21 Jeff Hobbs + + * README: + * generic/tcl.h: + * mac/README: + * unix/configure.in: + * tools/tcl.wse.in: + * win/README.binary: + * win/configure.in: updated to patch level 8.3b1 + + * unix/Makefile.in: added -srcdir=... for 'make html' + + * doc/Hash.3: fixed reference to ckfree [Bug: 3912] + * doc/RegExp.3: fixed calling params for Tcl_RegExecFromObj + * doc/open.n: fixed minor formatting errors + * doc/string.n: fixed minor formatting errors + + * doc/lsort.n: added -unique docs + * tests/cmdIL.test: + * generic/tclCmdIL.c: added -unique option to lsort + + * generic/tclThreadTest.c: changed thread ids to longs [Bug: 3902] + + * mac/tclMacOSA.c: fixed applescript for I18N [Bug: 3644] + + * win/mkd.bat: + * win/rmd.bat: removed necessity of tag.txt [Bug: 3874] + + * win/tclWinThrd.c: changed CreateThread to _beginthreadex and + ExitThread to _endthreadex + +1999-12-12 Jeff Hobbs + + * doc/glob.n: + * tests/fileName.test: + * generic/tclInt.decls: + * generic/tclInt.h: + * generic/tclIntDecls.h: + * generic/tclStubInit.c: + * generic/tclEncoding.c: + * generic/tclFileName.c: + * mac/tclMacFile.c: + * unix/tclUnixFile.c: + * win/tclWinFile.c: enhanced the glob command with the new options + -types -path -directory and -join. Deprecated TclpMatchFiles with + TclpMatchFilesTypes, extended TclGlob and TclDoGlob and added + GlobTypeData structure. [Bug: 2363] + +1999-12-10 Jeff Hobbs + + * tests/var.test: + * generic/tclCompile.c: fixed problem where setting to {} array + would intermittently not work. (Fontaine) [Bug: 3339] + + * generic/tclCmdMZ.c: + * generic/tclExecute.c: optimized INST_TRY_CVT_TO_NUMERIC to + recognize boolean objects. (Spjuth) [Bug: 2815] + + * tests/info.test: + * tests/parseOld.test: + * generic/tclCmdAH.c: + * generic/tclProc.c: changed Tcl_UplevelObjCmd (uplevel) and + Tcl_EvalObjCmd (eval) to use TCL_EVAL_DIRECT in the single arg + case as well, to take advantage of potential pure list input + optimization. This means that it won't get byte compiled though, + which should be acceptable. + * generic/tclBasic.c: made Tcl_EvalObjEx pure list object aware in + the TCL_EVAL_DIRECT case for efficiency. + * generic/tclUtil.c: made Tcl_ConcatObj pure list object aware, + and return a list object in that case [Bug: 2098 2257] + + * generic/tclMain.c: changed Tcl_Main to not constantly reuse the + commandPtr object (interactive case) as it could be shared. (Fellows) + + * unix/configure.in: + * unix/tcl.m4: + * unix/tclUnixPipe.c: removed checking for compatible vfork + function and use of the vfork function. Modern VM systems rarely + suffer any performance degradation when fork is used, and it + solves multiple problems with vfork. Users that still want vfork + can add -Dfork=vfork to the compile flags. [Bug: 942 2228 1312] + +1999-12-09 Jeff Hobbs + + * win/aclocal.m4: made it just include tcl.m4 + + * doc/exec.n: + * doc/open.n: + * win/tclWin32Dll.c: + * win/tclWinChan.c: + * win/tclWinFCmd.c: + * win/tclWinInit.c: + * win/tclWinPipe.c: + * win/tclWinSock.c: removed all code that supported Win32s. It + was no longer officially supported, and likely didn't work anyway. + * win/makefile.vc: removed 16 bit stuff, cleaned up. + + * win/tcl16.rc: + * win/tclWin16.c: + * win/winDumpExts.c: these files have been removed from the + source tree (no longer necessary to build) + +1999-12-07 Jeff Hobbs + + * tests/io.test: removed 'knownBug' tests that were for + unsupported0, which is now fcopy (that already has tests) + + * mac/tclMacPort.h: added utime.h include + + * generic/tclDate.c: + * unix/Makefile.in: fixed make gendate to swap const with CONST + so it uses the Tcl defined CONST type [Bug: 3521] + + * generic/tclIO.c: removed panic that could occur in FlushChannel + when a "blocking" channel would receive EAGAIN, instead treating + it the same as non-blocking. [Bug: 3773] + + * generic/tclUtil.c: fixed Tcl_ScanCountedElement to not step + beyond the end of the counted string [Bug: 3336] + +1999-12-03 Jeff Hobbs + + * doc/load.n: added note about NT's buggy handling of './' with + LoadLibrary + + * library/http2.1/http.tcl: fixed error handling in http::Event + [Bug: 3752] + + * tests/env.test: removed knownBug limitation from working test + * tests/all.tcl: ensured that ::tcltest::testsDirectory would be + set to an absolute path + + * tests/expr-old.test: + * tests/parseExpr.test: + * tests/string.test: + * generic/tclGet.c: + * generic/tclInt.h: + * generic/tclObj.c: + * generic/tclParseExpr.c: + * generic/tclUtil.c: + * generic/tclExecute.c: added TclCheckBadOctal routine to enhance + error message checking for when users use invalid octal numbers + (like 08), as well as replumbed the Expr*Funcs with a new + VerifyExprObjType to simplify type handling. [Bug: 2467] + + * tests/expr.test: + * generic/tclCompile.c: fixed 'bad code length' error for + 'expr + {[incr]}' case, with new test case [Bug: 3736] + and seg fault on 'expr + {[error]}' (different cause) that + was caused by a correct optimization that didn't correctly + track how it was modifying the source string in the opt. + The optimization was removed, which means that: + expr 1 + {[string length abc]} + will be not be compiled inline as before, but this should be + written: + expr {1 + [string length abc]} + which will be compiled inline for speed. This prevents + expr 1 + {[mindless error]} + from seg faulting, and only affects optimizations for + degenerate cases [Bug: 3737] + +1999-12-01 Scott Redman + + * generic/tcl.decls : + * generic/tclMain.c : + * unix/tclAppInit.c: + * win/tclAppInit.c: Added two new internal functions, + TclSetStartupScriptFileName() and TclGetStartupScriptFileName() + and added hooks into the main() code for supporting TclPro and + other "big" shells more easily without requiring a copy of the + main() code. + + * generic/tclEncoding.c: + * generic/tclEvent.c: Moved encoding-related startup code from + tclEvent.c into the more appropriate tclEncoding.c. + +1999-11-30 Jeff Hobbs + + * generic/tclIO.c: fix from Kupries for Tcl_UnstackChannel that + correctly handles resetting translation and encoding. + + * generic/tclLoad.c: #def'd out the unloading of DLLs at finalize + time for Unix in TclFinalizeLoad. [Bug: 2560 3373] Should be + parametrized to allow for user to specify unload or not. + + * win/tclWinTime.c: fixed handling of %Z on NT for time zones + that don't have DST. + +1999-11-29 Jeff Hobbs + + * library/dde1.1/pkgIndex.tcl: + * library/reg1.0/pkgIndex.tcl: added supported for debugged + versions of the libraries + + * unix/tclUnixPipe.c: fixed PipeBlockModeProc to properly set + isNonBlocking flag on pipe. [Bug: 1356 710] + removed spurious fcntl call from PipeBlockModeProc + + * tests/scan.test: + * generic/tclScan.c: fixed scan where %[..] didn't match anything + and added test case [Bug: 3700] + +1999-11-24 Jeff Hobbs + + * doc/open.n: + * win/tclWinSerial.c: adopted patch from Schroedter to handle + fconfigure $sock -lasterror on Windows. [RFE: 3368] + + * generic/tclCmdIL.c: made SORTMODE_INTEGER work with Longs + [Bug: 3652] + +1999-11-23 Scott Stanton + + * library/tcltest1.0/tcltest.tcl: Fixed bug where tcltest output + went to stdout instead of the specified output file in some + cases. + +1999-11-19 Jeff Hobbs + + * generic/tclProc.c: backed out change from 1999-11-18 as it + could affect return string from upvar as well. + + * tools/tcl.wse.in: added tcltest1.0 library to distribution list + + * doc/http.n: + * library/http2.1/http.tcl: + * library/http2.1/pkgIndex.tcl: updated http package to 2.2 + +1999-11-18 Jeff Hobbs + + * unix/tcl.m4: added defined for _THREAD_SAFE in --enable-threads + case; added check for pthread_mutex_init in libc; in AIX case, + with --enable-threads ${CC}_r is used; fixed flags when using gcc + on SCO + + * generic/tclProc.c: corrected error reporting for default case + at the global level for uplevel command. + + * generic/tclIOSock.c: changed int to size_t type for len + in TclSockMinimumBuffers. + + * generic/tclCkalloc.c: fixed Tcl_DbCkfree to return a value + on NULL input. [Bug: 3400] + + * generic/tclStringObj.c: fixed support for passing in negative + length to Tcl_SetUnicodeObj, et al handling routines. [Bug: 3380] + + * doc/scan.n: + * tests/scan.test: + * generic/tclScan.c: finished support for inline scan by + supporting XPG identifiers. + + * doc/http.n: + * library/http2.1/http.tcl: added register and unregister + commands to http:: package (better support for tls/SSL), + as well as -type argument to http::geturl. [RFE: 2617] + + * generic/tclBasic.c: removed extra decr of numLevels in + Tcl_EvalObjEx that could cause seg fault. (mjansen@wendt.de) + + * generic/tclEvent.c: fixed possible lack of MutexUnlock in + Tcl_DeleteExitHandler [Bug: 3545] + + * unix/tcl.m4: Added better pthreads library check and inclusion + of _THREAD_SAFE in --enable-threads case + Added support for gcc config on SCO + + * doc/glob.n: added note about ..../ glob behavior on Win9* + * doc/tcltest.n: fixed minor example errors [Bug: 3551] + +1999-11-17 Brent Welch + * library/http2.1/http.tcl: Correctly fixed the -timeout + problem mentioned in the 10-29 change. Also added error + handling for failed writes on the socket during the protocol. + +1999-11-09 Jeff Hobbs + + * doc/open.n: corrected docs for 'a' open mode. + + * generic/tclIOUtil.c: changed Tcl_Alloc to ckalloc + + * generic/tclInt.h: + * generic/tclObj.c: rolled back changes from 1999-10-29 + Purify noted new leaks with that code + + * generic/tclParse.c: added code in Tcl_ParseBraces to test for + possible unbalanced open brace in a comment + + * library/init.tcl: removed the installed binary directory from + the auto_path variable + + * tools/tcl.wse.in: updated to 8.3a1, fixed install of twind.tcl + and koi8-r.enc files + + * unix/tcl.m4: added recognition of pthreads library for AIX + +1999-10-29 Brent Welch + * generic/tclInt.h: Modified the TclNewObj and TclDecrRefCount + in two ways. First, in the case of TCL_THREADS, we do not use + the special Tcl_Obj allocator because that is a source of + lock contention. Second, general code cleanup to eliminate + duplicated code. In particular, TclDecrRefCount now uses + TclFreeObj instead of duplicating that code, so it is now + identical to Tcl_DecrRefCount. + + * generic/tclObj.c: Changed Tcl_NewObj so it uses the + TclNewObj macro instead of duplicating the code. Adjusted + TclFreeObj so it understands the TCL_THREADS case described + above. + + * library/http2.1/http.tcl: Fixed a bug in the handling of + the state(status) variable when the -timeout flag is specified. + Previously it was possible to leave the status undefined + instead of empty, which caused errors in http::status + +1999-10-28 Jeff Hobbs + + * unix/aclocal.m4: made it just include tcl.m4 + + * library/tcltest1.0/tcltest.tcl: updated makeFile to return + full pathname of file created + + * generic/tclStringObj.c: fixed Tcl_AppendStringsToObjVA so it only + iterates once over the va_list (avoiding a memcpy of it, + which is not portable). + + * generic/tclEnv.c: fixed possible ABR error in environ array + + * tests/scan.test: + * generic/tclScan.c: added support for use of inline scan, + XPG3 currently not included + + * tests/incr.test: + * tests/set.test: + * generic/tclCompCmds.c: fixed improper bytecode handling of + 'eval {set array($unknownvar) 5}' (also for incr) [Bug: 3184] + + * win/tclWinTest.c: added testvolumetype command, as atime is + completely ignored for Windows FAT file systems + * win/tclWinPort.h: added sys/utime.h to includes + * unix/tclUnixPort.h: added utime.h to includes + * doc/file.n: + * tests/cmdAH.test: + * generic/tclCmdAH.c: added time arguments to atime and mtime + file command methods (support 'touch' functionality) + +1999-10-20 Jeff Hobbs + + * unix/tclUnixNotfy.c: fixed event/io threading problems by + making triggerPipe non-blocking [Bug: 2792] + + * library/tcltest1.0/tcltest.tcl: + * generic/tclThreadTest.c: fixed mem leaks in threads + + * generic/tclResult.c: fixed Tcl_AppendResultVA so it only + iterates once over the va_list (avoiding a memcpy of it, + which is not portable). + + * generic/regc_color.c: fixed mem leak and assertion, from HS + + * generic/tclCompile.c: removed savedChar trick that appeared to + be causing a segv when the literal table was released + + * tests/string.test: + * generic/tclCmdMZ.c: fixed [string index] to return ByteArrayObj + when indexing into one (test case string-5.16) [Bug: 2871] + + * library/http2.1/http.tcl: protected gets with catch [Bug: 2665] + +1999-10-19 Jennifer Hom + + * tests/tcltest.test: + * doc/tcltest.n: + * library/tcltest1.0/tcltest.tcl: Removed the extra return at the + end of the tcltest.tcl file, added version information about tcl. + + Applied patches sent in by Andreas Kupries to add helper procs for + debug output, add 3 new flags (-testsdir, -load, -loadfile), and + internally refactors common code for dealing with paths into + separate procedures. [Bug: 2838, 2842] + + Merged code from core-8-2-1 branch that changes the checks for the + value of tcl_interactive to also incorporate a check for the + existence of the variable. + + * tests/autoMkindex.test: + * tests/pkgMkIndex.test: Explicitly cd to + ::tcltest::testsDirectory at the beginning of the test run + + * tests/basic.test: Use version information defined in tcltest + instead of hardcoded version number + + * tests/socket.test: package require tcltest before attempting to + use variable defined in tcltest namespace + + * tests/unixInit.test: + * tests/unixNotfy.test: Added explicit exits needed to avoid + problems when the tests area run in wish. + +1999-10-12 Jim Ingham + + * mac/tclMacLoad.c: Stupid bug - we converted the filename to + external, but used the unconverted version. + * mac/tclMacFCmd.c: Fix a merge error in the bug fix for [Bug: 2869] + +1999-10-12 Jeff Hobbs + + * generic/regc_color.c: + * generic/regc_cvec.c: + * generic/regc_lex.c: + * generic/regc_locale.c: + * generic/regcomp.c: + * generic/regcustom.h: + * generic/regerrs.h: + * generic/regex.h: + * generic/regexec.c: + * generic/regguts.h: + * generic/tclRegexp.c: + * generic/tclTest.c: + * tests/reg.test: updated to Henry Spencer's new regexp engine + (mid-Sept 99). Should greatly reduce stack space reqs. + + * library/tcltest1.0/pkgIndex.tcl: fixed procs in pkgIndex.tcl file + + * generic/tclEnv.c: fixed mem leak with putenv and DStrings + * doc/Encoding.3: corrected docs + * tests/basic.test: updated test cases for 8.3 + * tests/encoding.test: fixed test case that change system + encoding to a double-byte one (this causes a bogus mem read + error for purify) + * unix/Makefile.in: purify has to use -best-effort to instrument + * unix/tclAppInit.c: identified potential mem leak when compiling + tcltest (not critical) + * unix/tclUnixPipe.c: fixed mem leak in TclpCreateProcess when + doing alloc between vfork and execvp. + * unix/tclUnixTest.c: fixed mem leak in findexecutable test command + +1999-10-05 Jeff Hobbs + + * {win,mac,unix,tools,}/README: + * win/README.binary: + * win/makefile.vc: + * {win,unix}/configure.in: + * generic/tcl.h: + * library/init.tcl: updated to 8.3a1 from 8.2.0. + + * library/http2.1/http.tcl: fixed possible use of global c var. + + * win/tclWinReg.c: fixed registry command to properly 'get' + HKEY_PERFORMANCE_DATA root key data. Needs more work. + + * generic/tclNamesp.c: + * generic/tclVar.c: + * generic/tclCmdIL.c: fixed comment typos + + * mac/tclMacFCmd.c: fixed filename stuff to support UTF-8 [Bug: 2869] + + * win/tclWinSerial.c: changed SerialSetOptionProc to return + TCL_OK by default. (patch from Rolf Schroedter) + +1999-09-21 Jennifer Hom + + * library/tcltest1.0/tcltest.tcl: Applied patches sent in by + Andreas Kupries to fix typos in comments and ::tcltest::grep, + fix hook redefinition problems, and change "string compare" to + "string equal." [Bug: 2836, 2837, 2839, 2840] + +1999-09-20 Jeff Hobbs + + * tests/env.test: + * unix/Makefile.in: added support for AIX LIBPATH env var [Bug: 2793] + removed second definition of INCLUDE_INSTALL_DIR (the one that + referenced @includedir@) [Bug: 2805] + * unix/dltest/Makefile.in: added -lc to LIBS [Bug: 2794] + +1999-09-16 Jeff Hobbs + + * tests/timer.test: changed after delay in timer test 6.29 from + 1 to 10. [Bug: 2796] + + * tests/pkg.test: + * generic/tclPkg.c: fixed package version check to disallow 1.2..3 + [Bug: 2539] + + * unix/Makefile.in: fixed gendate target - this never worked + since RCS was intro'd. + * generic/tclGetDate.y: updated to reflect previous changes + to tclDate.c (leap year calc) and added CEST and UCT time zone + recognition. Fixed 4 missing UCHAR() casts. [Bug: 2717, 954, + 1245, 1249] + + * generic/tclCkalloc.c: changed Tcl_DumpActiveMemory to really + dump to stderr and close it [Bug: 725] and changed Tcl_Ckrealloc + and Tcl_Ckfree to not bomb when NULL was passed in [Bug: 1719] + and changed Tcl_Alloc, et al to not panic when a alloc request + for zero came through and NULL was returned (valid on AIX, Tru64) + [Bug: 2795, etc] + + * tests/clock.test: + * doc/clock.n: + * generic/tclClock.c: added -milliseconds switch to clock clicks + to guarantee that the return value of clicks is in the millisecs + granularity [Bug: 2682, 1332] + +1999-09-15 Jeff Hobbs + + * generic/tclIOCmd.c: fixed potential core dump in conjunction + with stacked channels with result obj manipulation in + Tcl_ReadChars [Bug: 2623] + + * tests/format.test: + * generic/tclCmdAH.c: fixed translation of %0#s in format [Bug: 2605] + + * doc/msgcat.n: fixed \\ bug in example [Bug: 2548] + + * unix/tcl.m4: + * unix/aclocal.m4: added fix for FreeBSD-[1-2] recognition + [Bug: 2070] and fix for IRIX SHLIB_LB_LIBS. [Bug: 2610] + + * doc/array.n: + * tests/var.test: + * tests/set.test: + * generic/tclVar.c: added an array unset operation, with docs + and tests. Variation of [Bug: 1775]. Added fix in TclArraySet + to check when trying to set in a non-existent namespace. [Bug: 2613] + +1999-09-14 Jeff Hobbs + + * tests/linsert.test: + * doc/linsert.n: + * generic/tclCmdIL.c: fixed end-int interpretation of linsert + to correctly calculate value for end, added test and docs [Bug: 2693] + + * doc/regexp.n: + * doc/regsub.n: + * tests/regexp.test: + * generic/tclCmdMZ.c: add -start switch to regexp and regsub + with docs and tests + + * doc/switch.n: added proper use of comments to example. + * generic/tclCmdMZ.c: changed switch to complain when an error + occurs that seems to be due to a misplaced comment. + + * generic/tclCmdMZ.c: fixed illegal ref for \[0-9] substitutions + in regsub [Bug: 2723] + + * generic/tclCmdMZ.c: changed [string equal] to return an Int + type object (was a Boolean) + +1999-09-01 Jennifer Hom + + * library/tcltest1.0/tcltest.tcl: Process command-line arguments + only ::tcltest doesn't have a child namespace (requires that + command-line args are processed in that namespace) + +1999-09-01 Jeff Hobbs + + * generic/tclParseExpr.c: changed '"' to '\"' to make FreeBSD + happy [Bug: 2625] + * generic/tclProc.c: moved static buf to better location and + changed static msg that would overflow in ProcessProcResultCode + [Bug: 2483] and added Tcl_DStringFree to Tcl_ProcObjCmd. + Also reworked size of static buffers. + * tests/stringObj.test: added test 9.11 + * generic/tclStringObj.c: changed Tcl_AppendObjToObj to + properly handle the 1-byte dest and mixed src case where + both had had Unicode string len checks made on them. [Bug: 2678] + * unix/aclocal.m4: + * unix/tcl.m4: adjusted fix from 8-21 to add -bnoentry to the + AIX-* case and readjusted the range + +1999-08-31 Jennifer Hom + + * library/tcltest1.0/tcltest.tcl: + * doc/tcltest.n: + * tests/README: Modified testConstraints variable so that it isn't + unset every time ::tcltest::initConstraints is called and cleaned up + documentation in the README file and the man page. + +1999-08-27 Jennifer Hom + + * tests/env.test: + * tests/exec.test: + * tests/io.test: + * tests/event.test: + * tests/tcltest.test: Added 'exit' calls to scripts that the tests + themselves write, and removed accidental checkin of knownBugThreaded + constraints for Solaris and Linux. + + * library/tcltest1.0/tcltest.tcl: Modified tcltest so that + variables are only initialized to their default values if they did + not previously exist. + +1999-08-26 Jennifer Hom + + * tests/tcltest.test: + * library/tcltest1.0/tcltest.tcl: Added a -args flag that sets a + variable named ::tcltest::parameters based on whatever's being + sent in as the argument to the -args flag. + +1999-08-23 Jennifer Hom + + * tests/tcltest.test: Added additional tests for -tmpdir, marked + all tests that use exec as unixOrPc. + + * tests/encoding.test: + * tests/interp.test: + * tests/macFCmd.test: + * tests/parseOld.test: + * tests/regexp.test: Applied patches from Jim Ingham to add + encoding to a Mac only interp test, change an error message in + macFCmd.tet, put a comment in parseOld.test, fix tests using the + testencoding path command, and put unixOrPc constraints on tests + that use exec. + +1999-08-21 Jeff Hobbs + + * unix/aclocal.m4: Changed AIX-4.[2-9] check to AIX-4.[1-9] + [Bug: 1909] + +1999-08-20 Jeff Hobbs + + * generic/tclPosixStr.c: fixed typo [Bug: 2592] + + * doc/*: fixed various nroff bugs in man pages [Bug: 2503 2588] + +1999-08-19 Jeff Hobbs + + * win/README.binary: fixed version info and some typos [Bug: 2561] + + * doc/interp.n: updated list of commands available in a safe + interpreter [Bug: 2526] + + * generic/tclIO.c: changed Tcl_GetChannelNames* to use style guide + headers (pleases HP cc) + +1999-08-18 Jeff Hobbs + + * doc/Eval.3: fixed doc on input args [Bug: 2114] + + * doc/OpenFileChnl.3: + * doc/file.n: + * tests/cmdAH.test: + * tclIO.c: + * tclCmdAH.c: added "file channels ?pattern?" tcl command, with + associated Tcl_GetChannelNames and Tcl_GetChannelNamesEx public + C APIs (added to tcl.decls as well), with docs and tests. + + * tests/expr.test: + * generic/tclCompile.c: add TCL_TOKEN_VARIABLE to the part types + that cause differed compilation for exprs, to correct the expr + double-evaluation problem for vars. Added test cases. + Related to [Bug: 732] + + * unix/Makefile.in: changed the dependency structure so that + install-* is dependent on * (ie - install-binaries is dependent + on binaries). + + * library/auto.tcl: + * library/init.tcl: + * library/ldAout.tcl: + * library/package.tcl: + * library/safe.tcl: + * library/word.tcl: + * library/http2.1/http.tcl: + * library/msgcat1.0/msgcat.tcl: updated libraries to better + Tcl style guide (no more string comparisons with == or !=, spacing + changes). + +1999-08-05 Jim Ingham + + * mac/tclMacProjects.sea.hqx: Rearrange the projects so that the build + directory is separate from the sources. Much more convenient! + +1999-08-13 Scott Redman + + * /: 8.2.0 tagged for final release + +1999-08-12 Scott Stanton + + * win/Makefile.in: Added COMPILE_DEBUG_FLAGS macro to make it + easier to turn on compiler tracing. + + * tests/parse.test: + * generic/tclParse.c: Fixed bug in Tcl_EvalEx where the termOffset + was not being updated in cases where the evaluation returned a non + TCL_OK error code. [Bug: 2535] + +1999-08-12 Scott Redman + + * win/tclWinSerial.c: Applied patch from Petteri Kettunen to + remove compiler warning. + +1999-08-10 Scott Redman + + * generic/tclAlloc.c: + * generic/tclCmdIL.c: + * generic/tclIO.c: + * generic/tclThread.c: + * win/tclWinThrd.c: + * unix/tclUnixThrd.c: Fixed Brent's changes so that they work on + Windows (and he fixed the bug in the Unix thread implementation). + +1999-08-09 Brent Welch + + * generic/tcl.decls: + * generic/tclAlloc.c: + * generic/tclCkalloc.c: + * generic/tclCmdIL.c: + * generic/tclDecls.h: + * generic/tclIO.c: + * generic/tclInt.decls: + * generic/tclIntDecls.h: + * generic/tclStubInit.c: + * generic/tclVar.c: + * mac/tclMacThrd.c: + * unix/tclUnixThrd.c: + * win/tclWinThrd.c: Added use of Tcl_GetAllocMutex to tclAlloc.c + and tclCkalloc.c so they can be linked against alternate thread + packages. Added Tcl_GetChannelNames to tclIO.c. Added + TclVarTraceExists hook so "info exists" triggers read traces + exactly like it did in Tcl 7.6. Stubs table changes to reflect new + internal and external APIs. + +1999-08-09 Jeff Hobbs + + * tests/string.test: added largest_int proc to adapt for >32 bit + machines and int overflow testing. + * tests/tcltest.test: fixed minor error in 8.2 result (from dgp) + + * doc/Object.3: clarified Tcl_DecrRefCount docs [Bug: 1952] + * doc/array.n: clarified array pattern docs [Bug: 1330] + * doc/clock.n: fixed clock docs [Bug: 693] + * doc/lindex.n: clarified to account for new end-int behavior. + * doc/string.n: fixed formatting errors [Bug: 2188 2189] + * doc/tclvars.n: fixed doc error [Bug: 2042] + * library/init.tcl: fixed path handling in auto_execok (it could + miss including the normal path on some Windows machines) [Bug: 1276] + +1999-08-05 Jeff Hobbs + + * doc/tclvars.n: Made it clear that tcl_pkgPath was not set + for Windows (already mentioned in init.tcl) [Bug: 2455] + * generic/tclLiteral.c: fixed reference to bytes that might + not be null terminated (using objPtr->bytes, which is) [Bug: 2496] + * library/http2.1/http.tcl: Made use of "i" in init section use + local var and start at 0 (was 1). [Bug: 2502] + +1999-08-04 Scott Stanton + + * tests/reg.test: Added test for REG_EXPECT bug fixed by Henry's + patch. + + * generic/regc_nfa.c: + * generic/regcomp.c: + * generic/rege_dfa.c: + * generic/regexec.c: + * generic/regguts.h: Applied patches supplied by Henry Spencer to + greatly enhance the performance of certain classes of regular + expressions. [Bug: 2440, 2447] + +1999-08-03 Scott Redman + + * win/tclWinInt.h: Remove function declarations in header that was + moved to tclInt.decls file in previous changes. + +1999-08-02 Scott Redman + + * unix/configure.in: + * win/configure.in: Change beta level to b2. + + * generic/tcl.h: + * generic/tcl.decls: + * generic/tclDecls.h: + * generic/tclInt.h: + * generic/tclInt.decls: + * generic/tclIntDecls.h: + * generic/tclRegexp.h: + * generic/tclStubInit.c: Move some exported public and internal + functions to the stub tables. Removed functions that are in the + stub tables (from this and previous changes) from the original + header files. + +1999-08-01 Scott Redman + + * win/tclWinSock.c: Added comment block to SocketThread() + function. Added code to avoid calling TerminateThread(), but + instead to send a message to the socket event window to tell it to + terminate its thread. + +1999-07-30 Jennifer Hom + + * tests/tcltest.test: + * library/tcltest1.0/tcltest.tcl: Exit with non-zero status if + there were problems with the way the test suite was started + (e.g. wrong # arguments). + +1999-07-30 Jeff Hobbs + + * generic/tclInt.decls: added declaractions necessary for the + Tcl test code to work wth stubs [Bug: 2445] + +1999-07-30 + + * win/tclWinPipe.c: + * win/Makefile.in: Fixing launching of 16-bit apps on Win9x from + wish. The command line was primed with tclpip82.dll, but it was + ignored. Fixed that, then fixed the gmake makefile to build + tclpip82.dll as an executable. + + * win/tclWinSock.c: Applied small patch to get thread-specific + data after initializing the socket driver. + + * unix/tclUnixThrd.c: Applied patch to fix threads on Irix 6.5. + Patch from James Dennett. [Bug: 2450] + + * tests/info.test: Enable test for tclParse.c change (info + complete). + +1999-07-30 + + * tclIO.c: added fix for Kupries' trf patch [Bug: 2386] + + * tclParse.c: fixed bug in info complete regarding nested square + brackets [Bug: 2382, 2466] + +1999-07-29 + + * win/tclWinChan.c: Allow tcl to open CON and NUL, even for std + channels. Checking for bad/unusable std channels was moved to Tk + since its only purpose was to check whether to use the Tk Console + Window for the std channels. [Bug: 2393 2392 2209 2458] + + * unix/mkLinks.tcl: Applied patch to avoid linking pack.n to + pack-old.n. Patch from Don Porter. [Bug: 2469] + + * doc/Encoding.n: Applied patch to fix typo in .SH NAME line. + Patch from Don Porter. [Bug: 2451] + + * win/tclWinSock.c: Free Win32 Event handles when destroying + the socket helper thread. + +1999-07-28 + + * tests/tcltest.test: + * library/tcltest1.0/tcltest.tcl: Fixed the condition under which + ::tcltest::PrintError had an infinite loop problem and added a + test case for it. Added an optional argument to + ::tcltest::getMatchingFiles telling it where to search for test + files. + +1999-07-27 + + * tools/tclSplash.bmp: Updated Windows installer bitmap + to ready Tcl/Tk Version 8.2. + +1999-07-26 + + * tests/tcltest.test: Need to close the new core file, there + seems to be a hang in threaded WinNT if the file isn't closed. + Open issue, need to fix that hang. + + * tests/httpold.test: Add time delay in response from Http server + so that test cases can properly detect timeout conditions with + threads enabled on multi-CPU WinNT. + + * tests/winFCmd.test: Test case winFcmd-1.33 was looking for + c:\windows, which may not exist. Instead, create a new directory + on c:\ and use it for the test. + + * win/tclWinConsole.c: + * win/tclWinPipe.c: + * win/tclWinSock.c: Fix terminating helper threads by holding any + mutexes from the primary thread while waiting for the helper + thread to terminate. Without these changes, the test suite hangs + on WinNT with 2 CPUs and threads enabled. Open issue, seems to be + a sporadic hang on dual CPU systems still (very rare). + +1999-07-26 Jennifer Hom + + * tests/tcltest.test: + * library/tcltest1.0/tcltest.tcl: + * doc/tcltest.n: Cleaned up code in ::tcltest::PrintError, revised + documentation, and added tests for the tcltest package. + +1999-07-23 + + * tests/info.test: + * generic/tclParse.c: Removed patch for info command, breaks test + cases on Unix. Patch was bad and needs to be redone + properly. [Bug: 2382] + +1999-07-22 + + * Changed version to 8.2b2. + + * win/tclWinSock.c: Fixed hang with threads enabled, fixed + semaphores with threads disabled. + + * win/safe.test: Fixed safe-6.3 with threads enabled. + + * win/Makefile.in: Fixed calling of tcltest to fix safe.test + failures due to path TCL_LIBRARY path. + + * win/tclWinPort.h: Block out include of sys/*.h in order to + build extensions with MetroWerks compiler for Win32. [Bug: 2385] + + * generic/tclCmdMZ.c: + * generic/tclIO.c: Fix ANSI-style prototypes based on patch from + Ulrich Ring. [Bug: 2391] + + * unix/Makefile.in: Need to make install-sh executable before + calling (with chmod +x). [Bug: 2413] + + * tests/var.test: + * generic/tclVar.c: Fixed bug that caused a seg. fault when using + "array set a(b) {}", which is a bad array name anyway. Now the + "array set" command will return an error in this case. Added test + case and fixed existing test. [Bug: 2427] + +1999-07-21 + + * tests/info.test: + * generic/tclParse.c: Applied patch to fix "info complete" + for the string {[a [b]}. Patch from Peter Spjuth. [Bug: 2382] + + * doc/Utf.3: + * generic/tcl.decls: + * generic/tclDecls.h: + * generic/tclUtf.c: Changed function declarations in + non-platform-specific public APIs to use "unsigned long" instead of + "size_t", which may not be defined on certain compilers (rather + than include sys/types.h, which may not exist). + + * unix/Makefile.in: Added the Windows configure script to the + distribution file list, already shipping configure.in and the .m4 + files, but needed the configure script itself. + + * win/makefile.vc: Changed version number of DDE package in VC++ + makefile to use 1.1 instead of 1.0. + + * doc/open.n: Added documentation of \\.\comX notation for opening + serial ports on Windows (alternative to comX:). + + * tests/ioCmd.test: + * doc/open.n: + * win/tclWinSerial.c: Applied patch from Rolf Schroedter to add + -pollinterval option to fconfigure to modify the maxblocktime used + in the fileevent polling. Added documentation and fixed the test + case as well. + + * win/tclWinSock.c: Modified 8.1.0 version of the Win32 socket + driver to move the handling of the socket event window in a + separate thread. It also turned out that Win95 & Win98 were, in + some cases, getting multiple FD_ACCEPTs but only handling one. + Added a count for the FD_ACCEPT to take care of this. Tested on + NT4 SP3, NT4 SP4, Win95, and Win98. + [Bug: 2178 2256 2259 2329 2323 2355] + +1999-07-21 + + * README: Small tweaks to clean up typos and wording. + +1999-07-20 Melissa Hirschl + + * generic/tclInitScript.h: + * unix/tclUnixInit.c: merged code with 8.0.5. We now use an + intermediate global tcl var "tclDefaultLibrary" to keep the + "tcl_library" var from being set by the default value in the + Makefile. Also fixed a bug in which caused the value of + TCL_LIBRARY env var to be ignored. + * unix/tclWinInit.c: just updated some comments. + +1999-07-19 Melissa Hirschl + + * library/http2.1/http.tcl: updated -useragent text to say version + 2.1. + +1999-07-16 + + * generic/tcl.decls: + * generic/tclDecls.h: + * generic/tclStubInit.c: Add Tcl_SetNotifier to stub table. + [Bug: 2364] + + * unix/aclocal.m4: + * unix/tcl.m4: Add check for Alpha/Linux to correct the IEEE + floating flag to the compiler, should be -mieee. Patch from Don + Porter. + + * tools/tcl.hpj.in: Change version number of .cnt file referenced + in .HPJ file. + +1999-07-15 + + * tools/tcl.wse.in: Fixed naming of target files for Windows. + +1999-07-14 + + * doc/re_syntax.n: Deleted sentence as suggested by Scott S. + +1999-07-12 + + * doc/re_syntax.n: Removed two notes to myself (oops), cleaned + up wording, fixed changebars, made two examples easier to read. + +1999-07-11 + + * win/makefile.vc: Since the makefile.vc should continue to work + while we're working out bugs/issues in the new TEA-style + autoconf/configure/gmake build mechanism for Windows, the version + numbers of the Tcl libraries need to remain in sync. Modified the + version numbers in the makefile to reflect the change to 8.2b1. + +1999-07-09 + + * win/configure.in: Eval DLLSUFFIX, LIBSUFFIX, and EXESUFFIX in + the configure script so that substitutions get expanded before + being placed in the Makefile. The "d" portion for debug libraries + and DLLs was not being set properly. + +1999-07-08 + + * tests/string.test: + * generic/tclCmdMZ.c: Fixed bug in string range bounds checking + code. + +1999-07-08 Jennifer Hom + + * doc/tcltest.n: + * library/tcltest1.0/tcltest.tcl: Removed -asidefromdir and + -relateddir flags, removed unused ::tcltest::dotests proc, cleaned + up implementation of core file checking, and fixed the code that + checks for 1-letter flag abbreviations. + +1999-07-08 + + * win/Makefile.in: Added tcltest target so runtest works + properly. Added missing names to the clean/distclean targets. + + * tests/reg.test: + * generic/rege_dfa.c: Applied fix supplied by Henry Spencer for + bug in DFA state caching under lookahead conditions. [Bug: 2318] + +1999-07-07 + + * doc/fconfigure.n: Clarified default buffering behavior for the + standard channels. [Bug: 2335] + +1999-07-06 + + * win/tclWinSerial.c: New implementation of serial port driver + from Rolf Shroedter (Rolf.Schroedter@dlr.de) that allows more than + one byte to be read from the port. Implemented using polling + instead of threads, there is a max. 10ms latency between checking the + port for file events. [Bug: 1980 2217] + +1999-07-06 + + * library/http2.0/http.tcl: Fixed the -timeout option so it + handles timeouts that occur during connection attempts to + hosts that are down (the only case that really matters!) + +1999-07-03 + + * doc/ChnlStack.3: + * generic/tcl.decls: + * generic/tclIO.c: Added a new variant of the "Trf patch" + from Andreas Kupres that adds new C APIs Tcl_StackChannel, + Tcl_UnstackChannel, and Tcl_GetStackedChannel. + +1999-07-03 + + * generic/tclNotify.c: + * unix/tclUnixNotfy.c: + * unix/tclXtTest.c: + * unix/tclXtNotify.c: + * win/tclWinNotify.c: + * mac/tclMacNotify.c: Added Tcl_SetNotifier and the associated + hook points in the notifiers to be able to replace the notifier + calls at runtime The Xt notifier and test program use this hook. + +1999-07-03 + + * generic/tclParse.c: Changed parsing of variable names to + allow empty array names. Now "$(foo)" is a variable reference! + Previous you had to use something like $::(foo), which is slower. + This change is requested by Jean-Luc Fontaine for his STOOOP + package. + +1999-07-01 + + * generic/tclCmdAH.c: + * generic/tclFCmd.c: Call TclStat instead of TclpStat in order to + allow Tcl_Stat hooks to work properly. + +1999-06-29 Jennifer Hom + + * library/tcltest1.0/pkgIndex.tcl: + * library/tcltest1.0/tcltest.tcl: + * doc/tcltest.n: + * tests/all.tcl: Added -preservecore, -limitconstraints, -help, + -file, -notfile, -relateddir and -asidefromdir flags to the + tcltest package along with exported proc + ::tcltest::getMatchingFiles. The documentation was modified to + match and all.tcl was modified to use the new functionality + instead of implementing -file itself. + +1999-06-28 + + * generic/tclIndexObj.c: + * doc/GetIndex.3: + * tests/binary.test: + * tests/winDde.test: Applied patch from Peter Hardie (with + changes) to fix problem with Tcl_GetIndexFromObj() when the key + being passed is the empty string. It used to match "" and return + TCL_OK, but it should have returned TCL_ERROR instead. Added test + case to "binary" and "dde" commands to check the behavior. Added + documentation note as well. + +1999-06-26 + + * win/tclWinDde.c: Applied patch from Peter Hardie to add poke + command to dde. Also rev'd version of dde package to 1.1. + [Bug: 1738] + +1999-06-25 Jennifer Hom + + * unix/Makefile.in: + * win/Makefile.in: + * library/tcltest1.0/pkgIndex.tcl: + * library/tcltest1.0/tcltest.tcl: + * library/tcltest1.0: Added initial implementation of the Tcl test + harness package. This package was based on the defs.tcl file that + was part of the tests directory. Reversed the way that tests were + evaluated to fix a problem with false passes. + + * doc/tcltest.n: Added documentation for the tcltest package. + + * tests/README: + * tests/defs.tcl: + * tests/all.tcl: Modified all test files (tests/*.test) and + all.tcl to use the new tcltest package and removed references to + the defs.tcl file. Modified the README file to point to the man + page for tcltest. + +1999-06-25 + + * tests/reg.test: + * generic/regexec.c: Fixed bugs in non-greedy quantifiers. + +1999-06-23 + + * doc/re_syntax.n: + * doc/switch.n: + * doc/lsearch.n: + * doc/RegExp.3: + * doc/regexp.n: + * doc/regsub.n: Moved information about syntax of 8.1 regular + expressions from regexp(n) manpage into new re_syntax(n) page. + Added pointers from other manpages to new re_syntax(n) page. + +1999-06-23 + + * unix/Makefile.in: Changed install-doc to install-man. + + * tools/uniParse.tcl: + * tools/uniClass.tcl: + * tools/README: + * tests/string.test: + * generic/regc_locale.c: + * generic/tclUniData.c: + * generic/tclUtf.c: + * doc/string.n: Updated Unicode character tables to reflect latest + Unicode 2.1 data. Also rationalized "regexp" and "string is" + definitions of character classes. + +1999-06-21 + + * unix/tclUnixThrd.c (TclpThreadCreate): Fixed memory leak where + thread attributes were not being released. [Bug: 2254] + +1999-06-17 + + * tests/regexp.test: + * generic/tclCmdMZ.c: + * generic/tclCmdIL.c: Changed to use new regexp interfaces. Added + -expanded, -line, -linestop, and -lineanchor switches to regsub. + + * doc/RegExp.3: Documented the new regexp interfaces and + the compile/execute flags. + + * generic/tclTest.c: + * generic/tclRegexp.h: + * generic/tclRegexp.c: + * generic/tcl.h: + * generic/tcl.decls: Renamed Tcl_RegExpMatchObj to + Tcl_RegExpExecObj and added a new Tcl_RegExpMatchObj that is + equivalent to Tcl_RegExpMatch. Added public macros for the regexp + compile/execute flags. Changed to store either an object pointer + or a string pointer in the TclRegexp structure. Changed to avoid + adding a reference to the object or copying the string. + + * generic/regcomp.c: lint + + * tests/reg.test: + * generic/regex.h: + * generic/regc_lex.c: Added REG_BOSONLY flag to allow Expect to + iterate through a string an only find matches that start at the + current position within the string. + +1999-06-16 + + * unix/configure.in: + * unix/Makefile.in: + * unix/tcl.m4: + * unix/aclocal.m4: Numerous build changes to make Tcl conform to the + proposed TEA spec + +1999-06-16 Melissa Hirschl + + * generic/tclVar.c (Tcl_VariableObjCmd): fixed premature increment + in loop that was causing out-of-bounds reads on array "varName". + +1999-06-16 + + * tests/execute.test: + * generic/tclExecute.c (TclExecuteByteCode): Fixed crash caused by + a bug in INST_LOAD_SCALAR1 where the scalar index was read as + a signed 1 byte value instead of unsigned. [Bug: 2243] + +1999-06-14 Melissa Hirschl + + * doc/StringObj.3 + * test/stringObj.test + * unix/Makefile.in + * win/Makefile.in + * win/makefile.vc + * generic/tclStringObj.c: + Merged String and Unicode object types. Added new functions to + the puplic API: Tcl_NewUnicodeObj, Tcl_SetUnicodeObj, + Tcl_GetUnicode, Tcl_GetUniChar, Tcl_GetCharLength, Tcl_GetRange, + Tcl_AppendUnicodeToObj. + +1999-06-09 + + * generic/tclUnicodeObj.c: Lots of cleanup and simplification. + Fixed several memory bugs. Added TclAppendUnicodeToObj. + + * generic/tclInt.h: Added declarations for various Unicode string + functions. + + * generic/tclRegexp.c: + * generic/tclCmdMZ.c: Changed to use new Unicode string interfaces + for better performance. + + * generic/tclRegexp.h: + * generic/tclRegexp.c: + * generic/tcl.h: + * generic/tcl.decls: Added Tcl_RegExpMatchObj and + Tcl_RegExpGetInfo calls to access lower level regexp API. These + features are needed by Expect. This is a preliminary + implementation pending final review and cleanup. + + * generic/tclCmdMZ.c: + * tests/string.test: Fixed bug where string map failed on null + strings. + + * generic/regexec.c: + * unix/tclUnixNotfy.c: lint + + * tools/genStubs.tcl: Changed to always write output in LF mode. + +1999-06-08 + + * win/tclWinSock.c: Rolled back to the 8.1.0 implementation + because of serious problems with the new driver. Basically no + incoming socket connections would be reported to a server port. + The 8.1.1 code needs to be redesigned and fixed correctly. + +1999-06-07 Melissa Hirschl + + * tests/string.test: + * generic/tclVar.c (Tcl_SetVar2Ex): + * generic/tclStringObj.c (Tcl_AppendObjToObj): + * generic/tclCmdMZ.c (Tcl_StringObjCmd): optimized the string + index, string length, string range, and append command in cases + where the object's internal rep is a bytearray. Objects with + other internal reps are converted to have the new unicode internal + rep. + + * unix/Makefile.in: + * win/Makefile.in: + * win/Makefile.vc: + * tests/unicode.test: + * generic/tclInt.h: + * generic/tclObj.c: + * generic/tclUnicodeObj.c: added a new object type to store the + unicode representation of a string. + + * generic/tclTestObj.c: added the objtype option to the testobj + command. This option returns the name of the type of internal rep + an object has. + +1999-06-04 + + * win/configure.in: + * win/Makefile.in: Windows build now handles static/dynamic + debug/nodebug builds and supports the standard targets using + Cygwin user tools plus GNU make and autoconf. + +1999-06-03 + + * generic/tclCmdMZ.c (Tcl_StringObjCmd): + * tests/string.test: Fixed bug where string equal/compare -nocase + reported wrong result on null strings. [Bug: 2138] + +1999-06-02 + + * generic/tclUtf.c (Tcl_UtfNcasecmp): Fixed incorrect computation + of relative ordering. [Bug: 2135] + +1999-06-01 + + * unix/configure.in: Fixed various small configure.in patches + submitted by Jan Nijtmans. [Bug: 2121] + + * tests/reg.test: + * generic/regc_color.c: + * generic/regc_cvec.c: + * generic/regc_lex.c: + * generic/regc_locale.c: + * generic/regc_nfa.c: + * generic/regcomp.c: + * generic/regcustom.h: + * generic/rege_dfa.c: + * generic/regerror.c: + * generic/regerrs.h: + * generic/regex.h: + * generic/regexec.c: + * generic/regfree.c: + * generic/regfronts.c: + * generic/regguts.h: + * generic/tclCmdMZ.c: + * generic/tclRegexp.c: + * generic/tclRegexp.h: + * generic/tclTest.c: Applied Henry Spencer's latest regexp patches + that fix an infinite loop bug and add support for testing whether + a string could match with additional input. [Bug: 2117] + +1999-05-28 + + * generic/tclObj.c: Changed to eliminate use of isupper/tolower in + favor of the Unicode versions. + + * win/Makefile.in: + * win/configure.in: Added preliminary TEA implementation. + + * win/tclWinDde.c: Fixed bug where dde calls were being passed an + invalid dde handle because Initialize had not been called. + [Bug: 2124] + +1999-05-26 + + * generic/tclThreadTest.c: Fixed race condition in testthread + code that showed up in the WinNT test suite intermittently. + + * win/tclWinSock.c: Fixed a hang in the WinNT socket driver, wake + up the socket thread every 100ms to check for events on the + sockets that did not wake up the thread (race condition). + +1999-05-24 + + * tools/genStubs.tcl: Changed to allow a list of platforms instead + of just one at a time. + + * generic/tcl.decls: + * generic/tclCmdMZ.c: + * generic/tclDecls.h: + * generic/tclInt.decls: + * generic/tclIntDecls.h: + * generic/tclPort.h: + * generic/tclStubInit.c: + * generic/tclStubLib.c: Various header file related changes and other + lint to try to get the Mac builds working. + +1999-05-21 + + * win/tclWinPipe.c: Fix bug when launching command.com on + Win95/98. Need to wait for the procInfo.hProcess of the process that + was created, not the hProcess of the current process. [Bug: 2105] + +1999-05-20 + + * library/init.tcl: Add the directory where the executable is, and + the ../lib directory relative to that, to the auto_path variable. + +1999-05-19 + + Merged in various changes submitted by Jeff Hobbs: + + * generic/tcl.decls: + * generic/tclUtf.c: Added Tcl_UniCharIs* functions for control, + graph, print, and punct classes. + + * generic/tclUtil.c: + * doc/StrMatch.3: Added Tcl_StringCaseMatch() implementation to + support case-insensitive globbing. + + * doc/string.n: + * unix/mkLinks: + * tests/string.test: + * generic/tclCmdMZ.c: Added additional character class tests, + added -nocase switch to "string match", changed string first/last + to use offsets. + +1999-05-19 + + * generic/tcl.h: Add extern "C" block around entire header file for + C++ compilers to fix linkage issues. Submitted by Don Porter and + Paul Duffin. + + * generic/tclRegexp.c: Fix bug when the regexp cache is empty + and an empty pattern is used in regexp ( such as {} or "" ). + +1999-05-18 + + * win/tclWinChan.c: Modified initialization code to avoid + inherenting closed or invalid channels. If the standard input is + anything other than a console, file, serial port, or pipe, then we + fall back to the standard Tk window console. + +1999-05-14 + + * generic/tclCmdAH.c (Tcl_ForObjCmd): Fixed crash caused by + failure to reset the result before evaluating the test + expression. + +1999-05-14 + + * generic/tclBasic.c (Tcl_CreateInterp): Added introspection + variable for threaded interps. If the interp was compiled with + threads enabled, the tcl_platform(threaded) variable will exist. + +1999-05-14 + + * generic/tclDate.c: Applied patch to fix 100-year and 400-year + boundaries in leap year code, from Isaac Hollander. [Bug: 2066] + +1999-05-13 + + * unix/Makefile.in: + * unix/tclAppInit.c: Minor cleanup related to Xt notifier. + + * unix/tclUnixInit.c (TclpSetInitialEncodings): Tcl now looks for + an encoding subfield in the LANG/LC_ALL variables in cases where + the locale is not found in the locale table. Ensure that + setlocale() is called at least once so X11 will initialize + properly. Also, forces the LC_NUMERIC locale to be "C" so numeric + processing in scripts is not affected by the current locale + setting. [Bug: 1989] + + * generic/tclRegexp.c: Increased per-thread regexp cache to 30 + slots. This seems to be about the right number for larger + applications like exmh. [Bug: 1063] + +1999-05-12 + + * doc/tclsh.1: Updated references to rc script names to accurately + reflect the platform differences on Windows. + + * tests/regexp.test: + * generic/tclInt.h: + * generic/tclBasic.c: + * generic/tclRegexp.h: + * generic/tclRegexp.c: Replaced the per-interpreter regexp cache + with a per-thread cache. Changed the Regexp object to take + advantage of this extra cache. Added a reference count to the + TclRegexp type so regexps can be shared by multiple objects. + Removed the per-interp regexp cache from the interpreter. Now + regexps can be used with no need for an interpreter. [Bug: 1063] + + * win/tclWinInit.c (TclpSetVariables): Avoid calling GetUserName + if the value can be determined from the USERNAME environment + variable. GetUserName is very slow. + +1999-05-07 + + * win/winDumpExts.c: + * win/makefile.vc: Removed incorrect patch. [Bug: 1998] + + * generic/tcl.decls: Replaced const with CONST. + + * generic/tclResult.c (Tcl_AppendResultVA): + * generic/tclStringObj.c (Tcl_AppendStringsToObjVA): Fixed to copy + arglist using memcpy instead of assignment so it works properly on + OS/390. [Bug: 1997] + + * generic/tclLoadNone.c: Updated to use current interfaces, added + TclpUnloadFile. [Bug: 2003] + + * win/winDumpExts.c: + * win/makefile.vc: Changed to emit library name in defs + file. [Bug: 1998] + + * unix/configure.in: Added fix for OS/390. [Bug: 1976] + +1999-05-06 + + * tests/string.test: + * generic/tclCmdMZ.c: + * doc/string.n: Fixed bug in string equal/compare code when using + -length option. Cleaned up docs a bit more. + + * tests/http.test: Unset "data" array before running tests to + avoid failures due to previous tests. + + * doc/string.n: + * tests/cmdIL.test: + * tests/cmdMZ.test: + * tests/error.test: + * tests/ioCmd.test: + * tests/lindex.test: + * tests/linsert.test: + * tests/lrange.test: + * tests/lreplace.test: + * tests/string.test: + * tests/cmdIL.test: + * generic/tclUtil.c: + * generic/tclCmdMZ.c: Replaced "string icompare/iequal" with + -nocase and -length switches to "string compare/equal". Added a + -nocase option to "string map". Changed index syntax to allow + integer or end?-integer? instead of a full expression. This is + much simpler with safeTcl scripts since it avoids double + substitution issues. + + * doc/Utf.3: + * generic/tclStubInit.c: + * generic/tclDecls.h: + * generic/tclUtf.c: + * generic/tcl.decls: Added Tcl_UtfNcmp and Tcl_UtfNcasecmp. + +1999-05-05 + + * win/makefile.vc: Added encoding directory to install-libraries + target. + +1999-05-03 + + * doc/string.n: + * tests/cmdMZ.test: + * tests/string.test: + * generic/tclCmdMZ.c (Tcl_StringObjCmd): Changed "string length" + to avoid regenerating the string rep of a ByteArray object. + + * tests/cmdIL.test: + * tests/cmdMZ.test: + * tests/error.test: + * tests/lindex.test: + * tests/linsert.test: + * tests/lrange.test: + * tests/lreplace.test: + * tests/string.test: + * generic/tclCmdMZ.c (Tcl_StringObjCmd): + * generic/tclUtil.c (TclGetIntForIndex): Applied Jeff Hobbs's + string patch which includes the following changes [Bug: 1845]: + + - string compare now takes optional length arg (for strncmp + behavior) + + - added string equal (just a few lines of code blended + in with string compare) + + - added string icompare/iequal for case-insensitive comparisons + + - string index's index can now be ?end[+-]?expression + I made this change in the private TclGetIntForIndex, + which means that the list commands also benefit, as + well as string range, et al. + + - added [string repeat string count] + Repeats given string number of times + + - added string replace, string equiv to lreplace + (quasi opposite of string range): + string replace first last ?string? + Example of use, replacing end of string with ... + should the string be more than 16 chars long: + string replace $string 16 end "..." + This just returns the string len < 16, so it + will only affect the long strings. + + - added optional first and last args to string to* + This allows you to just affect certain regions of + a string with the command (like just capping the + first letter). I found the original totitle to + be too draconian to be useful. + + - added [string map charMap string] + where charMap is a {from to from to} list that equates to + what one might get from [array get]. Each and + can be multiple chars (or none at all). For Tcl/CGI users, + this is a MAJOR speed booster. + + * generic/tclParse.c (Tcl_ParseCommand): Changed to avoid + modifying eval'ed strings that are already null terminated. + [Bug: 1793] + + * tests/binary.test: + * generic/tclBinary.c (DupByteArrayInternalRep): Fixed bug where + type was not being set in duplicated object. [Bug: 1975, 2047] + +1999-04-30 + + * Changed version to 8.1.1. + +1999-04-30 + + * Merged changes from 8.1.0 branch: + + * generic/tclParse.c: Fixed memory leak in CommandComplete. + + * generic/tclPlatDecls.h: + * generic/tclIntPlatDecls.h: + * generic/tclIntDecls.h: + * generic/tclDecls.h: + * tools/genStubs.tcl: Added 'extern "C" {}' block around the stub + table pointer declaration so the stub library can be used from + C++. [Bug: 1934] + + * Lots of documentation and other release engineering fixes. + +1999-04-28 + + * mac/tclMacResource.c: + * generic/tclListObj.c: + * generic/tclObj.c: + * generic/tclStringObj.c: Changed to avoid freeing the string + representation before freeing the internal rep. This helps with + debugging since the string rep will still be valid when the free + proc is invoked. + +1999-04-27 + + * generic/tclLiteral.c (TclHideLiteral): Fixed so hidden literals + get duplicated to avoid accidental sharing in the global object + table. + +1999-04-23 + + * generic/tclStubInit.c: + * tools/genStubs.tcl: Changed to avoid the need for forward + declarations in stub initializers. + +1999-04-23 + + * library/encoding/koi8-r.enc: + * tools/encoding/koi8-r.txt: Added support for the koi8-r Cyrillic + encoding. [Bug: 1771] + +1999-04-22 + + * win/tclWinFCmd.c: + * win/tclWin32Dll.c: Changed uses of "try" to "__try", since that + is the actual keyword. This eliminates the need for some -D flags + from the makefile. + + * generic/tclPort.h: Added include of tcl.h since it defines + various Windows macros that are needed before deciding which + platform porting file to use. + + * generic/tclEvent.c: lint + + * win/tclWinInit.c (TclpInitPlatform): Added call to TclWinInit + when building a static library since DllMain will not be invoked. + This could break old code that explicitly called TclWinInit, but + should be simpler in the long run. + +1999-04-22 Scott Stanton + + * generic/tclInt.h: + * generic/tclInt.decls: + * generic/tclCompile.c: Added TclSetByteCodeFromAny that takes a + hook procedure to invoke after compilation but before the byte + codes are emitted. This makes it possible to do postprocessing on + the compiled byte codes before the ByteCode is generated. + + * generic/tclLiteral.c: Added TclHideLiteral and TclAddLiteralObj + to make it possible to create local unshared literal objects. + + * win/tclWinInit.c: + * unix/tclUnixInit.c: Changed initial search path to match that + found used by tcl_findLibrary. + +1999-04-22 + + * win/tclWinPort.h: + * win/tclWinSock.c: Added code to use WinSock 2.0 API on NT to + avoid creating a window to handle sockets. API not available on + Win95 and needs to be fixed on Win98, until then continue to use + the older (window-based) scheme on those two OSes. + +1999-04-15 + + * Merged 8.1 back into the main trunk + +1999-04-13 + + * library/encoding/gb2312.enc: + * library/encoding/euc-cn.enc: + * tools/encoding/gb2312.txt: + * tools/encoding/cp950.txt: + * tools/encoding/Makefile: Restored the double byte definition of + GB2312 and added the EUC-CN encoding. EUC-CN is a variant of + GB2312 that shifts the characters into bytes with the high bit set + and includes ASCII as a subset. [Bug: 632] + +1999-04-13 + + * win/tclWinSock.c: Apply patch to allow write access to a socket + if FD_WRITE is sent but FD_CONNECT is not. Some strange problem + with either Win32 or a socket driver. [Bug: 1664 1776] + +1999-04-09 + + * unix/tclUnixNotfy.c: Fixed notifier deadlock situation when the + pipe used to talk back notifier thread is filled with data. When + calling the write() function to feed data down that pipe, unlock + the notifierMutex to allow the notifier to wake up again. Found + as a result of the focus.test for Tk hanging. [Bug: 1700] + +1999-04-06 + + * tests/unixNotfy.test: Fixed hang in tests when built with thread + support. + + * tests/httpold.test: Fixed broken test that didn't wait long + enough for events to arrive. + + * tests/unixInit.test: Fixed race condition in test. + + * tests/unixInit.test: + * tests/fileName.test: Minor test nits. + + * unix/tclUnixInit.c (TclpSetInitialEncodings): Fixed bad initial + encoding string. + +1999-04-06 + + * generic/tclVar.c: + * generic/tclEnv.c: Moved the "array set" C level code into a + common routine (TclArraySet). The TclSetupEnv routine now uses + this API to create an env array w/ no elements. + + * generic/tclEnv.c: + * generic/tclWinInit.h: + * generic/tclUnixInit.h: + * generic/tclInt.h: Made the Env module I18N compliant. Changed the + FindVariable routine to TclpFindVariable, that now does a case + insensitive string comparison on Windows, and not on UNIX. [Bug: + 1299, 1500] + +1999-04-05 + + * tests/io.test: Minor test cleanup. + + * generic/tclEncoding.c (Tcl_CreateEncoding): Minor lint to make + it easier to compile on Digital-unix. [Bug: 1659] + + * unix/configure.in: + * unix/tclUnixPort.h: Applied patch for OS/390 to handle lack of + sys/param.h. [Bug: 1725] + + * unix/configure.in: Fixed BSD/OS 4.* configuration to support + shared libraries properly. [Bug: 1730] + +1999-04-05 + + * win/tclWinDde.c: decrease timeout value for DDE calls to 30k + [Bug: 1639] + + * generic/tcl.decls: + * generic/tcl.h: + * generic/tclDecls.h: + * generic/tclInt.decls: + * generic/tclInt.h: + * generic/tclIntDecls.h: + * generic/tclStubInit.c: + * generic/tclUtil.c: Added more functions to the Tcl stubs table, + including all Tcl_ functions not already in it (except Cmd + functions) and Tcl_GetCwd() and Tcl_Chdir() (new functions). + + * tests/safe.test: + * doc/safe.n: + * generic/tclBasic.c: + * library/safe.tcl: The encoding command is not safe as-is, so + create a safe alias to mask out the "encoding system " but + allow all other uses including "encoding system". Added test cases + and updated the man page for Safe Tcl. + +1999-04-05 + + * tests/winTime.test: + * win/tclWinTime.c: Fixed crash in clock command that occurred + when manipulating negative time values in timezones east of + GMT. [Bug: 1142, 1458] + + * tests/platform.test: + * tests/fileName.test: Fixed broken tests. + + * generic/tclFileName.c: Moved global regexps into thread local + storage. + + * tests/socket.test: Changed so tests don't reuse sockets, + since Windows is slow to release sockets. + + * win/tclWinConsole.c: + * win/tclWinPipe.c: + * win/tclWinSerial.c: Fixed race condition where background + threads were terminated while they still held a lock in the + notifier. + +1999-04-02 + + * tests/http.test: Fixed bad test initialization code. + + * generic/tclThreadTest.c (ThreadExitProc): Fixed bug where static + memory was being returned instead of a dynamically allocated + result in error cases. + +1999-04-02 + + * doc/dde.n: + * tools/tcl.wse.in: + * win/makefile.vc: + * win/pkgIndex.tcl: + * win/tclWinDde.c: Add new DDE package, code removed from Tk now + separated into its own package. Changed DDE-based send code into + "dde eval" command. Can be loaded into tclsh (not just wish). + Windows only. + +1999-04-02 + + * tests/expr.test: + * tests/for-old.test: + * tests/for.test: + * tests/foreach.test: + * tests/format.test: + * tests/httpold.test: + * tests/if.test: + * tests/init.test: + * tests/interp.test: + * tests/while.test: Added some tests for known bugs (marked with + knownBug constraint), and cleaned up a few bad tests. + + * generic/regc_locale.c: + * generic/regcustom.h: + * generic/tcl.decls: + * generic/tclCmdIL.c: + * generic/tclCmdMZ.c: + * generic/tclInt.h: + * generic/tclRegexp.c: + * generic/tclScan.c: + * generic/tclTest.c: + * generic/tclUtf.c: + * win/tclWinFCmd.c: + * win/tclWinFile.c: Made various Unicode utility functions + public. The following functions were made public and added to the + stubs table: + Tcl_UtfToUniCharDString, Tcl_UniCharToUtfDString, + Tcl_UniCharLen, Tcl_UniCharNcmp, Tcl_UniCharIsAlnum, + Tcl_UniCharIsAlpha, Tcl_UniCharIsDigit, Tcl_UniCharIsLower, + Tcl_UniCharIsSpace, Tcl_UniCharIsUpper, Tcl_UniCharIsWordChar + +1999-04-01 + + * tests/registry.test: + * win/tclWinReg.c: Internationalized the registry code. It now + uses Unicode interfaces on NT. [Bug: 1197] + + * tests/parse.test: + * generic/tclParse.c: Fixed crash due to multiple frees in parser + during error cleanup when parsing commands with more tokens than + will fit in the static area of the parse structure. [Bug: 1681] + + * generic/tclInt.h: Removed duplicate declarations. + + * generic/tclInt.decls: + * generic/tcl.decls: Added Tcl_WinUtfToTChar and Tcl_WinTCharToUtf + to the tclPlat table. + +1999-04-01 + + * generic/tcl.decls: + * generic/tcl.h: + * generic/tclBasic.c: + * generic/tclDecls.h: + * generic/StubInit.c: + * tools/genStubs.tcl: + * unix/Makefile.in: + * win/makefile.vc: Applied patch from Jan Nijtmans to fix Ultrix + multiple symbol definition problem. Now, even Tcl includes a copy + of the Tcl stub library. Also fixed TCL_MEM_DEBUG mode (for Tk). + +1999-03-31 + + * win/tclWinConsole.c: WinNT has a bug when reading a single + character from the console. Rewrote the code for the console to + read an entire line at a time using the reader thread. + +1999-03-30 + + * unix/Makefile.in: Removed trailing backslash that broke the + "depend" target. + + * unix/tclUnixInit.c (TclpSetInitialEncodings): Changed to avoid + calling setlocale(). We now look directly at env(LANG) and + env(LC_CTYPE) instead. [Bug: 1636] + + * generic/tclFileName.c: + * generic/tclDecls.h: + * generic/tcl.decls: Removed CONST from Tcl_JoinPath and + Tcl_TranslateFileName because it changes the signature of + Tcl_JoinPath in an incompatible manner. + + * generic/tclInt.h: + * generic/tclLoad.c (TclFinalizeLoad): + * generic/tclEvent.c (Tcl_Finalize): Defer unloading of loadable + modules until all exit handlers have been invoked. + [Bug: 998, 1273, 1573, 1593] + +1999-03-29 + + * generic/tclFileName.c: + * generic/tclDecls.h: + * generic/tcl.decls: Added CONST to Tcl_JoinPath and + Tcl_TranslateFileName. + +1999-03-29 + + * tools/genStubs.tcl: + * unix/configure.in: + * unix/Makefile.in: + * win/makefile.vc: + * generic/tcl.h: + * generic/tclBasic.c: + * generic/tclDecls.h: + * generic/tclIntDecls.h: + * generic/tclPlatDecls.h: + * generic/tclIntPlatDecls.h: Removed the stub functions and + changed the stub macros to just use the name without params. Pass + &tclStubs into the interp (don't use tclStubsPtr because of + collisions with the stubs on Solaris). + +1999-03-27 + + * win/makefile.bc: Removed makefile for Borland compiler, no + longer supported. + +1999-03-26 + + * win/tclWinSerial.c: + * win/tclWinConsole.c: + * win/tclWinPipe.c: Don't close the Win32 handle for a channel if + it's a stdio handle (GetStdHandle()) during shutdown of a thread + to prevent it from destroying the stdio of other threads. + +1999-03-26 + + * unix/configure.in + --nameble-shared is now the default and build Tcl as a shared + library; specify --disable-shared to build a static Tcl library + and shell. + +1999-03-25 + + * tests/interp.test: + * generic/tclInterp.c (AliasObjCmd): Changed so aliases are + invoked at current scope in the target interpreter instead of at + the global scope. This was an incompatibility introduced in 8.1 + that is being removed. [Bug: 1153, 1556] + + * library/encoding/big5.enc: + * library/encoding/gb2312.enc: + * tools/encoding/big5.enc: + * tools/encoding/gb2312.enc: Added ASCII to big5 and gb2312 + encodings. [Bug: 632] + + * generic/tclPkg.c (Tcl_PkgRequireEx): Fixed broken clientData + initialization in package code. + + * unix/Makefile.in (dist): Added tcl.decls and tclInt.decls to + source distribution. [Bug: 1571] + + * doc/Thread.3: Updated documentation of Tcl_MutexLock to indicate + that the recursive locking behavior is undefined. On Windows, it + does not block, on Unix it deadlocks. [Bug: 1275] + +1999-03-24 + + * tests/execute.test: + * generic/tclExecute.c (TclExecuteByteCode): Fixed expression code + that incorrectly returned floating point values for integers if + the internal rep happened to be a double. Now we check to see if + the object has a string rep that looks like an integer before + using the double internal rep. [Bug: 1516] + +1999-03-24 + + * generic/tclAlloc.c: + * generic/tclEncoding.c: + * generic/tclProc.c: + * unix/tclUnixTime.c: + * win/tclWinSerial.c: Fixed compilation warnings/errors for VC++ + 5.0 and 6.0 and HP-UX native compiler without -Aa or -Ae. + [Bug: 1323 1518 1324 1583 1585 1586] + + * win/tclWinSock.c: Make sockets thread-safe on Windows. The + current implementation uses windows to handle events on the + socket, one for each thread (thread local storage). Previously, + there was only one window shared between threads, which didn't + work. [Bug: 1326] + +1999-03-23 + + * tools/tcl.wse: Fixed file association to look in the right place + for the wish icon. [Bug: 1544] + + * tests/winNotify.test: + * tests/ioCmd.test: + * tests/event.test: Changed to use new style conditionals. + + * tests/encoding.test: Fixed nonportable test. + + * unix/dltest/configure.in: + * unix/dltest/Makefile.in: Added missing DBGX macros. [Bug: 1564] + + * tests/winNotify.test: + * mac/tclMacNotify.c: + * win/tclWinNotify.c: + * unix/tclUnixNotfy.c: + * generic/tclNotify.c: Added a new Tcl_ServiceModeHook interface + that is invoked whenever the service mode changes. This is needed + to allow the Windows notifier to create a communication window the + first time Tcl is about to enter an external modal event loop + instead of at startup time. This will avoid the various problems + that people have been seeing where the system hangs when tclsh + is running outside of the event loop. [Bug: 783] + + * generic/tclInt.h: + * generic/tcl.decls: Renamed TclpAlertNotifier back to + Tcl_AlertNotifier since it is part of the public notifier driver + API. + +1999-03-23 + + * win/tclWinSerial.c: Fixed problem with fileevent on the serial + port and nonblocking mode. Gets no longer hangs, fileevents fire + whenever there is any character data on the port. + + * tests/winConsole.test: + * win/tclWinConsole.c: Fixed problem with fileevents and gets from + a console stdin. Previously, fileevents were firing before an + entire line was available for reading, which meant that when you + did a gets or read, it blocked (even in nonblocking mode). Now, it + should work the same as Unix: fileevents fire when an entire line + is ready, and gets and read do not block in non-blocking mode. + Added an interactive test case to check for this. + +1999-03-22 + + * tests/reg.test: + * generic/regc_color.c: Applied regexp bug fix from Henry Spencer. + +1999-03-19 + + * generic/tclCmdIL.c: Fixed the initialization of an array so that + the Sun 5.0 C compiler wouldn't complain. + + * unix/configure.in: Added support for --enable-64bit. For now, + this is only supported on Solaris 7 64bit (SunOS 5.7) using the Sun + compiler (not gcc). + +1999-03-18 + + * win/tclWinChan.c (TclpOpenFileChannel, Tcl_MakeFileChannel): + Changed to only test for console or comm handles when the type is + FILE_TYPE_CHAR to avoid useless tests on simple files. Also + reordered tests so consoles are tested first as this is more + common. + + * win/makefile.vc: Regularized usage of mkd and rmd and rm. + + * library/encoding/shiftjis.enc: + * tools/encoding/shiftjis.txt: Missing/incorrect characters in + shift-jis table. [Bug: 1008, 1526] + + * generic/tclInt.decls: + * generic/tcl.decls: Eliminated use of "string" and "list" from + argument lists to avoid conflicts with C++ STL. [Bug: 1181] + + * win/tclWinFile.c (TclpMatchFiles): Changed to ignore the + FS_CASE_IS_PRESERVED bit and always return exactly what we get + from the system. + +1999-03-17 + + * win/README.binary: + * win/README: + * unix/configure.in: + * generic/tcl.h: + * README: Updated version to 8.1b3. + +1999-03-14 + + * win/tclWinConsole.c: + * win/tclWinPipe.c: + * win/tclWinSerial.c: Changed so channel drivers wait for the + reader/writer threads to exit before returning during a close + operation. This ensures that the main thread is the last thread + to exit, so the process return value is set properly. + + * generic/tclIntDecls.h: + * generic/tclIntPlatDecls.h: + * generic/tclIntPlatStubs.c: + * generic/tclIntStubs.c: + * generic/tclPlatDecls.h: + * generic/tclPlatStubs.c: + * generic/tclStubInit.c: + * generic/tclStubs.c: Fixed bad eol characters. + + * generic/tclInt.decls: Changed "const" to "CONST" in + declarations for better portability. + + * generic/tcl.decls: Renamed panic and panicVA to Tcl_Panic and + Tcl_PanicVA in the stub files. + + * generic/tclInterp.c (Tcl_MakeSafe): Remove tcl_platform(user) + from safe interps. + +1999-03-11 + + * unix/Makefile.in: + * unix/configure.in: Include compat files in the stub library in + addition to the main library. Compat files are now built for + dynamic use in all cases. + + * generic/tcl.h: Changed magic number so it doesn't match the plus + patch, at Jan's request. + + * unix/tclConfig.sh.in: + * unix/dltest/Makefile.in: + * unix/dltest/configure.in: + * unix/dltest/pkga.c: + * unix/dltest/pkgb.c: + * unix/dltest/pkgc.c: + * unix/dltest/pkgd.c: + * unix/dltest/pkge.c: + * unix/dltest/pkgf.c: Changed package tests to build against the + stubs library. + +1999-03-10 + + * generic/tcl.h: + * generic/tcl.decls: Changed Tcl_ReleaseType from an enum to + macros so it can be used in .rc files. + Added Tcl_GetString. + + * mac/tclMacNotify.c: + * generic/tclNotify.c: + * generic/tclInt.h: + * win/tclWinNotify.c: + * generic/tcl.h: Renamed Tcl_AlertNotifier to TclpAlertNotifier. + + * generic/tclInt.decls: Added TclWinAddProcess to make it possible + for expect to use Tcl_WaitForPid(). This patch is from Gordon + Chaffee. + + * mac/tclMacPort.h: + * win/tclWinInit.c: + * unix/tclUnixPort.h: + * generic/tclAsync.c: Added TclpAsyncMark to fix bug in async + handling on Windows where async events don't wake up the event + loop. This patch comes from Gordon Chaffee. + + * generic/tcl.decls: Fixed declarations of reserved slots. + +1999-03-10 + + * generic/tclCompile.h: Ensure that the ByteCode struct is binary + compatible with the version in 8.0.6. + + * generic/tcl.h: + * generic/tclBasic.c: Add Tcl_GetVersion() function to the public + C API to allow programs to check the version number of the Tcl + library at runtime. Also added an enum to clarify the release + level (alpha, beta, final). + +1999-03-09 + + * Integrated changes from Tcl 8.0 including: + stubs mechanism + configure patches from Jan Nijtmans + rename of panic to Tcl_Panic + +1999-03-08 + + * win/tclWin32Dll.c: Removed Dll instance from thread-local + storage. + +1999-03-08 + + * generic/tcl.h: Moved Tcl_Mutex, etc. macros above the inclusion + of tclDecls.h to avoid macro conflicts. + + * generic/tclInt.h: + * generic/regc_color.c: + * generic/regcomp.c: + * generic/tclCmdIL.c: + * generic/tclCmdAH.c: + * generic/tclIOCmd.c: + * generic/tclParse.c: + * generic/tclStringObj.c: + * unix/tclUnixNotfy.c: Cleaned up various compiler warnings, + eliminated UCHAR bugs. + + * unix/tclUnixNotfy.c: + * unix/tclUnixThrd.c: + * generic/tclThreadTest.c: + * mac/tclMacThrd.c: Changed TclpCondition*() to Tcl_Condition*(). + + * INTEGRATED PATCHES FROM 8.0.6: + + * generic/tcl.decls: + * generic/tcl.h: + * generic/tclBasic.c: + * generic/tclDecls.h: + * generic/tclInt.decls: + * generic/tclInt.h: + * generic/tclIntDecls.h: + * generic/tclIntPlatDecls.h: + * generic/tclIntPlatStubs.c: + * generic/tclIntStubs.c: + * generic/tclPlatDecls.h: + * generic/tclPlatStubs.c: + * generic/tclStubInit.c: + * generic/tclStubLib.c: + * generic/tclStubs.c: + * tools/genStubs.tcl: + * unix/configure.in: + * unix/Makefile.in: + * unix/tclConfig.sh.in: + * win/makefile.vc: + * win/tclWinPort.h: Added Tcl stubs implementation. There are + now two new macros USE_TCL_STUBS and USE_TCL_STUB_PROCS that + enable use of stubs and disable stub macros respectively. All of + the public and private function declarations from tcl.h and + tclInt.h have moved into the *.decls files and the *Stubs.c and + *Decls.h files are generated using the genStubs.tcl script. + + * unix/Makefile.in: + * unix/configure.in: + * unix/ldAix: Enhanced AIX shared library support. + + * win/tclWinSock.c: Removed a bunch of extraneous PASCAL FAR + attributes from internal functions. + + * win/tclWinReg.c: Changed registry package to use stubs mechanism + so it no longer depends on the specific version of Tcl. + + * doc/AddErrInfo.3: + * doc/Eval.3: + * doc/PkgRequire.3: + * doc/SetResult.3: + * doc/StringObj.3: + * generic/tcl.h: + * generic/tclBasic.c: + * generic/tclPanic.c: + * generic/tclStringObj.c: + * generic/tclUtil.c: + * unix/mkLinks: Added va_list versions of all VARARGS + functions so they can be invoked from the stub functions. + + * doc/package.n: + * doc/PkgRequire.3: + * generic/tclPkg.c: Added Tcl_PkgProvideEx, Tcl_RequireEx, + Tcl_PresentEx, and Tcl_PkgPresent. Added "package present" + command. + + * generic/tclFileName.c: + * mac/tclMacFile.c: + * mac/tclMacShLib.exp: + * unix/tclUnixFile.c: + * win/tclWinFile.c: Changed so TclGetUserHome is defined on + all platforms, even though it is currently a noop on mac and + windows, and renamed it to TclpGetUserHome. + + * generic/tclPanic.c: + * generic/panic.c: Renamed panic to Tcl_Panic. + +1999-02-25 + + * win/makefile.vc: Added tclWinConsole.c and tclWinSerial.c + + * win/tclWinConsole.c: New code to properly deal with fileevents + and nonblocking mode on consoles. + + * win/tclWinSerial.c: New code to properly deal with fileevents + and nonblocking mode on serial ports. + + * win/tclWinPipe.c: + * win/tclWinPort.h: Exported functions to allow creation of pipe + channels from tclWinChan.c + + * win/tclWinChan.c: Check the type of a channel, including for the + standard (stdin/stdout/stderr), and use the correct channel type + to create the channel (file, serial, console, or pipe). + +1999-02-11 + + * README: + * generic/tcl.h: + * win/README.binary: + * win/README: + * unix/configure.in: + * mac/README: Updated version numbers to 8.1b2. + +1999-02-10 + + * library/auto.tcl: Fixed auto_mkindex so it handles .tbc files. + Did some general cleanup to handle bad eval statements that didn't + use "list". + + * unix/mkLinks: + * doc/SetVar.3: + * generic/tcl.h: + * generic/tclVar.c: Restored Tcl_ObjGetVar2 and Tcl_ObjSetVar2 + from 8.0. Renamed Tcl_Get/SetObjVar2 to Tcl_GetVar2Ex and + Tcl_SetVar2Ex. + +1999-02-10 + + INTEGRATED PATCHES FROM 8.0.5b2: + + * test/winPipe.test: Changed to remove echoArgs.tcl temporary file + when done. + + * tests/cmdAH.test: + * generic/tclFileName.c (TclGetExtension): Changed behavior so the + split happens at the last period in the name instead of the first + period of the last run of periods. So, "foo..o" is split into + "foo." and ".o" now. [Bug: 1126] + + * win/makefile.vc: Added better support for paths with spaces in + the name. Added .lib and support .dlls to the install-binaries + target. Added generate of a pkgIndex.tcl script to the + install-libraries target. + + * win/tclAppInit.c: + * unix/tclAppInit.c: + * mac/tclMacAppInit.c: + * generic/tclTest.c: Changed some EXTERN declarations to extern + since they are not defining exported interfaces. This avoids + generating useless declspec() attributes and makes the windows + makefile simpler. + + * generic/tcl.h: Moved Tcl_AppInit declaration to end and cleared + out TCL_STORAGE_CLASS so it is not declared with a declspec(). + + * tests/interp.test: + * generic/tclInterp.c (DeleteAlias): Changed to use + Tcl_DeleteCommandFromToken so we handle renames properly. This + avoids senseless panic. [Bug: 736] + + * unix/tclUnixChan.c: + * win/tclWinSock.c: + * doc/socket.n: Applied Gordon Chaffee's patch to handle failures + during asynchronous socket connection operations. This adds a new + "-error" fconfgure option to socket channels. [Bug: 893] + + * generic/tclProc.c: + * generic/tclNamesp.c: + * generic/tclInt.h: + * generic/tclCmdIL.c: + * generic/tclBasic.c: + * generic/tclVar.c: Applied patch from Viktor Dukhovni to + rationalize TCL_LEAVE_ERR_MSG behavior when creating variables. + + * generic/tclVar.c: Fixed bug in namespace tail computation. + Fixed bug where upvar could resurrect a namespace variable whose + namespace had been deleted. + + * generic/tclCompile.c (TclCompileExprCmd): Eliminated yet another + bogus optimization in expression compilation. + + * unix/configure.in: Added branch for BSD/OS-4* to shared library + case statement. [Bug: 975] + Fixed to correctly handle IRIX 6.5 n32 library support. [Bug: 1117] + + * win/winDumpExts.c: Patched to be pickier about stripping + @'s. [Bug: 920] + + * library/http2.0/http.tcl: Added catch around eof test in + CopyDone since the user may have already called http::reset. + [Bug: 1108] + + * unix/configure.in: Changed Linux and IRIX to set SHLIB_LIBS to + LIBS so shared libraries are linked with the system + libraries. [Bug: 1018] + + * generic/tclCompile.c (CompileExprWord): Fixed exception stack + overflow bug caused by missing statement. [Bug: 928] + + * generic/tclIOCmd.c: + * generic/tclBasic.c: Objectified the "open" command. [Bug: 1113] + + * generic/tclPosixStr.c (Tcl_ErrnoId, Tcl_ErrnoMsg): When using + egcs, ENOTSUP and EOPNOTSUPP are the same, so now we handle that + case. [Bug: 1137] + + * library/init.tcl: Various small changes requested by Jan Nijtmans. + - If the variable $tcl_library contains the empty string, this + empty string will be put in $auto_path. This is not useful at all, + it only slows down later package processing. + - If the variable tcl_pkgPath is not set, the "unset __dir" + fails. Thich makes init.tcl totally unusable. Better put a "catch" + around it. + - In the function tcl_findLibraries, the "string match" function + only works correctly if $tcl_patchLevel is in one of the forms + "?.?a?", "?.?b?" or "?.?.?". Could a "regexp" be used instead, + then it allows anything to be appended to the patchLevel + string. And it is more efficient. + - The tclPkgSetup function assumes that if $type != "load" then + the type must be "source". This needn't be true. Some users want + to add their own setup types. + [RFE: 1138] [Bug: 978] + + * win/tclWinReg.c: + * doc/registry.n: Added support for HKEY_PERFORMANCE_DATA and + HKEY_DYN_DATA keys. [Bug: 1109] + + * win/tclWinInit.c (TclPlatformInit): Added code to ensure + tcl_pkgPath is set to "" when no registry entry is found. [Bug: 978] + +1999-02-01 + + * generic/tclBasic.c: + * generic/tclCmdAH.c: + * generic/tclCmdIL.c: + * generic/tclCmdMZ.c: + * generic/tclExecute.c: + * generic/tclHistory.c: + * generic/tclIO.c: + * generic/tclIOUtil.c: + * generic/tclInterp.c: + * generic/tclMain.c: + * generic/tclNamesp.c: + * generic/tclParse.c: + * generic/tclProc.c: + * generic/tclTest.c: + * generic/tclTimer.c: + * generic/tcl.h: Made eval interfaces compatible with 8.0 by + renaming Tcl_EvalObj to Tcl_EvalObjEx, renaming Tcl_Eval2 to + Tcl_EvalEx and restoring Tcl_EvalObj and Tcl_GlobalEvalObj + interfaces so they match Tcl 8.0. + +1999-01-28 + + * Merged Tcl 8.0.5b1 changes. + + * generic/tclUtil.c (Tcl_DStringSetLength): Changed so the buffer + overallocates in a manner similar to Tcl_DStringAppend. This + should improve performance for TclUniCharToUtfDString. + +1998-12-11 === Tcl 8.1b1 Release === + +1998-12-10 + + * Fixed lots of files that used TCL_THREAD instead of TCL_THREADS. + + * generic/tclEncoding.c (Tcl_FreeEncoding): Moved most of the code + into a static FreeEncoding routine that does not grab the + encodingMutex to avoid deadlocks/races when called from other + routines that already have the mutex. + +1998-12-09 + + * library/msgcat1.0/msgcat.tcl: Fixed bad export list, fixed so + all locale strings are converted to lower case, including file + names. + + * generic/regcomp.c (makescan): Fixed bug in longest match case + that caused anchored patterns to fail. [Bug: 897] + +1998-12-08 + + * library/msgcat1.0/msgcat.tcl: changed mc to invoke mcunknown in + the calling context, changed locale lookups to be case insensitive + +1998-12-07 + + * generic/tclAlloc.c (TclpRealloc): Fixed a memory allocation bug + where big blocks that were reallocated into a different heap + location were not being placed into the bigBlocks list. [Bug: 933] + + * tests/msgcat.test: Added message catalog test suite. + + * library/msgcat1.0/msgcat.tcl: minor bug fixes, integrated latest + changes from Mark Harrison. + +1998-12-04 + + * library/msgcat1.0/msgcat.tcl: Changed code to conform to Tcl + coding standards. Changed to use file join for portability. + + * library/msgcat1.0: Added initial implementaion of Tcl message + catalog package contributed by Mark Harrison. + +1998-12-03 + + * win/tclWinPipe.c (BuildCommandLine): Fixed bug that kept + arguments containing spaces from being properly quoted. + + * tests/defs: Changed so auto_path is set to only contain the Tcl + library directory. This keeps the tests from accidentally picking + up stuff in installed packages. + + * generic/tclUtil.c (Tcl_StringMatch): Changed to match 8.0 + behavior in corner case where there is no closing bracket. + +1998-12-02 + + * win/tclWinPipe.c (TclpCreateCommandChannel): Changed + reader/writer threads to have THREAD_PRIORITY_HIGHEST so they will + have a chance to run whenever there is something to do. + + * generic/tclIO.c (WriteBytes, WriteChars): Fixed so extraneous + flushes do not happen in line mode. + (TranslateOutputEOL): Made translation more efficient in line mode + and fixed a buffer overflow bug in CRLF translation. [Bug: 887] + +1998-12-02 + + * Updated patchlevel to 8.1b1 + +1998-12-02 + + * generic/regc_color.c (subcolor): Added check for error case to + avoid an out of bounds array reference. + + * generic/tclCmdAH.c (Tcl_EncodingObjCmd): Changed to avoid using + Tcl_DStringResult because it is not binary clean. + + * generic/tclParse.c (Tcl_ParseCommand): Fixed bug in comment + parsing where a trailing comment looked like an incomplete + command. + +1998-12-02 + + * Merged changes from 8.0.4, especially the new pkg_mkIndex + +1998-12-01 + + * generic/tclIO.c (Tcl_ReadChars): Added a call to UpdateInterest + so we don't block when there is data sitting in the buffers. + + * generic/tclTest.c (TestevalobjvObjCmd): Updated for EvalObjv + change. + + * tests/parse.test: Updated tests for EvalObjv change. + + * generic/tclParse.c (EvalObjv, Tcl_EvalObjv): Changed + Tcl_EvalObjv interface to remove string and length arguments, + preserved original interface as EvalObjv for internal use. + + * generic/tcl.h: Changed Tcl_EvalObjv interface to remove string + and length arguments. + + * doc/Eval.3: Updated documentation for Tcl_EvalObjv to remove + string and length arguments. + + * generic/tclCompCmds.c (TclCompileForeachCmd): Fixed code that + corrupted the exceptDepth value in the compile environment when + foreach failed to compile inline. [Bug: 884] + + * library/encoding/euc-kr.enc: + * library/encoding/ksc5601.enc: + * tools/encoding/ksc5601.txt: + * unix/tclUnixInit.c: Added support for Korean EUC. + + * win/tclWinChan.c (TclpGetDefaultStdChannel): added check for a + failure during Tcl_MakeFileChannel. + +1998-11-30 + + * unix/tclUnixNotfy.c (Tcl_WaitForEvent): Fixed hang that occurs + when trying to close a pipe that is currently being waited on by + the notifier thread. [Bug: 607] + + * unix/tclUnixFCmd.c (GetPermissionsAttribute): Increase size of + returnString buffer to avoid overflow. [Bug: 584] + + * generic/tclThreadTest.c (TclThreadSend): Fixed memory leak due + to use of TCL_VOLATILE instead of TCL_DYNAMIC. + + * generic/tclThread.c (TclRememberSyncObject): Fixed memory leak + caused by failure to reuse condition variables. + + * unix/tclUnixNotfy.c: (Tcl_AlertNotifier, Tcl_WaitForEvent, + NotifierThreadProc, Tcl_InitNotifier): Fixed race condition caused + by incorrect use of condition variables when sending messages + between threads.. [Bug: 607] + + * generic/tclTestObj.c (TeststringobjCmd): MAX_STRINGS was off by one + so the strings array was too small. + + * generic/tclCkalloc.c (Tcl_DbCkfree): Moved mutex lock so + ValidateMemory is done inside the mutex to avoid a race condition + when validate_memory is enabled. [Bug: 880] + +1998-11-23 + + * regexec.c: more performance tuning from Henry Spencer. + +1998-11-17 + + * tclScan.c: moved "scan" implementation out of tclCmdMZ.c and + added Unicode support. This required a complete reimplementation + of the command to avoid using scanf(), which isn't Unicode aware. + Two new features were added in the process: %n to return the + current number of characters consumed, and XPG3-style %n$ argument + order specifiers similar to those provided by the "format" + command. [Bug: 833] + + * tclAlloc.c: changed so allocated memory is always 8-byte aligned + to improve memory performance and to ensure that it will work on + systems that don't like accessing 4-byte aligned values + (e.g. Solaris and HP-UX). [Bug: 834] + +1998-11-06 + + * tclVar.c (TclGetIndexedScalar): Fixed bug 796, var name was + getting lost before being passed to CallTraces. + +1998-10-21 + + * added "encoding" command + + * Moved internal regexp declarations from tclInt.h to tclRegexp.h + + * integrated regexp updates from Henry Spencer + +1998-10-15 + + * tclUtf.c: added Unicode character table support + + * tclInt.h: added TclUniCharIsWordChar + + * tclCmdMZ.c (Tcl_StringObjCmd): added "totitle" subcommand, + changed "wordend" and "wordstart" to properly handle Unicode word + characters and connector punctuation + +1998-10-05 + + * auto.tcl, package.tcl: fixed SCCS strings + + * tclIndex: updated index to reflect 8.1 files + + * tclCompile.c (TclCompileScript): changed to avoid modifying the + input string in place because name lookup operations could have + arbitrary side effects + + * tclInterp.c: added guard against deleting current interpreter + + * tclMacFile.c, tclUnixFile.c, tclWinFile.c, tclFileName.c: added + warnings around code that modifies strings in place + + * tclExecute.c: fixed off-by-one copying error, fixed merge bugs + + * tclEvent.c: changed so USE_TCLALLOC is tested for value instead + of definition + + * tclCompCmds.c: replaced SCCS strings, added warnings around code + that modifies strings in place + + * interp.test: added test for interp deleting itself + +1998-09-30 + + * makefile.vc: fixed so TCL_LIBRARY is set before running tcltest + + * tclWin32Dll.c: removed TclpFinalize, cleanup of merges + diff --git a/mk4/modtcl/tcl8.3.4/README b/mk4/modtcl/tcl8.3.4/README new file mode 100644 index 0000000..8283c9c --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/README @@ -0,0 +1,185 @@ +README: Tcl + This is the Tcl 8.3.4 source distribution. + You can get any release of Tcl from: + http://sourceforge.net/project/showfiles.php?group_id=10894 + Tcl/Tk is also available through NetCVS: + http://tcl.sourceforge.net/ + +RCS: @(#) $Id: README,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ + +Contents +-------- + 1. Introduction + 2. Documentation + 3. Compiling and installing Tcl + 4. Development tools + 5. Tcl newsgroup + 6. Tcl contributed archive + 7. Tcl Resource Center + 8. Mailing lists + 9. Support and Training + 10. Thank You + +1. Introduction +--------------- +Tcl provides a powerful platform for creating integration applications that +tie together diverse applications, protocols, devices, and frameworks. +When paired with the Tk toolkit, Tcl provides the fastest and most powerful +way to create GUI applications that run on PCs, Unix, and the Macintosh. +Tcl can also be used for a variety of web-related tasks and for creating +powerful command languages for applications. + +Tcl is maintained, enhanced, and distributed freely by the Tcl community. +The home for Tcl/Tk sources and bug/patch database is on SourceForge: + + http://tcl.sourceforge.net/ + +with the Tcl Developer Xchange hosted at: + + http://www.tcl-tk.net/ + +Tcl is a freely available open source package. You can do virtually +anything you like with it, such as modifying it, redistributing it, +and selling it either in whole or in part. See the file +"license.terms" for complete information. + +2. Documentation +---------------- + +Extensive documentation is available at our website. +The home page for this release, including new features, is + http://www.tcl-tk.net/software/tcltk/8.3.html + +Detailed release notes can be found at + http://sourceforge.net/project/showfiles.php?group_id=10894 + +Information about Tcl itself can be found at + http://www.tcl-tk.net/scripting/ + +There are many Tcl books on the market. Most are listed at + http://www.tcl-tk.net/resource/doc/books/ + +2a. Unix Documentation +---------------------- + +The "doc" subdirectory in this release contains a complete set of +reference manual entries for Tcl. Files with extension ".1" are for +programs (for example, tclsh.1); files with extension ".3" are for C +library procedures; and files with extension ".n" describe Tcl +commands. The file "doc/Tcl.n" gives a quick summary of the Tcl +language syntax. To print any of the man pages on Unix, cd to the +"doc" directory and invoke your favorite variant of troff using the +normal -man macros, for example + + ditroff -man Tcl.n + +to print Tcl.n. If Tcl has been installed correctly and your "man" program +supports it, you should be able to access the Tcl manual entries using the +normal "man" mechanisms, such as + + man Tcl + +2b. Windows Documentation +------------------------- + +The "doc" subdirectory in this release contains a complete set of Windows +help files for Tcl. Once you install this Tcl release, a shortcut to the +Windows help Tcl documentation will appear in the "Start" menu: + + Start | Programs | Tcl | Tcl Help + +3. Compiling and installing Tcl +------------------------------- + +There are brief notes in the unix/README, win/README, and mac/README about +compiling on these different platforms. There is additional information +about building Tcl from sources at + + http://www.tcl-tk.net/doc/howto/compile.html + +4. TclPro Development tools +--------------------------- + +A high quality set of commercial quality development tools is available to +accelerate your Tcl application development. The TclPro product provides a +debugger, static code checker, packaging utility, and bytecode compiler. +TclPro was open-sourced when Scriptics/Ajuba was acquired by Interwoven. +Visit its home at SourceForge for more information and source/binaries: + + http://tclpro.sourceforge.net/ + +5. Tcl newsgroup +---------------- + +There is a network news group "comp.lang.tcl" intended for the exchange of +information about Tcl, Tk, and related applications. The newsgroup is a +great place to ask general information questions. For bug reports, please +see the "Support and bug fixes" section below. + +6. Tcl contributed archive +-------------------------- + +Many people have created exciting packages and applications based on Tcl +and/or Tk and made them freely available to the Tcl community. An archive +of these contributions is kept on the machine ftp.neosoft.com. You +can access the archive using anonymous FTP; the Tcl contributed archive is +in the directory "/pub/tcl". The archive also contains several FAQ +("frequently asked questions") documents that provide solutions to problems +that are commonly encountered by TCL newcomers. + +7. Tcl Resource Center +---------------------- + +Visit http://www.tcl-tk.net/resource/ to see an annotated index of +many Tcl resources available on the World Wide Web. This includes +papers, books, and FAQs, as well as development tools, extensions, +applications, binary releases, and patches. You can also recommend +additional URLs for the resource center using the forms labeled "Add a +Resource". + +8. Mailing lists +---------------- + +Several mailing lists are hosted at SourceForge to discuss development or +use issues (like Macintosh and Windows topics). For more information and +to subscribe, visit: + + http://sourceforge.net/projects/tcl/ + +and go to the Mailing Lists page. + +9. Support and Training +------------------------ + +We are very interested in receiving bug reports, patches, and suggestions +for improvements. We prefer that you send this information to us via the +bug form at SourceForge, rather than emailing us directly. The bug +database is at: + + http://tcl.sourceforge.net/ + +The bug form was designed to give uniform structure to bug reports as +well as to solicit enough information to minimize followup questions. + +We will log and follow-up on each bug, although we cannot promise a +specific turn-around time. Enhancements may take longer and may not happen +at all unless there is widespread support for them (we're trying to slow +the rate at which Tcl/Tk turns into a kitchen sink). It's very difficult +to make incompatible changes to Tcl/Tk at this point, due to the size of +the installed base. + +The Tcl community is too large for us to provide much individual support +for users. If you need help we suggest that you post questions to +comp.lang.tcl. We read the newsgroup and will attempt to answer esoteric +questions for which no-one else is likely to know the answer. In addition, +see the following Web site for links to other organizations that offer +Tcl/Tk training: + + http://www.tcl-tk.net/resource/community/commercial/training + +10. Thank You +------------- + +We'd like to express our thanks to the Tcl community for all the +helpful suggestions, bug reports, and patches we have received. +Tcl/Tk has improved vastly and will continue to do so with your help. diff --git a/mk4/modtcl/tcl8.3.4/changes b/mk4/modtcl/tcl8.3.4/changes new file mode 100644 index 0000000..d3b5e56 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/changes @@ -0,0 +1,5075 @@ +Recent user-visible changes to Tcl: + +RCS: @(#) $Id: changes,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ + +1. No more [command1] [command2] construct for grouping multiple +commands on a single command line. + +2. Semi-colon now available for grouping commands on a line. + +3. For a command to span multiple lines, must now use backslash-return +at the end of each line but the last. + +4. "Var" command has been changed to "set". + +5. Double-quotes now available as an argument grouping character. + +6. "Return" may be used at top-level. + +7. More backslash sequences available now. In particular, backslash-newline +may be used to join lines in command files. + +8. New or modified built-in commands: case, return, for, glob, info, +print, return, set, source, string, uplevel. + +9. After an error, the variable "errorInfo" is filled with a stack +trace showing what was being executed when the error occurred. + +10. Command abbreviations are accepted when parsing commands, but +are not recommended except for purely-interactive commands. + +11. $, set, and expr all complain now if a non-existent variable is +referenced. + +12. History facilities exist now. See Tcl.man and Tcl_RecordAndEval.man. + +13. Changed to distinguish between empty variables and those that don't +exist at all. Interfaces to Tcl_GetVar and Tcl_ParseVar have changed +(NULL return value is now possible). *** POTENTIAL INCOMPATIBILITY *** + +14. Changed meaning of "level" argument to "uplevel" command (1 now means +"go up one level", not "go to level 1"; "#1" means "go to level 1"). +*** POTENTIAL INCOMPATIBILITY *** + +15. 3/19/90 Added "info exists" option to see if variable exists. + +16. 3/19/90 Added "noAbbrev" variable to prohibit command abbreviations. + +17. 3/19/90 Added extra errorInfo option to "error" command. + +18. 3/21/90 Double-quotes now only affect space: command, variable, +and backslash substitutions still occur inside double-quotes. +*** POTENTIAL INCOMPATIBILITY *** + +19. 3/21/90 Added support for \r. + +20. 3/21/90 List, concat, eval, and glob commands all expect at least +one argument now. *** POTENTIAL INCOMPATIBILITY *** + +21. 3/22/90 Added "?:" operators to expressions. + +22. 3/25/90 Fixed bug in Tcl_Result that caused memory to get trashed. + +------------------- Released version 3.1 --------------------- + +23. 3/29/90 Fixed bug that caused "file a.b/c ext" to return ".b/c". + +24. 3/29/90 Semi-colon is not treated specially when enclosed in +double-quotes. + +------------------- Released version 3.2 --------------------- + +25. 4/16/90 Rewrote "exec" not to use select or signals anymore. +Should be more Sys-V compatible, and no slower in the normal case. + +26. 4/18/90 Rewrote "glob" to eliminate GNU code (there's no GNU code +left in Tcl, now), and added Tcl_TildeSubst procedure. Added automatic +tilde-substitution in many commands, including "glob". + +------------------- Released version 3.3 --------------------- + +27. 7/11/90 Added "Tcl_AppendResult" procedure. + +28. 7/20/90 "History" with no options now defaults to "history info" +rather than to "history redo". Although this is a backward incompatibility, +it should only be used interactively and thus shouldn't present any +compatibility problems with scripts. + +29. 7/20/90 Added "Tcl_GetInteger", "Tcl_GetDouble", and "Tcl_GetBoolean" +procedures. + +30. 7/22/90 Removed "Tcl_WatchInterp" procedure: doesn't seem to be +necessary, since the same effect can be achieved with the deletion +callbacks on individual commands. *** POTENTIAL INCOMPATIBILITY *** + +31. 7/23/90 Added variable tracing: Tcl_TraceVar, Tcl_UnTraceVar, +and Tcl_VarTraceInfo procedures, "trace" command. + +32. 8/9/90 Mailed out list of all bug fixes since 3.3 release. + +33. 8/29/90 Fixed bugs in Tcl_Merge relating to backslashes and +semi-colons. Mailed out patch. + +34. 9/3/90 Fixed bug in tclBasic.c: quotes weren't quoting ]'s. +Mailed out patch. + +35. 9/19/90 Rewrote exec to always use files both for input and +output to the process. The old pipe-based version didn't work if +the exec'ed process forked a child and then exited: Tcl waited +around for stdout to get closed, which didn't happen until the +grandchild exited. + +36. 11/5/90 ERR_IN_PROGRESS flag wasn't being cleared soon enough +in Tcl_Eval, allowing error messages from different commands to +pile up in $errorInfo. Fixed by re-arranging code in Tcl_Eval that +re-initializes result and ERR_IN_PROGRESS flag. Didn't mail out +patch: changes too complicated to describe. + +37. 12/19/90 Added Tcl_VarEval procedure as a convenience for +assembling and executing Tcl commands. + +38. 1/29/91 Fixed core leak in Tcl_AddErrorInfo. Also changed procedure +and Tcl_Eval so that first call to Tcl_AddErrorInfo need not come from +Tcl_Eval. + +----------------- Released version 5.0 with Tk ------------------ + +39. 4/3/91 Removed change bars from manual entries, leaving only those +that came after version 3.3 was released. + +40. 5/17/91 Changed tests to conform to Mary Ann May-Pumphrey's approach. + +41. 5/23/91 Massive revision to Tcl parser to simplify the implementation +of string and floating-point support in expressions. Newlines inside +[] are now treated as command separators rather than word separators +(this makes newline treatment consistent throughout Tcl). +*** POTENTIAL INCOMPATIBILITY *** + +42. 5/23/91 Massive rewrite of expression code to support floating-point +values and simple string comparisons. The C interfaces to expression +routines have changed (Tcl_Expr is replaced by Tcl_ExprLong, Tcl_ExprDouble, +etc.), but all old Tcl expression strings should be accepted by the new +expression code. +*** POTENTIAL INCOMPATIBILITY *** + +43. 5/23/91 Modified tclHistory.c to check for negative "keep" value. + +44. 5/23/91 Modified Tcl_Backslash to handle backslash-newline. It now +returns 0 to indicate that a backslash sequence should be replaced by +no character at all. +*** POTENTIAL INCOMPATIBILITY *** + +45. 5/29/91 Modified to use ANSI C function prototypes. Must set +"USE_ANSI" switch when compiling to get prototypes. + +46. 5/29/91 Completed test suite by providing tests for all of the +built-in Tcl commands. + +47. 5/29/91 Changed Tcl_Concat to eliminate leading and trailing +white-space in each of the things it concatenates and to ignore +elements that are empty or have only white space in them. This +produces cleaner output from the "concat" command. +*** POTENTIAL INCOMPATIBILITY *** + +48. 5/31/91 Changed "set" command and Tcl_SetVar procedure to return +new value of variable. + +49. 6/1/91 Added "while" and "cd" commands. + +50. 6/1/91 Changed "exec" to delete the last character of program +output if it is a newline. In most cases this makes it easier to +process program-generated output. +*** POTENTIAL INCOMPATIBILITY *** + +51. 6/1/91 Made sure that pointers are never used after freeing them. + +52. 6/1/91 Fixed bug in TclWordEnd where it wasn't dealing with +[] inside quotes correctly. + +53. 6/8/91 Fixed exec.test to accept return values of either 1 or +255 from "false" command. + +54. 7/6/91 Massive overhaul of variable management. Associative +arrays now available, along with "unset" command (and Tcl_UnsetVar +procedure). Variable traces have been completely reworked: +interfaces different both from Tcl and C, and multiple traces may +exist on same variable. Can no longer redefine existing local +variable to be global. Calling sequences have changed slightly +for Tcl_GetVar and Tcl_SetVar ("global" is now "flags"). Tcl_SetVar +can fail and return a NULL result. New forms of variable-manipulation +procedures: Tcl_GetVar2, Tcl_SetVar2, etc. Syntax of variable +$-notation changed to support array indexing. +*** POTENTIAL INCOMPATIBILITY *** + +55. 7/6/91 Added new list-manipulation procedures: Tcl_ScanElement, +Tcl_ConvertElement, Tcl_AppendElement. + +56. 7/12/91 Created new procedure Tcl_EvalFile, which does most of the +work of the "source" command. + +57. 7/20/91 Major reworking of "exec" command to allow pipelines, +more redirection, background. Added new procedures Tcl_Fork, +Tcl_WaitPids, Tcl_DetachPids, and Tcl_CreatePipeline. The old +"< input" notation has been replaced by "<< input" ("<" is for +redirection from a file). Also handles error returns and abnormal +terminations (e.g. signals) differently. +*** POTENTIAL INCOMPATIBILITY *** + +58. 7/21/91 Added "append" and "lappend" commands. + +59. 7/22/91 Reworked error messages and manual entries to use +?x? as the notation for an optional argument x, instead of [x]. The +bracket notation was often confused with the use of brackets for +command substitution. Also modified error messages to be more +consistent. + +60. 7/23/91 Tcl_DeleteCommand now returns an indication of whether +or not the command actually existed, and the "rename" command uses +this information to return an error if an attempt is made to delete +a non-existent command. +*** POTENTIAL INCOMPATIBILITY *** + +61. 7/25/91 Added new "errorCode" mechanism, along with procedures +Tcl_SetErrorCode, Tcl_UnixError, and Tcl_ResetResult. Renamed +Tcl_Return to Tcl_SetResult, but left a #define for Tcl_Return to +avoid compatibility problems. + +62. 7/26/91 Extended "case" command with alternate syntax where all +patterns and commands are together in a single list argument: makes +it easier to write multi-line case statements. + +63. 7/27/91 Changed "print" command to perform tilde-substitution on +the file name. + +64. 7/27/91 Added "tolower", "toupper", "trim", "trimleft", and "trimright" +options to "string" command. + +65. 7/29/91 Added "atime", "mtime", "size", and "stat" options to "file" +command. + +66. 8/1/91 Added "split" and "join" commands. + +67. 8/11/91 Added commands for file I/O, including "open", "close", +"read", "gets", "puts", "flush", "eof", "seek", and "tell". + +68. 8/14/91 Switched to use a hash table for command lookups. Command +abbreviations no longer have direct support in the Tcl interpreter, but +it should be possible to simulate them with the auto-load features +described below. The "noAbbrev" variable is no longer used by Tcl. +*** POTENTIAL INCOMPATIBILITY *** + +68.5 8/15/91 Added support for "unknown" command, which can be used to +complete abbreviations, auto-load library files, auto-exec shell +commands, etc. + +69. 8/15/91 Added -nocomplain switch to "glob" command. + +70. 8/20/91 Added "info library" option and TCL_LIBRARY #define. Also +added "info script" option. + +71. 8/20/91 Changed "file" command to take "option" argument as first +argument (before file name), for consistency with other Tcl commands. +*** POTENTIAL INCOMPATIBILITY *** + +72. 8/20/91 Changed format of information in $errorInfo variable: +comments such as + ("while" body line 1) +are now on separate lines from commands being executed. +*** POTENTIAL INCOMPATIBILITY *** + +73. 8/20/91 Changed Tcl_AppendResult so that it (eventually) frees +large buffers that it allocates. + +74. 8/21/91 Added "linsert", "lreplace", "lsearch", and "lsort" +commands. + +75. 8/28/91 Added "incr" and "exit" commands. + +76. 8/30/91 Added "regexp" and "regsub" commands. + +77. 9/4/91 Changed "dynamic" field in interpreters to "freeProc" (procedure +address). This allows for alternative storage managers. +*** POTENTIAL INCOMPATIBILITY *** + +78. 9/6/91 Added "index", "length", and "range" options to "string" +command. Added "lindex", "llength", and "lrange" commands. + +79. 9/8/91 Removed "index", "length", "print" and "range" commands. +"Print" is redundant with "puts", but less general, and the other +commands are replaced with the new commands described in change 78 +above. +*** POTENTIAL INCOMPATIBILITY *** + +80. 9/8/91 Changed history revision to occur even when history command +is nested; needed in order to allow "history" to be invoked from +"unknown" procedure. + +81. 9/13/91 Changed "panic" not to use vfprintf (it's uglier and less +general now, but makes it easier to run Tcl on systems that don't +have vfprintf). Also changed "strerror" not to redeclare sys_errlist. + +82. 9/19/91 Lots of changes to improve portability to different UNIX +systems, including addition of "config" script to adapt Tcl to the +configuration of the system it's being compiled on. + +83. 9/22/91 Added "pwd" command. + +84. 9/22/91 Renamed manual pages so that their filenames are no more +than 14 characters in length, moved to "doc" subdirectory. + +85. 9/24/91 Redid manual entries so they contain the supplemental +macros that they need; can just print with "troff -man" or "man" +now. + +86. 9/26/91 Created initial version of script library, including +a version of "unknown" that does auto-loading, auto-execution, and +abbreviation expansion. This library is used by tclTest +automatically. See the "library" manual entry for details. + +----------------- Released version 6.0, 9/26/91 ------------------ + +87. 9/30/91 Made "string tolower" and "string toupper" check case +before converting: on some systems, "tolower" and "toupper" assume +that character already has particular case. + +88. 9/30/91 Fixed bug in Tcl_SetResult: wasn't always setting freeProc +correctly when called with NULL value. This tended to cause memory +allocation errors later. + +89. 10/3/91 Added "upvar" command. + +90. 10/4/91 Changed "format" so that internally it converts %D to %ld, +%U to %lu, %O to %lo, and %F to %f. This eliminates some compatibility +problems on some machines without affecting behavior. + +91. 10/10/91 Fixed bug in "regsub" that caused core dumps with the -all +option when the last match wasn't at the end of the string. + +92. 10/17/91 Fixed problems with backslash sequences: \r support was +incomplete and \f and \v weren't supported at all. + +93. 10/24/91 Added Tcl_InitHistory procedure. + +94. 10/24/91 Changed "regexp" to store "-1 -1" in subMatchVars that +don't match, rather than returning an error. + +95. 10/27/91 Modified "regexp" to return actual strings in matchVar +and subMatchVars instead of indices. Added "-indices" switch to cause +indices to be returned. +*** POTENTIAL INCOMPATIBILITY *** + +96. 10/27/91 Fixed bug in "scan" where it used hardwired constants for +sizes of floats and doubles instead of using "sizeof". + +97. 10/31/91 Fixed bug in tclParse.c where parse-related error messages +weren't being storage-managed correctly, causing spurious free's. + +98. 10/31/91 Form feed and vertical tab characters are now considered +to be space characters by the parser. + +99. 10/31/91 Added TCL_LEAVE_ERR_MSG flag to procedures like Tcl_SetVar. + +100. 11/7/91 Fixed bug in "case" where "in" argument couldn't be omitted +if all case branches were embedded in a single list. + +101. 11/7/91 Switched to use "pid_t" and "uid_t" and other official +POSIC types and function prototypes. + +----------------- Released version 6.1, 11/7/91 ------------------ + +102. 12/2/91 Modified Tcl_ScanElement and Tcl_ConvertElement in several +ways. First, allowed caller to request that only backslashes be used +(no braces). Second, made Tcl_ConvertElement more aggressive in using +backslashes for braces and quotes. + +103. 12/5/91 Added "type", "lstat", and "readlink" options to "file" +command, plus added new "type" element to output of "stat" and "lstat" +options. + +104. 12/10/91 Manual entries had first lines that caused "man" program +to try weird preprocessor. Added blank comment lines to fix problem. + +105. 12/16/91 Fixed a few bugs in auto_mkindex proc: wasn't handling +errors properly, and hadn't been upgraded for new "regexp" syntax. + +106. 1/2/92 Fixed bug in "file" command where it didn't properly handle +a file names containing tildes where the indicated user doesn't exist. + +107. 1/2/92 Fixed lots of cases in tclUnixStr.c where two different +errno symbols (e.g. EWOULDBLOCK and EAGAIN) have the same number; Tcl +will only use one of them. + +108. 1/2/92 Lots of changes to configuration script to handle many more +systems more gracefully. E.g. should now detect the bogus strtoul that +comes with AIX and substitute Tcl's own version instead. + +----------------- Released version 6.2, 1/10/92 ------------------ + +109. 1/20/92 Config didn't have code to actually use "uid_t" variable +to set TCL_UIT_T #define. + +110. 2/10/92 Tcl_Eval didn't properly reset "numLevels" variable when +too-deep recursion occurred. + +111. 2/29/92 Added "on" and "off" to keywords accepted by Tcl_GetBoolean. + +112. 3/19/92 Config wasn't installing default version of strtod.c for +systems that don't have one in libc.a. + +113. 3/23/92 Fixed bug in tclExpr.c where numbers with leading "."s, +like 0.75, couldn't be properly substituted into expressions with +variable or command substitution. + +114. 3/25/92 Fixed bug in tclUnixAZ.c where "gets" command wasn't +checking to make sure that it was able to write the variable OK. + +115. 4/16/92 Fixed bug in tclUnixAZ.c where "read" command didn't +compute file size right for device files. + +116. 4/23/92 Fixed but in tclCmdMZ.c where "trace vinfo" was overwriting +the trace command. + +----------------- Released version 6.3, 5/1/92 ------------------ + +117. 5/1/92 Added Tcl_GlobalEval. + +118. 6/1/92 Changed auto-load facility to source files at global level. + +119. 6/8/92 Tcl_ParseVar wasn't always setting termPtr after errors, which +sometimes caused core dumps. + +120. 6/21/92 Fixed bug in initialization of regexp pattern cache. This +bug caused segmentation violations in regexp commands under some conditions. + +121. 6/22/92 Changed implementation of "glob" command to eliminate +trailing slashes on directory names: they confuse some systems. There +shouldn't be any user-visible changes in functionality except for names +in error messages not having trailing slashes. + +122. 7/2/92 Fixed bug that caused 'string match ** ""' to return 0. + +123. 7/2/92 Fixed bug in Tcl_CreateCmdBuf where it wasn't initializing +the buffer to an empty string. + +124. 7/6/92 Fixed bug in "case" command where it used NULL pattern string +after errors in the "default" clause. + +125. 7/25/92 Speeded up auto_load procedure: don't reread all the index +files unless the path has changed. + +126. 8/3/92 Changed tclUnix.h to define MAXPATHLEN from PATH_MAX, not +_POSIX_PATH_MAX. + +----------------- Released version 6.4, 8/7/92 ------------------ + +127. 8/10/92 Changed tclBasic.c so that comment lines can be continued by +putting a backslash before the newline. + +128. 8/21/92 Modified "unknown" to allow the source-ing of a file for +an auto-load to trigger other nested auto-loads, as long as there isn't +any recursion on the same command name. + +129. 8/25/92 Modified "format" command to allow " " and "+" flags, and +allow flags in any order. + +130. 9/14/92 Modified Tcl_ParseVar so that it doesn't actually attempt +to look up the variable if "noEval" mode is in effect in the interpreter +(it just parses the name). This avoids the errors that used to occur +in statements like "expr {[info exists foo] && $foo}". + +131. 9/14/92 Fixed bug in "uplevel" command where it didn't output the +correct error message if a level was specified but no command. + +132. 9/14/92 Renamed manual entries to have extensions like .3 and .n, +and added "install" target to Makefile. + +133. 9/18/92 Modified "unknown" command to emulate !!, !, and +^^ csh history substitutions. + +134. 9/21/92 Made the config script cleverer about figuring out which +switches to pass to "nm". + +135. 9/23/92 Fixed tclVar.c to be sure to copy flags when growing variables. +Used to forget about traces in progress and make extra recursive calls +on trace procs. + +136. 9/28/92 Fixed bug in auto_reset where it was unsetting variables +that might not exist. + +137. 10/7/92 Changed "parray" library procedure to print any array +accessible to caller, local or global. + +138. 10/15/92 Fixed bug where propagation of new environment variable +values among interpreters took N! time if there exist N interpreters. + +139. 10/16/92 Changed auto_reset procedure so that it also deletes any +existing procedures that are in the auto_load index (the assumption is +that they should be re-loaded to get the latest versions). + +140. 10/21/92 Fixed bug that caused lists to be incorrectly generated +for elements that contained backslash-newline sequences. + +141. 12/9/92 Added support for TCL_LIBRARY environment variable: use +it as library location if it's present. + +142. 12/9/92 Added "info complete" command, Tcl_CommandComplete procedure. + +143. 12/16/92 Changed the Makefile to check to make sure "config" has been +run (can't run config directly from the Makefile because it modifies the +Makefile; thus make has to be run again after running config). + +----------------- Released version 6.5, 12/17/92 ------------------ + +144. 12/21/92 Changed config to look in several places for libc file. + +145. 12/23/92 Added "elseif" support to if. Also, "then", "else", and +"elseif" may no longer be abbreviated. +*** POTENTIAL INCOMPATIBILITY *** + +146. 12/28/92 Changed "puts" and "read" to support initial "-nonewline" +switch instead of additional "nonewline" argument. The old form is +still supported, but it is discouraged and is no longer documented. +Also changed "puts" to make the file argument default to stdout: e.g. +"puts foo" will print foo on standard output. + +147. 1/6/93 Fixed bug whereby backslash-newline wasn't working when +typed interactively, or in "info complete". + +148. 1/22/93 Fixed bugs in "lreplace" and "linsert" where close +quotes were being lost from last element before replacement or +insertion. + +149. 1/29/93 Fixed bug in Tcl_AssembleCmd where it wasn't requiring +a newline at the end of a line before considering a command to be +complete. The bug caused some very long lines in script files to +be processed as multiple separate commands. + +150. 1/29/93 Various changes in Makefile to add more configuration +options, simplify installation, fix bugs (e.g. don't use -f switch +for cp), etc. + +151. 1/29/93 Changed "name1" and "name2" identifiers to "part1" and +"part2" to avoid name conflicts with stupid C++ implementations that +use "name1" and "name2" in a reserved way. + +152. 2/1/93 Added "putenv" procedure to replace the standard system +version so that it will work correctly with Tcl's environment handling. + +----------------- Released version 6.6, 2/5/93 ------------------ + +153. 2/10/93 Fixed bugs in config script: missing "endif" in libc loop, +and tried to use strncasecmp.c instead of strcasecmp.c. + +154. 2/10/93 Makefile improvements: added RANLIB variable for easier +Sys-V configuration, added SHELL variable for SGI systems. + +----------------- Released version 6.7, 2/11/93 ------------------ + +153. 2/6/93 Changes in backslash processing: + - \Cx, \Mx, \CMx, \e sequences no longer special + - \ also eats up any space after the newline, replacing + the whole sequence with a single space character + - Hex sequences like \x24 are now supported, along with ANSI C's \a. + - "format" no longer does backslash processing on its format string + - there is no longer any special meaning to a 0 return value from + Tcl_Backslash + - unknown backslash sequences, like (e.g. \*), are replaced with + the following character (e.g. *), instead of just treating the + backslash as an ordinary character. +*** POTENTIAL INCOMPATIBILITY *** + +154. 2/6/93 Updated all copyright notices. The meaning hasn't changed +at all but the wording does a better job of protecting U.C. from +liability (according to U.C. lawyers, anyway). + +155. 2/6/93 Changed "regsub" so that it overwrites the result variable +in all cases, even if there is no match. +*** POTENTIAL INCOMPATIBILITY *** + +156. 2/8/93 Added support for XPG3 %n$ conversion specifiers to "format" +command. + +157. 2/17/93 Fixed bug in Tcl_Eval where errors due to infinite +recursion could result in core dumps. + +158. 2/17/93 Improved the auto-load mechanism to deal gracefully (i.e. +return an error) with a situation where a library file that supposedly +defines a procedure doesn't actually define it. + +159. 2/17/93 Renamed Tcl_UnixError procedure to Tcl_PosixError, and +changed errorCode variable usage to use POSIX as keyword instead of +UNIX. +*** POTENTIAL INCOMPATIBILITY *** + +160. 2/19/93 Changes to exec and process control: + - Added support for >>, >&, >>&, |&, <@, >@, and >&@ forms of redirection. + - When exec puts processes into background, it returns a list of + their pids as result. + - Added support for file, etc. (i.e. no space between + ">" and file name. + - Added -keepnewline option. + - Deleted Tcl_Fork and Tcl_WaitPids procedures (just use fork and + waitpid instead). + - Added waitpid compatibility procedure for systems that don't have + it. + - Added Tcl_ReapDetachedProcs procedure. + - Changed "exec" to return an error if there is stderr output, even + if the command returns a 0 exit status (it's always been documented + this way, but the implementation wasn't correct). + - If a process returns a non-zero exit status but doesn't generate + any diagnostic output, then Tcl generates an error message for it. +*** POTENTIAL INCOMPATIBILITY *** + +161. 2/25/93 Fixed two memory-management problems having to do with +managing the old result during variable trace callbacks. + +162. 3/1/93 Added dynamic string library: Tcl_DStringInit, Tcl_DStringAppend, +Tcl_DStringFree, Tcl_DStringResult, etc. + +163. 3/1/93 Modified glob command to only return the names of files that +exist, and to only return names ending in "/" if the file is a directory. +*** POTENTIAL INCOMPATIBILITY *** + +164. 3/19/93 Modified not to use system calls like "read" directly, +but instead to use special Tcl procedures that retry automatically +if interrupted by signals. + +165. 4/3/93 Eliminated "noSep" argument to Tcl_AppendElement, plus +TCL_NO_SPACE flag for Tcl_SetVar and Tcl_SetVar2. +*** POTENTIAL INCOMPATIBILITY *** + +166. 4/3/93 Eliminated "flags" and "termPtr" arguments to Tcl_Eval. +*** POTENTIAL INCOMPATIBILITY *** + +167. 4/3/93 Changes to expressions: + - The "expr" command now accepts multiple arguments, which are + concatenated together with space separators. + - Integers aren't automatically promoted to floating-point if they + overflow the word size: errors are generated instead. + - Tcl can now handle "NaN" and other special values if the underlying + library procedures handle them. + - When printing floating-point numbers, Tcl ensures that there is a "." + or "e" in the number, so it can't be treated as an integer accidentally. + The procedure Tcl_PrintDouble is available to provide this function + in other contexts. Also, the variable "tcl_precision" can be used + to set the precision for printing (must be a decimal number giving + digits of precision). + - Expressions now support transcendental and other functions, e.g. sin, + acos, hypot, ceil, and round. Can add new math functions with + Tcl_CreateMathFunc(). + - Boolean expressions can now have any of the string values accepted + by Tcl_GetBoolean, such as "yes" or "no". +*** POTENTIAL INCOMPATIBILITY *** + +168. 4/5/93 Changed Tcl_UnsetVar and Tcl_UnsetVar2 to return TCL_OK +or TCL_ERROR instead of 0 or -1. +*** POTENTIAL INCOMPATIBILITY *** + +169. 4/5/93 Eliminated Tcl_CmdBuf structure and associated procedures; +can use Tcl_DStrings instead. +*** POTENTIAL INCOMPATIBILITY *** + +170. 4/8/93 Changed interface to Tcl_TildeSubst to use a dynamic +string for buffer space. This makes the procedure re-entrant and +thread-safe, whereas it wasn't before. +*** POTENTIAL INCOMPATIBILITY *** + +171. 4/14/93 Eliminated tclHash.h, and moved everything from it to +tcl.h +*** POTENTIAL INCOMPATIBILITY *** + +172. 4/15/93 Eliminated Tcl_InitHistory, made "history" command always +be part of interpreter. +*** POTENTIAL INCOMPATIBILITY *** + +173. 4/16/93 Modified "file" command so that "readable" option always +exists, even on machines that don't support symbolic links (always returns +same error as if the file wasn't a symbolic link). + +174. 4/26/93 Fixed bugs in "regsub" where ^ patterns didn't get handled +right (pretended not to match when it really did, and looped infinitely +if -all was specified). + +175. 4/29/93 Various improvements in the handling of variables: + - Can create variables and array elements during a read trace. + - Can delete variables during traces (note: unset traces will be + invoked when this happens). + - Can upvar to array elements. + - Can retarget an upvar to another variable by re-issuing the + upvar command with a different "other" variable. + +176. 5/3/93 Added Tcl_GetCommandInfo, which returns info about a Tcl +command such as whether it exists and its ClientData. Also added +Tcl_SetCommandInfo, which allows any of this information to be modified +and also allows a command's delete procedure to have a different +ClientData value than its command procedure. + +177. 5/5/93 Added Tcl_RegExpMatch procedure. + +178. 5/6/93 Fixed bug in "scan" where it didn't properly handle +%% conversion specifiers. Also changed "scan" to use Tcl_PrintDouble +for printing real values. + +179. 5/7/93 Added "-exact", "-glob", and "-regexp" options to "lsearch" +command to allow different kinds of pattern matching. + +180. 5/7/93 Added many new switches to "lsort" to control the sorting +process: "-ascii", "-integer", "-real", "-command", "-increasing", +and "-decreasing". + +181. 5/10/93 Changes to file I/O: + - Modified "open" command to support a list of POSIX access flags + like {WRONLY CREAT TRUNC} in addition to current fopen-style + access modes. Also added "permissions" argument to set permissions + of newly-created files. + - Fixed Scott Bolte's bug (can close stdin etc. in application and + then re-open them with Tcl commands). + - Exported access to Tcl's file table with new procedures Tcl_EnterFile + and Tcl_GetOpenFile. + +182. 5/15/93 Added new "pid" command, which can be used to retrieve +either the current process id or a list of the process ids in a +pipeline opened with "open |..." + +183. 6/3/93 Changed to use GNU autoconfig for configuration instead of +the home-brew "config" script. Also made many other configuration-related +changes, such as using instead of explicitly declaring system +calls in tclUnix.h. + +184. 6/4/93 Fixed bug where core-dumps could occur if a procedure +redefined itself (the memory for the procedure's body could get +reallocated in the middle of evaluating the body); implemented +simple reference count mechanism. + +185. 6/5/93 Changed tclIndex file format in two ways: (a) it's now +eval-ed instead of parsed, which makes it 3-4x faster; (b) the entries +in auto_index are now commands to evaluate, which allows commands to +be loaded in different ways such as dynamic-loading of C code. The +old tclIndex file format is still supported. + +186. 6/7/93 Eliminated tclTest program, added new "tclsh" program +that is more like wish (allows script files to be invoked automatically +using "#!/usr/local/bin/tclsh", makes arguments available to script, +etc.). Added support for Tcl_AppInit plus default version; this +allows new Tcl applications to be created without modifying the +main program for tclsh. + +187. 6/7/93 Fixed bug in TclWordEnd that kept backslash-newline from +working correctly in some cases during interactive input. + +188. 6/9/93 Added Tcl_LinkVar and related procedures, which automatically +keep a Tcl variable in sync with a C variable. + +189. 6/16/93 Increased maximum nesting depth from 100 to 1000. + +190. 6/16/93 Modified "trace var" command so that error messages from +within traces are returned properly as the result of the variable +access, instead of the generic "access disallowed by trace command" +message. + +191. 6/16/93 Added Tcl_CallWhenDeleted to provide callbacks when an +interpreter is deleted (same functionality as Tcl_WatchInterp, which +used to exist in versions before 6.0). + +193. 6/16/93 Added "-code" argument to "return" command; it's there +primarily for completeness, so that procedures implementing control +constructs can reflect exceptional conditions back to their callers. + +194. 6/16/93 Split up Tcl.n to make separate manual entries for each +Tcl command. Tcl.n now contains a summary of the language syntax. + +195. 6/17/93 Added new "switch" command to replace "case": allows +alternate forms of pattern matching (exact, glob, regexp), replaces +pattern lists with single patterns (but you can use "-" bodies to +share one body among several patterns), eliminates "in" noise word. +"Case" command is now obsolete. + +196. 6/17/93 Changed the "exec", "glob", "regexp", and "regsub" commands +to include a "--" switch. All initial arguments starting with "-" are now +treated as switches unless a "--" switch is present to end the list. +*** POTENTIAL INCOMPATIBILITY *** + +197. 6/17/93 Changed auto-exec so that the subprocess gets stdin, stdout, +and stderr from the parent. This allows truly interactive sub-processes +(e.g. vi) to be auto-exec'ed from a tcl shell command line. + +198. 6/18/93 Added patchlevel.h, for use in coordinating future patch +releases, and also added "info patchlevel" command to make the patch +level available to Tcl scripts. + +199. 6/19/93 Modified "glob" command so that a leading "//" in a name +gets left as is (this is needed for systems like Apollos where "//" is +the super-root; Tcl used to collapse the two slashes into a single +slash). + +200. 7/7/93 Added Tcl_SetRecursionLimit procedure so that the maximum +allowable nesting depth can be controlled for an interpreter from C. + +----------------- Released version 7.0 Beta 1, 7/9/93 ------------------ + +201. 7/12/93 Modified Tcl_GetInt and tclExpr.c so that full-precision +unsigned integers can be specified without overflow errors. + +202. 7/12/93 Configuration changes: eliminate leading blank line in +configure script; provide separate targets in Makefile for installing +binary and non-binary information; check for size_t and a few other +potentially missing typedefs; don't put tclAppInit.o into libtcl.a; +better checks for matherr support. + +203. 7/14/93 Changed tclExpr.c to check the termination pointer before +errno after strtod calls, to avoid problems with some versions of +strtod that set errno in unexpected ways. + +204. 7/16/93 Changed "scan" command to be more ANSI-conformant: +eliminated %F, %D, etc., added code to ignore "l", "h", and "L" +modifiers but always convert %e, %f, and %g with implicit "l"; +also added support for %u and %i. Also changed "format" command +to eliminate %D, %U, %O, and add %i. +*** POTENTIAL INCOMPATIBILITY *** + +205. 7/17/93 Changed "uplevel" and "upvar" so that they can be used +from global level to global level: this used to generate an error. + +206. 7/19/93 Renamed "setenv", "putenv", and "unsetenv" procedures +to avoid conflicts with system procedures with the same names. If +you want Tcl's procedures to override the system procedures, do it +in the Makefile (instructions are in the Makefile). +*** POTENTIAL INCOMPATIBILITY *** + +----------------- Released version 7.0 Beta 2, 7/21/93 ------------------ + +207. 7/21/93 Fixed bug in tclVar.c where freed memory was accidentally +used if a procedure returned an element of a local array. + +208. 7/22/93 Fixed bug in "unknown" where it didn't properly handle +errors occurring in the "auto_load" procedure, leaving its state +inconsistent. + +209. 7/23/93 Changed exec's ">2" redirection operator to "2>" for +consistency with sh. This is incompatible with earlier beta releases +of 7.0 but not with pre-7.0 releases, which didn't support either +operator. + +210. 7/28/93 Changed backslash-newline handling so that the resulting +space character *is* treated as a word separator unless the backslash +sequence is in quotes or braces. This is incompatible with 7.0b1 +and 7.0b2 but is more compatible with pre-7.0 versions that the b1 +and b2 releases were. + +211. 7/28/93 Eliminated Tcl_LinkedVarWritable, added TCL_LINK_READ_ONLY to +Tcl_LinkVar to accomplish same purpose. This change is incompatible +with earlier beta releases, but not with releases before Tcl 7.0. + +212. 7/29/93 Renamed regexp C functions so they won't clash with POSIX +regexp functions that use the same name. + +213. 8/3/93 Added "-errorinfo" and "-errorcode" options to "return" +command: these allow for much better handling of the errorInfo +and errorCode variables in some cases. + +214. 8/12/93 Changed "expr" so that % always returns a remainder with +the same sign as the divisor and absolute value smaller than the +divisor. + +215. 8/14/93 Turned off auto-exec in "unknown" unless the command +was typed interactively. This means you must use "exec" when +invoking subprocesses, unless it's a command that's typed interactively. +*** POTENTIAL INCOMPATIBILITY *** + +216. 8/14/93 Added support for tcl_prompt1 and tcl_prompt2 variables +to tclMain.c: makes prompts user-settable. + +217. 8/14/93 Added asynchronous handlers (Tcl_AsyncCreate etc.) so +that signals can be taken cleanly by Tcl applications. + +218. 8/16/93 Moved information about open files from the interpreter +structure to global variables so that a file can be opened in one +interpreter and read or written in another. + +219. 8/16/93 Removed ENV_FLAGS from Makefile, so that there's no +official support for overriding setenv, unsetenv, and putenv. + +220. 8/20/93 Various configuration improvements: coerce chars +to unsigned chars before using macros like isspace; source ~/.tclshrc +file during initialization if it exists and program is running +interactively; allow there to be directories in auto_path that don't +exist or don't have tclIndex files (ignore them); added Tcl_Init +procedure and changed Tcl_AppInit to call it. + +221. 8/21/93 Fixed bug in expr where "+", "-", and " " were all +getting treated as integers with value 0. + +222. 8/26/93 Added "tcl_interactive" variable to tclsh. + +223. 8/27/93 Added procedure Tcl_FilePermissions to return whether a +given file can be read or written or both. Modified Tcl_EnterFile +to take a permissions mask rather than separate read and write arguments. + +224. 8/28/93 Fixed performance bug in "glob" command (unnecessary call +to "access" for each file caused a 5-10x slow-down for big directories). + +----------------- Released version 7.0 Beta 3, 8/28/93 ------------------ + +225. 9/9/93 Renamed regexp.h to tclRegexp.h to avoid conflicts with system +include file by same name. + +226. 9/9/93 Added Tcl_DontCallWhenDeleted. + +227. 9/16/93 Changed not to call exit C procedure directly; instead +always invoke "exit" Tcl command so that application can redefine the +command to do additional cleanup. + +228. 9/17/93 Changed auto-exec to handle names that contain slashes +(i.e. don't use PATH for them). + +229. 9/23/93 Fixed bug in "read" and "gets" commands where they didn't +clear EOF conditions. + +----------------- Released version 7.0, 9/29/93 ------------------ + +230. 10/7/93 "Scan" command wasn't properly aligning things in memory, +so segmentation faults could arise under some circumstances. + +231. 10/7/93 Fixed bug in Tcl_ConvertElement where it forgot to +backslash leading curly brace when creating lists. + +232. 10/7/93 Eliminated dependency of tclMain.c on tclInt.h and +tclUnix.h, so that people can copy the file out of the Tcl source +directory to make modified private versions. + +233. 10/8/93 Fixed bug in auto-loader that reversed the priority order +of entries in auto_path for new-style index files. Now things are +back to the way they were before 3.0: first in auto_path is always +highest priority. + +234. 10/13/93 Fixed bug where Tcl_CommandComplete didn't recognize +comments and treat them as such. Thus if you typed the line + # { +interactively, Tcl would think that the command wasn't complete and +wait for more input before evaluating the script. + +235. 10/14/93 Fixed bug where "regsub" didn't set the output variable +if the input string was empty. + +236. 10/23/93 Fixed bug where Tcl_CreatePipeline didn't close off enough +file descriptors in child processes, causing children not to exit +properly in some cases. + +237. 10/28/93 Changed "list" and "concat" commands not to generate +errors if given zero arguments, but instead to just return an empty +string. + +----------------- Released version 7.1, 11/4/93 ------------------ + +Note: there is no 7.2 release. It was flawed and was thus withdrawn +shortly after it was released. + +238. 11/10/93 TclMain.c didn't compile on some systems because of +R_OK in call to "access". Changed to eliminate call to "access". + +----------------- Released version 7.3, 11/26/93 ------------------ + +239. 11/6/93 Modified "lindex", "linsert", "lrange", and "lreplace" +so that "end" can be specified as an index. + +240. 11/6/93 Modified "append" and "lappend" to allow only two +words total (i.e., nothing to append) without generating an error. + +241. 12/2/93 Changed to use EAGAIN as the errno for non-blocking +I/O instead of EWOULDBLOCK: this should fix problem where non-blocking +I/O didn't work correctly on System-V systems. + +242. 12/22/93 Fixed bug in expressions where cancelled evaluation +wasn't always working correctly (e.g. "set one 1; eval {1 || 1/$one}" +failed with a divide by zero error). + +243. 1/6/94 Changed TCL_VOLATILE definition from -1 to the address of +a dummy procedure Tcl_Volatile, since -1 causes portability problems on +some machines (e.g., Crays). + +244. 2/4/94 Added support for unary plus. + +245. 2/17/94 Changed Tcl_RecordAndEval and "history" command to +call Tcl_GlobalEval instead of Tcl_Eval. Otherwise, invocation of +these facilities in nested procedures can cause unwanted results. + +246. 2/17/94 Fixed bug in tclExpr.c where an expression such as +"expr {"12398712938788234-1298379" != ""}" triggers an integer +overflow error for the number in quotes, even though it isn't really +a proper integer anyway. + +247. 2/19/94 Added new procedure Tcl_DStringGetResult to move result +from interpreter to a dynamic string. + +248. 2/19/94 Fixed bug in Tcl_DStringResult that caused it to overwrite +the contents of a static result in some situations. This can cause +bizarre errors such as variables suddenly having empty values. + +249. 2/21/94 Fixed bug in Tcl_AppendElement, Tcl_DStringAppendElement, +and the "lappend" command that caused improper omission of a separator +space in some cases. For example, the script + set x "abc{"; lappend x "def" +used to return the result "abc{def" instead of "abc{ def". + +250. 3/3/94 Tcl_ConvertElement was outputting empty elements as \0 if +TCL_DONT_USE_BRACES was set. This depends on old pre-7.0 meaning of +\0, which is no longer in effect, so it didn't really work. Changed +to output empty elements as {} always. + +251. 3/3/94 Renamed Tcl_DStringTrunc to Tcl_DStringSetLength and extended +it so that it can be used to lengthen a string as well as shorten it. +Tcl_DStringTrunc is defined as a macro for backward compatibility, but +it is deprecated. + +252. 3/3/94 Added Tcl_AllowExceptions procedure. + +253. 3/13/94 Fixed bug in Tcl_FormatCmd that could cause "format" +to mis-behave on 64-bit Big-Endian machines. + +254. 3/13/94 Changed to use vfork instead of fork on systems where +vfork exists. + +255. 3/23/94 Fixed bug in expressions where ?: didn't associate +right-to-left as they should. + +256. 4/3/94 Fixed "exec" to flush any files used in >@ or >&@ +redirection in exec, so that data buffered for them is written +before any new data added by the subprocess. + +257. 4/3/94 Added "subst" command. + +258. 5/20/94 The tclsh main program is now called Tcl_Main; tclAppInit.c +has a "main" procedure that calls Tcl_Main. This makes it easier to use +Tcl with C++ programs, which need their own main programs, and it also +allows an application to prefilter the argument list before calling +Tcl_Main. +*** POTENTIAL INCOMPATIBILITY *** + +259. 6/6/94 Fixed bug in procedure returns where the errorInfo variable +could get truncated if an unset trace was invoked as part of returning +from the procedure. + +260. 6/13/94 Added "wordstart" and "wordend" options to "string" command. + +261. 6/27/94 Fixed bug in expressions where they didn't properly cancel +the evaluation of math functions in &&, ||, and ?:. + +262. 7/11/94 Incorrect boolean values, like "ogle", weren't being +handled properly. + +263. 7/15/94 Added Tcl_RegExpCompile, Tcl_RegExpExec, and Tcl_RegExpRange, +which provide lower-level access to regular expression pattern matching. + +264. 7/22/94 Fixed bug in "glob" command where "glob -nocomplain ~bad_user" +would complain about a missing user. Now it doesn't complain anymore. + +265. 8/4/94 Fixed bug with linked variables where they didn't behave +correctly when accessed via upvars. + +266. 8/17/94 Fixed bug in Tcl_EvalFile where it didn't clear interp->result. + +267. 8/31/94 Modified "open" command so that errors in exec-ing +subprocesses are returned by the open immediately, rather than +being delayed until the "close" is executed. + +268. 9/9/94 Modified "expr" command to generate errors for integer +overflow (includes addition, subtraction, negation, multiplication, +division). + +269. 9/23/94 Modified "regsub" to return a count of the number of +matches and replacements, rather than 0/1. + +279. 10/4/94 Added new features to "array" command: + - added "get" and "set" commands for easy conversion between arrays + and lists. + - added "exists" command to see if a variable is an array, changed + "names" and "size" commands to treat a non-existent array (or scalar + variable) just like an empty one. + - added pattern option to "names" command. + +280. 10/6/94 Modified Tcl_SetVar2 so that read traces on variables get +called during append operations. + +281. 10/20/94 Fixed bug in "read" command where reading from stdin +required two control-D's to stop the reading. + +282. 11/3/94 Changed "expr" command to use longs for division just like +all other expr operators; it previously used ints for division. + +283. 11/4/94 Fixed bugs in "unknown" procedure: it wasn't properly +handling exception returns from commands that were executed after +being auto-loaded. + +----------------- Released version 7.4b1, 12/23/94 ------------------ + +284. 12/26/94 Fixed "install" target in Makefile (couldn't always +find install program). + +285. 12/26/94 Added strcncasecmp procedure to compat directory. + +286. 1/3/95 Fixed all procedure calls to explicitly cast arguments: +implicit conversions from prototypes (especially integer->double) +don't work when compiling under non-ANSI compilers. Tcl is now clean +under gcc -Wconversion. + +287. 1/4/95 Fixed problem in Tcl_ArrayCmd where same name was used for +both a label and a variable; caused problems on several older compilers, +making array command misbehave and causing many errors in Tcl test suite. + +----------------- Released version 7.4b2, 1/12/95 ------------------ + +288. 2/9/95 Modified Tcl_CreateCommand to return a token, and added +Tcl_GetCommandName procedure. Together, these procedures make it possible +to track renames of a command. + +289. 2/13/95 Fixed bug in expr where "089" was interpreted as a +floating-point number rather than a bogus octal number. +*** POTENTIAL INCOMPATIBILITY *** + +290. 2/14/95 Added code to Tcl_GetInt and Tcl_GetDouble to check for +overflows when reading in numbers. + +291. 2/18/95 Changed "array set" to stop after first error, rather than +continuing after error. + +292. 2/20/95 Upgraded to use autoconf version 2.2. + +293. 2/20/95 Fixed core dump that could occur in "scan" command if a +close bracket was omitted. + +294. 2/27/95 Changed Makefile to always use install-sh for installations: +there's just too much variation among "install" system programs, which +makes installation flakey. + +----------------- Released version 7.4b3, 3/24/95 ------------------ + +3/25/95 (bug fix) Changed "install" to "./install" in Makefile so that +"make install" will work even when "." isn't in the search path. + +3/29/95 (bug fix) Fixed bug where the auto-loading mechanism wasn't +protecting the values of the errorCode and errorInfo variables. + +3/29/95 (new feature) Added optional pattern argument to "parray" procedure. + +3/29/95 (bug fix) Made the full functionality of + "return -code ... -errorcode ..." +work not just inside procedures, but also in sourced files and at +top level. + +4/6/95 (new feature) Added "pattern" option to "array names" command. + +4/18/95 (bug fix) Fixed bug in parser where it didn't allow backslash-newline +immediately after an argument in braces or quotes. + +4/19/95 (new feature) Added tcl_library variable, which application can +set to override default library directory. + +4/30/95 (bug fix) During trace callbacks for array elements, the variable +name used in the original reference would be temporarily modified to +separate the array name and element name; if the trace callback used +the same name string, it would get the wrong name (the array name without +element). Fixed to restore the variable name before making trace +callbacks. + +4/30/95 (new feature) Added -nobackslashes, -nocommands, and -novariables +switches to "subst" command. + +5/4/95 (new feature) Added TCL_EVAL_GLOBAL flag to Tcl_RecordAndEval. + +5/5/95 (bug fix) Format command would overrun memory when printing +integers with very large precision, as in "format %.1000d 0". + +5/5/95 (portability improvement) Changed to use BSDgettimeofday on +IRIX machines, to avoid compilation problems with the gettimeofday +declaration. + +5/6/95 (bug fix) Changed manual entries to use the standard .TH +macro instead of a custom .HS macro; the .HS macro confuses index +generators like makewhatis. + +5/9/95 (bug fix) Modified configure script to check for Solaris bug +that makes vfork unreliable (core dumps result if vforked child +changes a signal handler); will use fork instead of vfork if the +bug is present. + +6/5/95 (bug fix) Modified "lsort" command to disallow recursive calls +to lsort from a comparison function. This is needed because qsort +is not reentrant. + +6/5/95 (bug fix) Undid change 243 above: changed TCL_VOLATILE and +TCL_DYNAMIC back to integer constants rather than procedure addresses. +This was needed because procedure addresses can have multiple values +under some dynamic loading systems (e.g. SunOS 4.1 and Windows). + +6/8/95 (feature change) Modified interface to Tcl_Main to pass in the +address of the application-specific initialization procedure. +Tcl_AppInit is no longer hardwired into Tcl_Main. This is needed +in order to make Tcl a shared library. + +6/8/95 (feature change) Modified Makefile so that the installed versions +of tclsh and libtcl.a have version number in them (e.g. tclsh7.4 and +libtcl7.4.a) and the library directory name also has an embedded version +number (e.g., /usr/local/lib/tcl7.4). This should make it easier for +Tcl 7.4 to coexist with earlier versions. + +----------------- Released version 7.4b4, 6/16/95 ------------------ + +6/19/95 (bug fix) Fixed bugs in tclCkalloc.c that caused core dumps +if TCL_MEM_DEBUG was enabled on word-addressed machines such as Crays. + +6/21/95 (feature removal) Removed overflow checks for integer arithmetic: +they just cause too much trouble (e.g. for random number generators). + +6/28/95 (new features) Added tcl_patchLevel and tcl_version variables, +for consistency with Tk. + +6/29/95 (bug fix) Fixed problem in Tcl_Eval where it didn't record +the right termination character if a script ended with a comment. This +caused erroneous output for the following command, among others: +puts "[ +expr 1+1 +# duh! +]" + +6/29/95 (message change) Changed the error message for ECHILD slightly +to provide a hint about why the problem is occurring. + +----------------- Released version 7.4, 7/1/95 ------------------ + +7/18/95 (bug fix) Changed "lreplace" so that nothing is deleted if +the last index is less than the first index or if the last index +is < 0. + +7/18/95 (bug fix) Fixed bugs with backslashes in comments: +Tcl_CommandComplete (and "info complete") didn't properly handle +strings ending in backslash-newline, and neither Tcl_CommandComplete +nor the Tcl parser handled other backslash sequences right, such +as two backslashes before a newline. + +7/19/95 (bug fix) Modified Tcl_DeleteCommand to delete the hash table +entry for the command before invoking its callback. This is needed in +order to deal with reentrancy. + +7/22/95 (bug fix) "exec" wasn't reaping processes correctly after +certain errors (e.g. if the name of the executable was bogus, as +in "exec foobar"). + +7/27/95 (bug fix) Makefile.in wasn't using the LIBS variable provided +by the "configure" script. This caused problems on some SCO systems. + +7/27/95 (bug fix) The version of strtod in fixstrtod.c didn't properly +handle the case where endPtr == NULL. + +----------------- Released patch 7.4p1, 7/29/95 ----------------------- + +8/4/95 (bug fix) C-level trace callbacks for variables were sometimes +receiving the PART1_NOT_PARSED flag, which could cause errors in +subsequent Tcl library calls using the flags. (JO) + +8/4/95 (bug fix) Calls to toupper and tolower weren't using the +UCHAR macros, which caused trouble in non-U.S. locales. (JO) + +8/10/95 (new feature) Added the "load" command for dynamic loading of +binary packages, and the Tcl_PackageInitProc prototype for package +initialization procedures. (JO) + +8/23/95 (new features) Added "info sharedlibextension" and +"info nameofexecutable" commands, plus Tcl_FindExtension procedure. (JO) + +8/25/95 (bug fix) If the target of an "upvar" was non-existent but +had traces set, the traces were silently lost. Change to generate +an error instead. (JO) + +8/25/95 (bug fix) Undid change from 7/19, so that commands can stay +around while their deletion callbacks execute. Added lots of code to +handle all of the reentrancy problems that this opens up. (JO) + +8/25/95 (bug fix) Fixed core dump that could occur in TclDeleteVars +if there was an upvar from one entry in the table to the next entry +in the same table. (JO) + +8/28/95 (bug fix) Exec wasn't handling bad user names properly, as +in "exec ~bogus_user/foo". (JO) + +8/29/95 (bug fixes) Changed backslash-newline handling to correct two +problems: + - Only spaces and tabs following the backslash-newline are now + absorbed as part of the backslash-newline. Newlinew are no + longer absorbed (add another backslash if you want to absorb + another newline). + - TclWordEnd returns the character just before the backslash in + the sequence as the end of the sequence; it used to not consider + the backslash-newline as a word separator. (JO) + +8/31/95 (new feature) Changed man page installation (with "mkLinks" +script) to create additional links for manual pages corresponding to +each of the procedure and command names described in the pages. (JO) + +9/10/95 Reorganized Tcl sources for Windows and Mac ports. All sources +are now in subdirectories: "generic" contains sources that work on all +platforms, "windows", "mac", and "unix" directories contain platform- +specific sources. Some UNIX sources are also used on other platforms. (SS) + +9/10/95 (feature change) Eliminated exported global variables (they +don't work with Windows DLLs). Replaced tcl_AsyncReady and +tcl_FileCloseProc with procedures Tcl_AsyncReady() and +Tcl_SetFileCloseProc(). Replaced C variable tcl_RcFileName with +a Tcl variable tcl_rcFileName. (SS) +*** POTENTIAL INCOMPATIBILITY *** + +9/11/95 (new feature) Added procedure Tcl_SetPanicProc to override +the default implementation of "panic". (SS) + +9/11/95 (new feature) Added "interp" command to allow creation of +new interpreters and execution of untrusted scripts. Added many new +procedures, such as Tcl_CreateSlave, Tcl_CreateAlias,and Tcl_MakeSafe, +to provide C-level access to the interpreter facility. This mechanism +now provides almost all of the generic functions of Borenstein's and +Rose's Safe-Tcl (but not any Tk or email-related stuff). (JL) + +9/11/95 (feature change) Changed file management so that files are +no longer shared between interpreters: a file cannot normally be +referenced in one interpreter if it was opened in another. This +feature is needed to support safe interpreters. Added Tcl_ShareHandle() +procedure for allowing files to be shared, and added "interp" argument +to Tcl_FilePermissions procedure. (JL) +*** POTENTIAL INCOMPATIBILITY *** + +9/11/95 (new feature) Added "AssocData" mechanism, whereby extensions +can associate their own data with an interpreter and get called back +when the interpreter is deleted. This is visible at C level via the +procedures Tcl_SetAssocData and Tcl_GetAssocData. (JL) + +9/11/95 (new feature) Added Tcl_ErrnoMsg to translate an errno value +into a human-readable string. This is now used instead of calling +strerror because strerror mesages vary dramatically from platform +to platform, which messes up Tcl tests. Tcl_ErrnoMsg uses the standard +POSIX messages for all the common signals, and calls strerror for +signals it doesn't understand. + +----------------- Released patch 7.4p2, 9/15/95 ----------------------- + +----------------- Released 7.5a1, 9/15/95 ----------------------- + +9/22/95 (bug fix) Changed auto_mkindex to create tclIndex files that +handle directories whose paths might contain spaces. (RJ) + +9/27/95 (bug fix) The "format" command didn't check for huge or negative +width specifiers, which could cause core dumps. (JO) + +9/27/95 (bug fix) Core dumps could occur if an interactive command typed +to tclsh returned a very long result for tclsh to print out. The bug is +actually in printf (in Solaris 2.3 and 2.4, at least); switched to use +puts instead. (JO) + +9/28/95 (bug fix) Changed makefile.bc to eliminate a false dependency +for tcl1675.dll on the Borland run time library. (SS) + +9/28/95 (bug fix) Fixed tcl75.dll so it looks for tcl1675.dll instead +of tcl16.dll. (SS) + +9/28/95 (bug fix) Tcl was not correctly detecting the difference +between Win32s and Windows '95. (SS) + +9/28/95 (bug fix) "exec" was not passing environment changes to child +processes under Windows. (SS) + +9/28/95 (bug fix) Changed Tcl to ensure that open files are not passed +to child processes under Windows. (SS) + +9/28/95 (bug fix) Fixed Windows '95 and NT versions of exec so it can +handle both console and windows apps. (SS) + +9/28/95 (bug fix) Fixed Windows version of exec so it no longer leaves +temp files lying around. Also changed it so the temp files are +created in the appropriate system dependent temp directory. (SS) + +9/28/95 (bug fix) Eliminated source dependency on the Win32s Universal +Thunk header file, since it is not bundled with VC++. (SS) + +9/28/95 (bug fix) Under Windows, Tcl now constructs the HOME +environment variable from HOMEPATH and HOMEDRIVE when HOME is not +already set. (SS) + +9/28/95 (bug fix) Added support for "info nameofexecutable" and "info +sharedlibextension" to the Windows version. (SS) + +9/28/95 (bug fix) Changed tclsh to correctly parse command line +arguments so that backslashes are preserved under Windows. (SS) + +9/29/95 (bug fix) Tcl 7.5a1 treated either return or newline as end +of line in "gets", which caused lines ending in CRLF to be treated as +two separate lines. Changed to allow only character as end-of-line: +carriage return on Macs, newline elsewhere. (JO) + +9/29/95 (new feature) Changed to install "configInfo" file in same +directory as library scripts. It didn't used to get installed. (JO) + +9/29/95 (bug fix) Tcl was not converting Win32 errors into POSIX +errors under some circumstances. (SS) + +10/2/95 (bug fix) Safe interpreters no longer get initialized with +a call to Tcl_Init(). (JL) + +10/1/95 (new feature) Added "tcl_platform" global variable to provide +environment information such as the instruction set and operating +system. (JO) + +10/1/95 (bug fix) "exec" command wasn't always generating the +"child process exited abnormally" message when it should have. (JO) + +10/2/95 (bug fix) Changed "mkLinks.tcl" so that the scripts it generates +won't create links that overwrite original manual entries (there was +a problem where pack-old.n was overwriting pack.n). (JO) + +10/2/95 (feature change) Changed to use -ldl for dynamic loading under +Linux if it is available, but fall back to -ldld if it isn't. (JO) + +10/2/95 (bug fix) File sharing was causing refcounts to reach 0 +prematurely for stdin, stdout and stderr, under some circumstances. (JL) + +10/2/95 (platform support) Added support for Visual C++ compiler on +Windows, Windows '95 and Windows NT, code donated by Gordon Chaffee. (JL) + +10/3/95 (bug fix) Tcl now frees any libraries that it loads before it +exits. (SS) + +10/03/95 (bug fix) Fixed bug in Macintosh ls command where the -l +and -C options would fail in anything but the HOME directory. (RJ) + +----------------- Released 7.5a2, 10/6/95 ----------------------- + +10/10/95 (bug fix) "file dirnam /." was returning ":" on UNIX instead +of "/". (JO) + +10/13/95 (bug fix) Eliminated dependency on MKS toolkit for generating +the tcl.def file from Borland object files. (SS) + +10/17/95 (new features) Moved the event loop from Tcl to Tk, made major +revisions along the way: + - New Tcl commands: after, update, vwait (replaces "tkwait variable"). + - "tkerror" is now replaced with "bgerror". + - The following procedures are similar to their old Tk counterparts: + Tcl_DoOneEvent, Tcl_Sleep, Tcl_DoWhenIdle, Tcl_CancelIdleCall, + Tcl_CreateFileHandler, Tcl_DeleteFileHandler, Tcl_CreateTimerHandler, + Tcl_DeleteTimerHandler, Tcl_BackgroundError. + - Revised notifier, add new concept of "event source" with the following + procedures: Tcl_CreateEventSource, Tcl_DeleteEventSource, + Tcl_WatchFile, Tcl_SetMaxBlockTime, Tcl_FileReady, Tcl_QueueEvent, + Tcl_WaitForEvent. (JO) + +10/31/95 (new features) Implemented cross platform file name support to make +it easier to write cross platform scripts. Tcl now understands 4 file naming +conventions: Windows (both DOS and UNC), Mac, Unix, and Network. The network +convention is a new naming mechanism that can be used to paths in a platform +independent fashion. See the "file" command manual page for more details. +The primary interfaces changes are: + - All Tcl commands that expect a file name now accept both network and + native form. + - Two new "file" subcommands, "nativename" and "networkname", provide a + way to convert between network and native form. + - Renamed Tcl_TildeSubst to Tcl_TranslateFileName, and changed it so that + it always returns a filename in native form. Tcl_TildeSubst is defined + as a macro for backward compatibility, but it is deprecated. (SS) + +11/5/95 (new feature) Made "tkerror" and "bgerror" synonyms, so that +either name can be used to manipulate the command (provides temporary +backward compatibility for existing scripts that use tkerror). (JO) + +11/5/95 (new feature) Added exit handlers and new C procedures +Tcl_CreateExitHandler, Tcl_DeleteExitHandler, and Tcl_Exit. (JO) + +11/6/95 (new feature) Added pid command for Macintosh version of +Tcl (it didn't previously exist on the Mac). (RJ) + +11/7/95 (new feature) New generic IO facility and support for IO to +files, pipes and sockets based on a common buffering scheme. Support +for asynchronous (non-blocking) IO and for event driver IO. Support +for automatic (background) asynchronous flushing and asynchronous +closing of channels. (JL) + +11/7/95 (new feature) Added new commands "fconfigure" and "fblocked" +to support new I/O features such as nonblocking I/O. Added "socket" +command for creating TCP client and server sockets. (JL). + +11/7/95 (new feature) Complete set of C APIs to the new generic IO +facility: + - Opening channels: Tcl_OpenFileChannel, Tcl_OpenCommandChannel, + Tcl_OpenTcpClient, Tcl_OpenTcpServer. + - I/O procedures on channels, which roughly mirror the ANSI C stdio + library: Tcl_Read, Tcl_Gets, Tcl_Write, Tcl_Flush, Tcl_Seek, + Tcl_Tell, Tcl_Close, Tcl_Eof, Tcl_InputBlocked, Tcl_GetChannelOption, + Tcl_SetChannelOption. + - Extension mechanism for creating new kinds of channels: + Tcl_CreateChannel, Tcl_GetChannelInstanceData, Tcl_GetChannelType, + Tcl_GetChannelName, Tcl_GetChannelFile, Tcl_RegisterChannel, + Tcl_UnregisterChannel, Tcl_GetChannel. + - Event-driven I/O on channels: Tcl_CreateChannelHandler, + Tcl_DeleteChannelHandler. (JL) + +11/7/95 (new feature) Channel driver interface specification to allow +new types of channels to be added easily to Tcl. Currently being used +in three drivers - for files, pipes and TCP-based sockets. (JL). + +11/7/95 (new feature) interp delete now takes any number of path +names of interpreters to delete, including zero. (JL). + +11/8/95 (new feature) implemented 'info hostname' and Tcl_GetHostName +command to get host name of machine on which the Tcl process is running. (JL) + +11/9/95 (new feature) Implemented file APIs for access to low level files +on each system. The APIs are: Tcl_CloseFile, Tcl_OpenFile, Tcl_ReadFile, +Tcl_WriteFile and Tcl_SeekFile. Also implemented Tcl_WaitPid which waits +in a system dependent manner for a child process. (JL) + +11/9/95 (new feature) Added Tcl_UpdateLinkedVar procedure to force a +Tcl variable to be updated after its C variable changes. (JO) + +11/9/95 (bug fix) The glob command has been totally reimplemented so +that it can support different file name conventions. It now handles +Windows file names (both UNC and drive-relative) properly. It also +supports nested braces correctly now. (SS) + +11/13/95 (bug fix) Fixed Makefile.in so that configure can be run +from a clean directory separate from the Tcl source tree, and compilations +can be performed there. (JO) + +11/14/95 (bug fix) Fixed file sharing between interpreters and file +transferring between interpreters to correctly manage the refcount so that +files are closed when the last reference to them is discarded. (JL) + +11/14/95 (bug fix) Fixed gettimeofday implementation for the +Macintosh. This fixes several timing related bugs. (RJ) + +11/17/95 (new feature) Added missing support for info nameofexecutable +on the Macintosh. (RJ) + +11/17/95 (bug fix) The Tcl variables argc argv and argv0 now return +something reasonable on the Mac. (RJ) + +11/22/95 (new feature) Implemented "auto-detect" mode for end of line +translations. On input, standalone "\r" mean MAC mode, standalone "\n" +mean Unix mode and "\r\n" means Windows mode. On output, the mode is +modified to whatever the platform specific mode for that platform is. (JL) + +11/24/95 (feature change) Replaced "configInfo" file with tclConfig.sh, +which is more complete and uses slightly different names. Also +arranged for tclConfig.sh to be installed in the platform-specific +library directory instead of Tcl's script library directory. (JO) +*** POTENTIAL INCOMPATIBILITY with Tcl 7.5a2, but not with Tcl 7.4 *** + +----------------- Released patch 7.4p3, 11/28/95 ----------------------- + +12/5/95 (new feature) Added Tcl_File facility to support platform- +independent file handles. Changed all interfaces that used Unix- +style integer fd's to use Tcl_File's instead. (SS) +*** POTENTIAL INCOMPATIBILITY *** + +12/5/95 (new feature) Added a new "clock" command to Tcl. The command +allows you to get the current "clicks" or seconds & allows you to +format or scan human readable time/date strings. (RJ) + +12/18/95 (new feature) Moved Tk_Preserve, Tk_Release, and Tk_EventuallyFree +to Tcl, renamed to Tcl_Preserve, Tcl_Release, and Tcl_EventuallyFree. (JO) + +12/18/95 (new feature) Added new "package" command and associated +procedures Tcl_PkgRequire and Tcl_PkgProvide. Also wrote +pkg_mkIndex library procedure to create index files from binaries +and scripts. (JO) + +12/20/95 (new feature) Added Tcl_WaitForFile procedure. (JO) + +12/21/95 (new features) Made package name argument to "load" optional +(Tcl will now attempt to guess the package name if necessary). Also +added Tcl_StaticPackage and support in "load" for statically linked +packages. (JO) + +12/22/95 (new feature) Upgraded the foreach command to accept multiple +loop variables and multiple value lists. This lets you iterate over +multiple lists in parallel, and/or assign multiple loop variables from +one value list during each iteration. The only potential compatibility +problem is with scripts that used loop variables with a name that could be +construed to be a list of variable names (i.e. contained spaces). (BW) + +1/5/96 (new feature) Changed tclsh so it builds as a console mode +application under Windows. Now tclsh can be used from the command +line with pipes or interactively. Note that this only works under +Windows 95 or NT. (SS) + +1/17/96 (new feature) Modified Makefile and configure script to allow +Tcl to be compiled as a shared library: use the --enable-shared option +when configuing. (JO) + +1/17/96 (removed obsolete features) Removed the procedures Tcl_EnterFile +and Tcl_GetOpenFile: these no longer make sense with the new I/O system. (JL) +*** POTENTIAL INCOMPATIBILITY *** + +1/19/96 (bug fixes) Prevented formation of circular aliases, through the +Tcl 'interp alias' command and through the 'rename' command, as well as +through the C API Tcl_CreateAlias. (JL) + +1/19/96 (bug fixes) Fixed several bugs in direct deletion of interpreters +with Tcl_DeleteInterp when the interpreter is a slave; fixes based on a +patch received from Viktor Dukhovni of ESM. (JL) + +1/19/96 (new feature) Implemented on-close handlers for channels; added +the C APIs Tcl_CreateCloseHandler and Tcl_DeleteCloseHandler. (JL) + +1/19/96 (new feature) Implemented portable error reporting mechanism; added +the C APIs Tcl_SetErrno and Tcl_GetErrno. (JL) + +1/24/96 (bug fix) Unknown command processing properly invokes external +commands under Windows NT and Windows '95 now. (SS) + +1/23/96 (bug fix) Eliminated extremely long startup times under Windows '95. +The problem was a result of the option database initialization code that +concatenated $HOME with /.Xdefaults, resulting in a // in the middle of the +file name. Under Windows '95, this is incorrectly interpreted as a UNC +path. They delays came from the network timeouts needed to determine that +the file name was invalid. Tcl_TranslateFileName now suppresses duplicate +slashes that aren't at the beginning of the file name. (SS) + +1/25/96 (bug fix) Changed exec and open to create children so they are +attached to the application's console if it exists. (SS) + +1/31/96 (bug fix) Fixed command line parsing to handle embedded +spaces under Windows. (SS) + +----------------- Released 7.5b1, 2/1/96 ----------------------- + +2/7/96 (bug fix) Fixed off by one error in argument parsing code under +Windows. (SS) + +2/7/96 (bug fix) Fixed bugs in VC++ makefile that improperly +initialized the tcl75.dll. Fixed bugs in Borland makefile that caused +build failures under Windows NT. (SS) + +2/9/96 (bug fix) Fixed deadlock problem in AUTO end of line translation +mode which would cause a socket server with several concurrent clients +writing in CRLF mode to hang. (JL) + +2/9/96 (API change) Replaced -linemode option to fconfigure with a +new -buffering option, added "none" setting to enable immediate write. (JL) +*** INCOMPATIBILITY with b1 *** + +2/9/96 (new feature) Added C API Tcl_InputBuffered which returns the count +of bytes currently buffered in the input buffer of a channel, and o for +output only channels. (JL) + +2/9/96 (new feature) Implemented asynchronous connect for sockets. (JL) + +2/9/96 (new feature) Added C API Tcl_SetDefaultTranslation to set (per +channel) the default end of line translation mode. This is the mode that +will be installed if an output operation is done on the channel while it is +still in AUTO mode. (JL) + +2/9/96 (bug fix) Changed Tcl_OpenCommandChannel interface to properly +handle all of the combinations of stdio inheritance in background +pipelines. See the Tcl_OpenFileChannel(3) man page for more +info. This change fixes the bug where exec of a background pipeline +was not getting passed the stdio handles properly. (SS) + +2/9/96 (bug fix) Removed the new Tcl_CreatePipeline interface, and +restored the old version for Unix platforms only. All new code should +use Tcl_CreateCommandChannel instead. (SS) + +2/9/96 (bug fix) Changed Makefile.in to use -L and -ltcl7.5 for Tcl +library so that shared libraries are more likely to be found correctly +on more platforms. (JO) + +2/13/96 (new feature) Added C API Tcl_SetNotifierData and +Tcl_GetNotifierData to allow notifier and channel driver writers to +associate data with a Tcl_File. The result of this change is that +Tcl_GetFileInfo now always returns an OS file handle, and Tcl_GetFile +can be used to construct a Tcl_File for an externally constructed OS +handle. (SS) + +2/13/96 (bug fix) Changed Windows socket implementation so it doesn't +set SO_REUSEADDR on server sockets. Now attempts to create a server +socket on a port that is already in use will be properly identified +and an error will be generated. (SS) + +2/13/96 (bug fix) Fixed problems with DLL initialization under Visual +C++ that left the C run time library uninitialized. (SS) + +2/13/96 (bug fix) Fixed Windows socket initialization so it loads +winsock the first time it is used, rather than at the time tcl75.dll +is loaded. This should fix the bug where the modem immediately starts +trying to connect to a service provider when wish or tclsh are +started. (SS) + +2/13/96 (new feature) Added C APIs Tcl_MakeFileChannel and +Tcl_MakeTcpClientChannel to wrap up existing fds and sockets into +channels. Provided implementations on Unix and Windows. (JL) + +2/13/96 (bug fix) Fixed bug with seek leaving EOF and BLOCKING set. (JL) + +2/14/96 (bug fix) Fixed reentrancy problem in fileevent handling +and made it more robust in the face of errors. (JL) + +2/14/96 (feature change) Made generic IO level emulate blocking mode if the +channel driver is unable to provide it, e.g. if the low level device is +always nonblocking. Thus, now blocking behavior is an advisory setting for +channel drivers and can be ignored safely if the channel driver is unable +to provide it. (JL) + +2/15/96 (new feature) Added "binary" end of line translation mode, which is +a synonym of "lf" mode. (JL) + +2/15/96 (bug fix) Fixed reentrancy problem in fileevent handling vs +deletion of channel event handlers. (JL) + +2/15/96 (bug fix) Fixed bug in event handling which would cause a +nonblocking channel to not see further readable events after the first +readable event that had insufficient input. (JL) + +2/17/96 (bug fix) "info complete" didn't properly handle comments +in nested commands. (JO) + +2/21/96 (bug fix) "exec" under Windows NT/95 did not properly handle +very long command lines (>200 chars). (SS) + +2/21/96 (bug fix) Sockets could get into an infinite loop if a read +event arrived after all of the available data had been read. (SS) + +2/22/96 (bug fix) Added cast of st_size elements to (long) before +sprintf-ing in "file size" command. This is needed to handle systems +like NetBSD with 64-bit file offsets. (JO) + +----------------- Released 7.5b2, 2/23/96 ----------------------- + +2/23/96 (bug fix) TCL_VARARGS macro in tcl.h wasn't defined properly +when compiling with C++. (JO) + +2/24/96 (bug fix) Removed dependencies on Makefile in the UNIX Makefile: +this caused problems on some platforms (like Linux?). (JO) + +2/24/96 (bug fix) Fixed configuration bug that made Tcl not compile +correctly on Linux machines with neither -ldl or -ldld. (JO) + +2/24/96 (new feature) Added a block of comments and definitions to +Makefile.in to make it easier to have Tcl's TclSetEnv etc. replace +the library procedures setenv etc, so that calls to setenv etc. in +the application automatically update the Tcl "env" variable. (JO) + +2/27/96 (feature change) Added optional Tcl_Interp * argument (may be NULL) +to C API Tcl_Close and simplified closing of command channels. (JL) +*** INCOMPATIBILITY with Tcl 7.5b2, but not with Tcl 7.4 *** + +2/27/96 (feature change) Added optional Tcl_Interp * argument (may be NULL) +to C type definition Tcl_DriverCloseProc; modified all channel drivers to +implement close procedures that accept the additional argument. (JL) +*** INCOMPATIBILITY with Tcl 7.5b2, but not with Tcl 7.4 *** + +2/28/96 (bug fix) Fixed memory leak that could occur if an upvar +referred to an element of an array in the same stack frame as the +upvar. (JO) + +2/29/96 (feature change) Modified both Tcl_DoOneEvent and Tcl_WaitForEvent +so that they return immediately in cases where they would otherwise +block forever (e.g. if there are no event handlers of any sort). (JO) + +2/29/96 (new feature) Added C APIs Tcl_GetChannelBufferSize and +Tcl_SetChannelBufferSize to set and retrieve the size, in bytes, for +buffers allocated to store input or output in a channel. (JL) + +2/29/96 (new feature) Added option -buffersize to Tcl fconfigure command +to allow Tcl scripts to query and set the size of channel buffers. (JL) + +2/29/96 (feature removed) Removed channel driver function to specify +the buffer size to use when allocating a buffer. Removed the C typedef +for Tcl_DriverBufferSizeProc. Channels are now created with a default +buffer size of 4K. (JL) +*** INCOMPATIBILITY with Tcl 7.5b2, but not with Tcl 7.4 *** + +2/29/96 (feature change) The channel driver function for setting blocking +mode on the device may now be NULL. If the generic code detects that the +function is NULL, operations that set the blocking mode on the channel +simply succeed. (JL) + +3/2/96 (bug fix) Fixed core dump that could occur if a syntax error +(such as missing close paren) occurred in an array reference with a +very long array name. (JO) + +3/4/96 (bug fix) Removed code in the "auto_load" procedure that deletes +all existing auto-load information whenever the "auto_path" variable +is changed. Instead, new information adds to what was already there. +Otherwise, changing the "auto_path" variable causes all package- +related information to be lost. If you really want to get rid of +existing auto-load information, use auto_reset before setting auto_path. (JO) + +3/5/96 (new feature) Added version suffix to shared library names so that +Tcl will compile under NetBSD and FreeBSD (I hope). (JO) + +3/6/96 (bug fix) Cleaned up error messages in new I/O system to correspond +more closely to old I/O system. (JO) + +3/6/96 (new feature) Added -myaddr and -myport options to the socket +command, removed -tcp and -- options. This lets clients and servers +choose a particular interface. Also changed the default server address +from the hostname to INADDR_ANY. The server accept callback now gets +passed the client's port as well as IP address. The C interfaces for +Tcl_OpenTcpClient and Tcl_OpenTcpServer have changed to support the +above changes. (BW) +*** POTENTIAL INCOMPATIBILITY with Tcl 7.5b2, but not with Tcl 7.4 *** + +3/6/96 (changed feature) The library function auto_mkindex will now +default to using the pattern "*.tcl" if no pattern is given. (RJ) + +3/6/96 (bug fix) The socket channel code for the Macintosh has been +rewritten to use native MacTcp. (RJ) + +3/7/96 (new feature) Added Tcl_SetStdChannel and Tcl_GetStdChannel +interfaces to allow applications to explicitly set and get the global +standard channels. (SS) + +3/7/96 (bug fix) Tcl did close not the file descriptors associated +with "stdout", etc. when the corresponding channels were closed. (SS) + +3/7/96 (bug fix) Reworked shared library and dynamic loading stuff to +try to get it working under AIX. Added new @SHLIB_LD_LIBS@ autoconf +symbol as part of this. AIX probably doesn't work yet, but it should +be a lot closer. (JO) + +3/7/96 (feature change) Added Tcl_ChannelProc typedef and changed the +signature of Tcl_CreateChannelHandler and Tcl_DeleteChannelHandler to take +Tcl_ChannelProc arguments instead of Tcl_FileProc arguments. This change +should not affect any code outside Tcl because the signatures of +Tcl_ChannelProc and Tcl_FileProc are compatible. (JL) + +3/7/96 (API change) Modified signature of Tcl_GetChannelOption to return +an int instead of char *, and to take a Tcl_DString * argument. Modified +the implementation so that the option name can be NULL, to mean that the +call should retrieve a list of alternating option names and values. (JL) +*** INCOMPATIBILITY with Tcl 7.5b2, but not with Tcl 7.4 *** + +3/7/96 (API change) Added Tcl_DriverSetOptionProc, Tcl_DriverGetOptionProc +typedefs, added two slots setOptionProc and getOptionProc to the channel +type structure. These may be NULL to indicate that the channel type does +not support any options. (JL) +*** INCOMPATIBILITY with Tcl 7.5b2, but not with Tcl 7.4 *** + +3/7/96 (feature change) stdin, stdout and stderr can now be put into +nonblocking mode. (JL) + +3/8/96 (feature change) Eliminated dependence on the registry for +finding the Tcl library files. (SS) + +----------------- Released 7.5b3, 3/8/96 ----------------------- + +3/12/96 (feature improvement) Modified startup script to look in several +different places for the Tcl library directory. This should allow Tcl +to find the libraries under all but the weirdest conditions, even without +the TCL_LIBRARY environment variable being set. (JO) + +3/13/96 (bug fix) Eliminated use of the "linger" option from the Windows +socket implementation. (JL) + +3/13/96 (new feature) Added -peername and -sockname options for fconfigure +for socket channels. Code contributed by John Haxby of HP. (JL) + +3/13/96 (bug fix) Fixed panic and core dump that would occur if the accept +callback script on a server socket encountered an error. (JL) + +3/13/96 (feature change) Added -async option to the Tcl socket command. +If the command is creating a client socket and the flag is present, the +client is connected asynchronously. If the option is absent (the default), +the client socket is connected synchronously, and the command returns only +when the connection has been completed or failed. This change was suggested +by Mark Diekhans. (JL) + +3/13/96 (feature change) Modified the signature of Tcl_OpenTcpClient to +take an additional int argument, async. If nonzero, the client is connected +to the server asynchronously. If the value is zero, the connection is made +synchronously, and the call to Tcl_OpenTcpClient returns only when the +connection fails or succeeds. This change was suggested by Mark Diekhans. (JL) +*** INCOMPATIBILITY with Tcl 7.5b3, but not with Tcl 7.4 *** + +3/14/96 (bug fix) "tclsh bogus_file_name" didn't print an error message. (JO) + +3/14/96 (bug fix) Added new procedures to tclCkalloc.c so that libraries +and applications can be compiled with TCL_MEM_DEBUG even if Tcl isn't +(however, the converse is still not true). Patches provided by Jan +Nijtmans. (JO) + +3/15/96 (bug fix) Marked standard IO handles of a process as close-on-exec +to fix bug in Ultrix where exec was not sharing standard IO handles with +subprocesses. Fix suggested by Mark Diekhans. (JL) + +3/15/96 (bug fix) Fixed asynchronous close mechanism so that it closes the +channel instead of leaking system resources. The manifestation was that Tcl +would eventually run out of file descriptors if it was handling a large +number of nonblocking sockets or pipes with high congestion. (JL) + +3/15/96 (bug fix) Fixed tests so that they no longer leak file descriptors. +The manifestation was that Tcl would eventually run out of file descriptors +if the tests were rerun many times (> a hundred times on Solaris). (JL) + +3/15/96 (bug fix) Fixed channel creation code so that it never creates +unnamed channels. This would cause a panic and core dump when the channel +was closed. (JL) + +3/16/96 (bug fixes) Made lots of changes in configuration stuff to get +Tcl working under AIX (finally). Tcl should now support the "load" +command under AIX and should work either with or without shared +libraries for Tcl and Tk. (JO) + +3/21/96 (configuration improvement) Changed configure script so it +doesn't use version numbers (as in -ltcl7.5 and libtcl7.5.so) under +SunOS 4.1, where they don't work anyway. (JO) + +3/22/96 (new feature) Added C API Tcl_InterpDeleted that allows extension +writers to discover when an interpreter is being deleted. (JL) + +3/22/96 (bug fix) The standard IO channels are now added to each +trusted interpreter as soon as the interpreter is created. This ensures +against the bug where a child would do IO before the master had done any, +and then the child is destroyed - the standard IO channels would be then +closed and the master would be unable to do any IO. (JL) + +3/22/96 (bug fix) Made Tcl more robust against interpreter deletion, by +using Tcl_Preserve, Tcl_Release and Tcl_EventuallyFree to split the process +of interpreter deletion into two distinct phases. Also went through all of +Tcl and added calls to Tcl_Preserve and Tcl_Delete where needed. (JL) + +3/22/96 (bug fix) Fixed several places where C code was reading and writing +into freed memory, especially during interpreter deletion. (JL) + +3/22/96 (bug fix) Fixed very deep bug in Tcl_Release that caused memory to +be freed twice if the release callback did Tcl_Preserve and Tcl_Release on +the same memory as the chunk currently being freed. (JL) + +3/22/96 (bug fix) Removed several memory leaks that would cause memory +buildup on half-K chunks in the generic IO level. (JL) + +3/22/96 (bug fix) Fixed several core dumps which occurred when new +AssocData was being created during the cleanups in interpreter deletion. +The solution implemented now is to loop repeatedly over the AssocData until +none is left to clean up. (JL) + +3/22/96 (bug fix) Fixed a bug in event handling which caused an infinite +loop if there were no files being watched and no timer. Fix suggested by +Jan Nijtmans. (JL) + +3/22/96 (bug fix) Fixed Tcl_CreateCommand, Tcl_DeleteCommand to be more +robust if the interpreter is being deleted. Also fixed several order +dependency bugs in Tcl_DeleteCommand which kicked in when an interpreter +was being deleted. (JL) + +3/26/96 (bug fix) Upon a "short read", the generic code no longer calls +the driver for more input. Doing this caused blocking on some platforms +even on nonblocking channels. Bug and fix courtesy Mark Roseman. (JL) + +3/26/96 (new feature) Added 'package Tcltest' which is present only in +test versions of Tcl; this allows the testing commands to be loaded into +new interpreters besides the main one. (JL) + +3/26/96 (restored feature) Recreated the Tcl_GetOpenFile C API. You can +now get a FILE * from a registered channel; Unix only. (JL) + +3/27/96 (bug fix) The regular expression code did not support more +than 9 subexpressions. It now supports up to 20. (SS) + +4/1/96 (bug fixes) The CHANNEL_BLOCKED bit was being left on on a short +read, so that fileevents wouldn't fire correctly. Bug reported by Mark +Roseman.(JL, RJ) + +4/1/96 (bug fix) Moved Tcl_Release to match Tcl_Preserve exactly, in +tclInterp.c; previously interpreters were being freed only conditionally +and sometimes not at all. (JL) + +4/1/96 (bug fix) Fixed error reporting in slave interpreters when the +error message was being generated directly by C code. Fix suggested by +Viktor Dukhovni of ESM. (JL) + +4/2/96 (bug fixes) Fixed a series of bugs in Windows sockets that caused +events to variously get lost, to get sent multiple times, or to be ignored +by the driver. The manifestation was blocking if the channel is blocking, +and either getting EAGAIN or infinite loops if the channel is nonblocking. +This series of bugs was found by Ian Wallis of Cisco. Now all tests (also +those that were previously commented out) in socket.test pass. (JL, SS) + +4/2/96 (feature change/bug fix) Eliminated network name support in +favor of better native name support. Added "file split", "file join", +and "file pathtype" commands. See the "file" man page for more +details. (SS) +*** INCOMPATIBILITY with Tcl 7.5b3, but not with Tcl 7.4 *** + +4/2/96 (bug fix) Changed implementation of auto_mkindex so tclIndex +files will properly handle path names in a cross platform context. (SS) + +4/5/96 (bug fix) Fixed Tcl_ReadCmd to use the channel buffer size as the +chunk size it reads, instead of a fixed 4K size. Thus, on large reads, the +user can set the channel buffer size to a large size and the read will +occur orders of magnitude faster. For example, on a 2MB file, reading in 4K +chunks took 34 seconds, while reading in 1MB chunks took 1.5 seconds (on a +SS-20). Problem identified and fix suggested by John Haxby of HP. (JL) + +4/5/96 (bug fix) Fixed socket creation code to invoke gethostbyname only if +inet_addr failed (very unlikely). Before this change the order was reversed +and this made things much slower than they needed to be (gethostbyname +generally requires an RPC, which is slow). Problem identified and fix +suggested by John Loverso of OSF. (JL) + +4/9/96 (feature change) Modified "auto" translation mode so that it +recognizes any of "\n", "\r" and "\r\n" in input as end of line, so +that a file can have mixed end-of-line sequences. It now outputs +the platform specific end of line sequence on each platform for files and +pipes, and for sockets it produces crlf in output on all platforms. (JL) +*** INCOMPATIBILITY with Tcl 7.5b3, but not with Tcl 7.4 *** + +4/11/96 (new feature) Added -eofchar option to Tcl_SetChannelOption to allow +setting of an end of file character for input and output. If an input eof +char is set, it is recognized as EOF and further input from the channel is +not presented to the caller. If an output eof char is set, on output, that +byte is appended to the channel when it is closed. On Unix and Macintosh, +all channels start with no eof char set for input or output. On Windows, +files and pipes start with input and output eof chars set to Crlt-Z (ascii +26), and sockets start with no input or output eof char. (JL) +*** INCOMPATIBILITY with Tcl 7.5b3, but not with Tcl 7.4 *** + +4/17/96 (bug fix) Fixed series of bugs with handling of crlf sequence split +across buffer boundaries in input, in AUTO mode. (JL, BW) + +4/17/96 (test suite improvement) Fixed test suite so that tests that +depend on the availability of Unix commands such as echo, cat and others +are not run if these commands are not present. (JL) + +4/17/96 (test suite improvement) The socket test now automatically starts, +on platformst that support exec, a separate process for remote testsing. (JL) + +----------------- Released 7.5, 4/21/96 ----------------------- + +5/1/96 (bug fix) "file tail ~" did not correctly return the tail +portion of the user's home directory. (SS) + +5/1/96 (bug fix) Fixed bug in TclGetEnv where it didn't lookup environment +variables correctly: could confuse "H" and "HOME", for example. (JO) + +5/1/96 (bug fix) Changed to install tclConfig.sh under "make install-binaries", +not "make install-libraries". (JO) + +5/2/96 (bug fix) Changed pkg_mkIndex not to attempt to "load" a file unless +it has the standard shared library extension. On SunOS, attempts to load +Tcl scripts cause the whole application to be aborted (there's no way to +get the error back into Tcl). (JO) + +5/7/96 (bug fix) Moved initScript in tclUnixInit.c to writable memory to +avoid potential core dumps. (JO) + +5/7/96 (bug fix) Auto_reset procedure was removing procedure from init.tcl, +such as pkg_mkIndex. (JO) + +5/7/96 (bug fix) Fixed cast on socket address resolution code that +would cause a failure to connect on Dec Alphas. (JL) + +5/7/96 (bug fix) Added "time", "subst" and "fileevent" commands to set of +commands available in a safe interpreter. (JL) + +5/13/96 (bug fix) Preventing OS level handles for stdin, stdout and stderr +from being implicitly closed when the last reference to the standard +channel containing that handle is discarded when an interpreter is deleted. +Explicitly closing standard channels by using "close" still works. (JL) + +5/21/96 (bug fix) Do not create channels for stdin, stdout and stderr on +Unix if the devices are closed. This prevents a duplicate channel name +panic later on when the fd is used to open a channel and the channel is +registered in an interpreter. (JL) + +5/23/96 (bug fix) Fixed bug that prevented the use of standard channels in +interpreters created after the last interpreter was destroyed. In the sequence + + interp = Tcl_CreateInterp(); + Tcl_DeleteInterp(interp); + interp = Tcl_CreateInterp(); + +channels for stdio would not be available in the second interpreter. (JL) + +5/23/96 (bug fix) Fixed bug that allowed Tcl_MakeFileChannel to create new +channels with Tcl_Files in them that are already used by another channel. +This would cause core dumps when the Tcl_Files were being freed twice. (JL) + +5/23/96 (bug fix) Fixed a logical timing bug that caused a standard channel +to be removed from the standard channel table too early when the channel +was being closed. If the channel was being flushed asynchronously, it could +get recreated before being actually destroyed, and the recreated channel +would contain the same Tcl_File as the one being closed, leading to +dangling pointers and core dumps. (JL) + +5/27/96 (bug fix) Fixed a bug in Tcl_GetChannelOption which caused it to +always return a list of one element, a list of the settings, for +-translation and -eofchar options. Now correctly returns the value +described by the documentation (Mark Diekhans found this, thanks!). (JL) + +5/30/96 (bug fix) Fixed a couple of syntax errors in io.test. (JL) + +5/30/96 (bug fix) If a fileevent scripts gets an error, delete it before +causing a background error. This is to allow the error handler to reinstall +the fileevent and to prevent infinite loops if the event loop is reentered +in the error handler. (JL) + +5/31/96 (bug fix) Channels now will get properly flushed on exit. (JL) + +6/5/96 (bug fix) Changed Tcl_Ckalloc, Tcl_Ckfree, and Tcl_Ckrealloc to +Tcl_Alloc, Tcl_Free, and Tcl_Realloc. Added documentation for these +routines now that they are officially supported. Extension writers +should use these routines instead of free() and malloc(). (SS) + +6/10/96 (bug fix) Changes the Tcl close command so that it no longer +waits on nonblocking pipes for the piped processes to exit; instead it +reaps them in the background. (JL) + +6/11/96 (bug fix) Increased the length of the listen queue for server +sockets on Unix from 5 to 100. Some OSes will disregard this and reset it +to 5, but we should try to get as long a queue as we can, for performance +reasons. (JL) + +6/11/96 (bug fix) Fixed windows sockets bug that caused a cascade of events +if the fileevent script read less than was available. Now reading less than +is available does not cause a flood of Tcl events. (JL, SS) + +6/11/96 (bug fix) Fixed bug in background flushing on closed channels that +would prevent the last buffer from getting flushed. (JL) + +6/13/96 (bug fix) Fixed bug in Windows sockets that caused a core dump if +a DLL linked with tcl.dll and referred to e.g. ntohs() without opening a +Tcl socket. The problem was that the indirection table was not being +initialized. (JL) + +6/13/96 (bug fix) Fixed OS level resource leak that would occur when a +Tcl channel was still registered in some interpreter when the process +exits. Previously the channel was not being closed and the OS level handles +were not being released; the output was being flushed but the device was +not being closed. Now the device is properly closed. This was only a +problem on Win3.1 and MacOS. (JL, SS) + +6/28/96 (bug fix) Fixed bug where transient errors were leaving an error +code around, so that it would erroneously get reported later. This bug was +exercised intermittently by closing a channel to a file on a very loaded +NFS server, or to a socket whose other end blocked. (JL, BW) + +7/3/96 (bug fix) Fileevents declared in an interpreter are now deleted +when the channel is closed in that interpreter. Before this fix, the +fileevent would hang around until the channel is completely closed, and +would cause errors if events happened before the channel was closed. This +could happen in two cases: first if the channel is shared between several +interpreters, and second if an async flush is in progress that prevents the +channel from being closed until the flush finishes. (JL) + +7/10/96 (bug fix) Fixed bugs in both "lrange" and "lreplace" commands +where too much white space was being removed. For example, the command + lreplace {\}\ hello} end end +was returning "\}\", losing the significant space in the first list +element and corrupting the list. (JO) + +7/20/96 (bug fix) The procedure pkg_mkIndex didn't work properly for +extensions that depend on Tk, because it didn't load Tk into the child +interpreter before loading the extension. Now it loads Tk if Tk is +present in the parent. (JO) + +7/23/96 (bug fix) Added compat version of strftime to fix crashes +resulting from bad implementations under Windows. (SS) + +7/23/96 (bug fix) Standard implementations of gmtime() and localtime() +under Windows did not handle dates before 1970, so they were replaced +with a revised implementation. (SS) + +7/23/96 (bug fix) Tcl would crash on exit under Borland 5.0 because +the global environ pointer was left pointing to freed memory. (SS) + +7/29/96 (bug fix) Fixed memory leak in Tcl_LoadCmd that could occur if +a package's AppInit procedure called Tcl_StaticPackage to register +static packages. (JO) + +8/1/96 (bug fix) Fixed a series of bugs in Windows sockets so that async +writebehind in the presence of read event handlers now works, and so that +async writebehind also works on sockets for which a read event handler was +declared and whose channels were then closed before the async write +finished. The bug was reported by John Loverso and Steven Wahl, +independently, test case supplied by John Loverso. (JL) + +----------------- Released patch 7.5p1, 8/2/96 ----------------------- + +5/8/96 (new feature) Added Tcl_GetChannelMode C API for retrieving whether +a channel is open for reading and writing. (JL) + +5/8/96 (API changes) Revised C APIs for channel drivers: + - Removed all Tcl_Files from channel driver interface; you can now have + channels that are not based on Tcl_Files. + - Added channelReadyProc and watchChannelProc procedures to interface; + these are used to implement event notification for channels. + - Added getFileProc to channel driver, to allow the generic IO code + to retrieve a Tcl_File from a channel (presumably if the channel + uses Tcl_Files they will be stored inside its instanceData). (JL) +*** INCOMPATIBILITY with Tcl 7.5 *** + +5/8/96 (API change) The Tcl_CreateChannel C API was modified to not take +Tcl_File arguments, and instead to take a mask specifying whether the +channel is readable and/or writable. (JL) +*** INCOMPATIBILITY with Tcl 7.5 *** + +6/3/96 (bug fix) Made Tcl_SetVar2 robust against the case where the value +of the variable is a NULL pointer instead of "". (JL) + +6/17/96 (bug fix) Fixed "reading uninitialized memory" error reported by +Purify, in Tcl_Preserve/Tcl_Release. (JL) + +8/9/96 (bug fix) Fixed bug in init.tcl that caused incorrect error message +if the act of autoloading a procedure caused the procedure to be invoked +again. (JO) + +8/9/96 (bug fix) Configure script produced bad library names and extensions +under SunOS and a few other platforms if the --disable-load switch was used. +(JO) + +8/9/96 (bug fix) Tcl_UpdateLinkedVar generated an error if the variable +being updated was read-only. (JO) + +8/14/96 (bug fix) The macintosh now supports synchronous socket +connections. Other minor bugs were also fixed. (RJ) + +8/15/96 (configuration improvement) Changed the file patchlevel.h +to be tclPatch.h. This avoids conflict with the Tk file and is now +in 8.3 format on the Windows platform. (RJ) + +8/20/96 (bug fix) Fixed core dump in interp alias command for interpreters +created with Tcl_CreateInterp (as opposed to with Tcl_CreateSlave). (JL) + +8/20/96 (bug fix) No longer masking ECONNRESET on Windows sockets so +that the higher level of the IO mechanism sees the error instead of +entering an infinite loop. (JL) + +8/20/96 (bug fix) Destroying the last interpreter no longer closes the +standard channels. (JL) + +8/20/96 (bug fix) Closing one of the stdin, stdout or stderr channels and +then opening a new channel now correctly assigns the new channel as the +standard channel that was closed. (JL) + +8/20/96 (bug fix) Added code to unix/tclUnixChan.c for using ioctl with +FIONBIO instead of fcntl with O_NONBLOCK, for those versions of Unix where +either O_NONBLOCK is not supported or implemented incorrectly. (JL) + +8/21/96 (bug fix) Fixed "file extension" so it correctly returns the +extension on files like "foo..c" as "..c" instead of ".c". (SS) + +8/22/96 (bug fix) If environ[] contains static strings, Tcl would core +dump in TclSetupEnv because it was trying to write NULLs into the actual +data in environ[]. Now we instead copy as appropriate. (JL) + +8/22/96 (added impl) Added missing implementation of Tcl_MakeTcpClientChannel +for Windows platform. Code contributed by Mark Diekhans. (JL) + +8/22/96 (new feature) Added a new memory allocator for the Macintosh +version of Tcl. It's quite a bit faster than MetroWerk's version. (RJ) + +8/26/96 (documentation update) Removed old change bars (for all changes +in Tcl 7.5 and earlier releases) from manual entries. (JO) + +8/27/96 (enhancement) The exec and open commands behave better and work in +more situations under Windows NT and Windows 95. Documentation describes +what is still lacking. (CS) + +8/27/96 (enhancement) The Windows makefiles will now compile even if the +compiler is not in the path and/or the compiler's environment variables +have not been set up. (CS) + +8/27/96 (configuration improvement) The Windows resource files are +automatically updated when the version/patch level changes. The header file +now has a comment that reminds the user which other files must be manually +updated when the version/patch level changes. (CS) + +8/28/96 (new feature) Added file manipulation features (copy, rename, delete, +mkdir) that are supported on all platforms. They are implemented as +subcommands to the "file" command. See the documentation for the "file" +command for more information. (JH) + +----------------- Released 7.6b1, 8/30/96 ----------------------- + +9/3/96 (bug fix) Simplified code so that standard channels are created +lazily, they are added to an interpreter lazily, and they are never added +to a safe interpreter. (JL) + +9/3/96 (bug fix) Closing a channel after closing a standard channel, e.g. +stdout, would cause the implicit recreation of that standard channel. (JL) + +9/3/96 (new feature) Now calling Tcl_RegisterChannel with a NULL +interpreter increments the refcount so that code outside any interpreter +can use channels that are also registered in interpreters, without worrying +that the channel may turn into a dangling pointer at any time. Calling +Tcl_UnregisterChannel with a NULL interpreter only decrements the recount +so that code outside any interpreter can safely declare it is no longer +interested in a channel. (JL) + +9/4/96 (new features) Two changes to dynamic loading: + - If the file name is empty in the "load" command and there is no + statically loaded version of the package, a dynamically loaded + version will be used if there is one. + - Tcl_StaticPackage ignores redundant calls for the same package. (JO) + +9/6/96 (bug fix) Platform specific procedures for manipulating files are +no longer macros and have been prefixed with "Tclp", such as TclpRenameFile. +Unix file code now handles symbolic links and other special files correctly. +The semantics of file copy and file rename has been changed so that if +a target directory exists, the source files will NOT be merged with the +existing files. (JH) + +9/6/96 (bug fix) If standard channel is NULL, because Tcl cannot connect +to the standard channel, do not increment the refcount. The channel can +be NULL if there is for example no standard input. (JL) + +9/6/96 (portability improvement) Changed parsing of backslash sequences +like \n to translate directly to absolute values like 0xa instead of +letting the compiler do the translation. This guarantees that the +translation is done the same everywhere. (JO) + +9/9/96 (bug fix) If channel is opened and not associated with any +interpreter, but Tcl decides to use it as one of the standard channels, it +became impossible to close the channel with Tcl_Close -- instead you had +to call Tcl_UnregisterChannel. Fixed now so that it's safe to call +Tcl_Close even when Tcl is using the channel as one of the standard ones. (JL) + +9/11/96 (feature change) The Tcl library is now placed in the Tcl +shared libraries resource. You no longer need to place the Tcl files +in your applications explicitly. (RJ) + +9/11/96 (feature change) Extensions no longer automatically have the +resource fork of the extension opened for it. Instead you need to +use the tclMacLibrary.c file in your extension. (RJ) +*** POTENTIAL INCOMPATIBILITY *** + +9/12/96 (bug fix) The extension loading mechanism on the Macintosh now +looks at the 'cfrg' resource to determine where to load the code +fragment from. This means FAT fragments should now work. (RJ) + +9/18/96 (enhancement) The exec and open commands behave better and work in +more situations under Windows 3.X. Documentation describes what is still +lacking. (CS) + +9/19/96 (bug fix) Fixed a panic which would occur if you delete a +non-existent alias before any aliases are created. Now instead correctly +returns an error that the alias is not found. (JL) + +9/19/96 (bug fix) Slave interpreters could rename aliases and they would +not get deleted when the alias was being redefined. This led to dangling +pointers etc. (JL) + +9/19/96 (bug fix) Fixed a panic where a hash table entry was being deleted +twice during alias management operations. (JL) + +9/19/96 (bug fix) Fixed bug in event loop that could cause the input focus +in Tk to get confused during menu traversal, among other problems. The +problem was related to handling of the "marker" when its event was +deleted. (JO) + +9/26/96 (bug fix) Windows was losing EOF on a socket if the FD_CLOSE event +happened to precede any left over FD_READ events. Now correctly remembers +seeing FD_CLOSE, so that trailing FD_READ events are not discarded if they +do not contain any data. This allows Tcl to correctly get a zero read and +notice EOF. (JL) + +9/26/96 (bug fix) Was not resetting READABLE state properly on sockets +under Windows if the driver discarded an FD_READ event because no data was +present. Now correctly resets the state. (JL) + +9/30/96 (bug fix) Made EOF sticky on Windows sockets, so that fileevent +readable will fire repeatedly until the socket is closed. Previously the +fileevent fired only once. This could lead to never-closed connections if +the Tcl script in the fileevent wasn't closing the socket immediately. (JL) + +10/2/96 (new feature) Improved the package loader: + - Added new variable tcl_pkgPath, which holds the default + directories under which packages are normally installed (each + package goes in a separate subdirectory of a directory in + $tcl_pkgPath). These directories are included in auto_path by + default. + - Changed the package auto-loader to look for pkgIndex.tcl files + not only in the auto_path directories but also in their immediate + children. This should make it easier to install and uninstall + packages (don't have to change auto_path or merge pkgIndex.tcl + files). (JO) + +10/3/96 (bug fix) Changed tclsh to look for tclshrc.tcl instead of +tclsh.rc on startup under Windows. This is more consistent with wish and +uses the right extension. (SS) +*** POTENTIAL INCOMPATIBILITY *** + +10/8/96 (bug fix) Convertclock does not parse 24-hour times of the +form "hhmm" correctly when hour = 00. In the parse code, hour must be +>= 100 for minutes to be non-zero. Thanks to Lint LaCour for this +bug fix. (RJ) + +10/11/96 (bug fix) Under Windows, the pid command returned the process +handle instead of the process id. (SS) + +----------------- Released 7.6, 10/16/96 ----------------------- + +10/29/96 (bug fix) Under Windows, sockets would consume 100% CPU time after +the first accept(), due to a typo. (JL) + +10/29/96 (bug fix) Incorrect refcount management caused standard channels +not to get deleted at process exit or DLL unload time, causing a memory +leak of upwards of 20K each time. (JL) + +11/7/96 (bug fix) Auto-exec didn't work on file names that contained +spaces. (JO) + +11/8/96 (bug fix) Fixed core dump that would occur if more than one call +to Tcl_DeleteChannelHandler was made to delete a given channel handler. (JL) + +11/8/96 (bug fix) Fixed test for return value in Tcl_Seek and Tcl_SeekCmd +to only treat -1 as error, instead of all negative numbers. (JL) + +11/12/96 (bug fix) Do not blocking waiting for processes at the end of a +pipe during exit cleanup. (JL) + +11/12/96 (bug fix) If we are in exit cleanup, do not close the system level +file descriptors 0, 1 and 2. Previously they were being closed which is +incorrect, in the embedded case. This led to weird behavior for programs +that want to interpose on I/O through the standard file descriptors (e.g. +Netscape Navigator). (JL) + +11/15/96 (bug fix) Fixed core dump on Windows sockets due to dependency on +deletion order at exit. Now all socket functions check to see if sockets +are (still) initialized, before calling through function pointers. Before, +they would call and might end up calling unloaded object code. (JL) + +11/15/96 (bug fix) Fixed core dump in Windows socket initialization routine +if sockets were not installed on the system. Before, it was not properly +checking the result of attempting to load the socket DLL, so it would call +through uninitialized function pointers. (JL) + +11/15/96 (bug fix) Fixed memory leak in Windows sockets which left socket +DLL handle open and could hold the socket DLL in memory uneccessarily, +until a reboot. (JL) + +12/4/96 (bug fix) Fixed bug in Macintosh socket code that could result +in lost data if a client was closed too soon after sending data. (RJ) + +12/17/96 (bug fix) Fixed deadlock bug in Windows sockets due to losing an +event. This was happening because of an interaction between buffering and +nonblocking mode on sockets. Now switched to sockets being blocking by +default, so we are also no longer emulating blocking through a private +event loop. (JL) + +1/21/97 (performance bug fix) Client TCP connections were slow to create +because getservbyname was always called on the port. Now this is only +done if Tcl_GetInt fails. (BW) + +1/21/97 (configuration fix) Made it possible to override TCL_PACKAGE_PATH +during make. Previously it was only set during autoconf process. + +1/29/97 (bug fix) Fixed some problems with the clock command that +impacted how dates were scaned after the year 2000. (RJ) + +----------------- Released 7.6p2, 1/31/97 ----------------------- + +2/5/97 (bug fix) Fixed a bug where in CR-LF translation mode, \r bytes +in the input stream were not being handled correctly. (JL) + +2/24/97 (bug fix) Fix bug with exec under Win32s not being able to create +stderr file which caused all execs to fail. Fixed temp file leak under +Win32s. Fixed optional parameter bug with SearchPath that only happened +under Win32s 1.25. (CCS) + +---------------------------------------------------------- +Changes for Tcl 7.6 go above this line. +Changes for Tcl 7.7 go below this line. +---------------------------------------------------------- + +5/8/96 (new feature) Added Tcl_Ungets C API for putting a sequence of bytes +into a channel's input buffer. This can be used for "push" model channels +where the input is obtained via callbacks instead of by request of the +generic IO code. No Tcl procedure yet. (JL) + +11/15/96 (new feature) Implemented hidden commands. New C APIs: + Tcl_HideCommand -- hides an existing exposed command. + Tcl_ExposeCommand -- exposes an existing hidden command. +New tcl APIs: + interp invokehidden -- invokes a hidden command in a slave. + interp hide -- hides an existing exposed command. + interp expose -- exposes an existing hidden command. + interp hidden -- returns a list of hidden commands. +The implementation of Safe Tcl now uses the new hidden commands facility +to implement the safe base, instead of deleting the commands from a safe +interpreter. (JL) + +11/15/96 (new feature) Implemented the safe base, a mechanism for +installing and requesting security policies, purely in Tcl code. Overloads +the package command to also allow an interpreter to "require" a policy. The +following new library commands are provided: + tcl_safeCreateInterp -- creates a slave an initializes the + policy mechanism. + tcl_safeInitInterp -- initializes an existing slave with the + policy mechanism. + tcl_safeDeleteInterp -- deletes a slave and deinitializes the + policy mechanism. +Added a new file to the library, safeinit.tcl, to hold implementation. (JL) +On 7/9/97, removed the policy loading mechanism from the Safe Base. Left +only the Safe Base aliases dealing with auto-loading and source. (JL) + +12/6/96 (new feature) Implemented Tcl_Finalize, an API that should be +called by a process when it is done using Tcl. This API runs all the exit +handlers to allow them to clean up resources etc. (JL) + +12/17/96 (new feature) Add an http Tcl script package to the Tcl library. +This package implements the client side of HTTP/1.0; the GET, HEAD, +and POST requests. (BW) + +1/21/97 (new feature) Added a "marktrusted" subcommand to the "interp" and +to the interpreter object command. It removes the "safe" mark on an +interpreter and disables hard-wired checks for safety in the C sources. (JL) + +1/21/97 (removed feature) Removed "vwait" from set of commands available in +a safe interpreter. (JL) + +2/11/97 (new feature, bug fix) http package. Added -accept to http_config +so you can set the Accept header. Added -handler option to http_get so +you can supply your own data handler. Also fixed POST operation to +set the correct MIME type on the request. (BW) + +---------------------------------------------------------- +Changes for Tcl 7.7 go above this line. +Changes for Tcl 8.0 go below this line. +---------------------------------------------------------- + +9/17/96 (bug fix) Using "upvar" it was possible to turn an array element +into an array itself. Changed to disallow this; it was quirky and didn't +really work correctly anyway. (JO) + +10/21/96 (new feature) The core of the Tcl interpreter has been replaced +with an on-the-fly compiler that translates Tcl scripts to bytecoded +instructions; a new interpreter then executes the bytecodes. The compiler +introduces only a few minor changes at the level of Tcl scripts. The biggest +changes are to expressions and lists. + - A second level of substitutions is no longer done for expressions. + This substantially improves their execution time. This means that + the expression "$x*4" produces a different result than in the past + if x is "$y+2". Fortunately, not much code depends on the old + two-level semantics. Some expressions that do, such as + "expr [join $list +]" can be recoded to work in Tcl8.0 by adding + an eval: e.g., "eval expr [join $list +]". + - Lists are now completely parsed on the first list operation to + create a faster internal representation. In the past, if you had a + misformed list but the erroneous part was after the point you + inserted or extracted an element, then you never saw an error. + In Tcl8.0 an error will be reported. This should only effect + incorrect programs that took advantage of behavior of the old + implementation that was not documented in the man pages. +Other changes to Tcl scripts are discussed in the web page at +http://www.scriptics.com/doc/compiler.html. (BL) +*** POTENTIAL INCOMPATIBILITY *** + +10/21/96 (new feature) In earlier versions of Tcl, strings were used as a +universal representation; in Tcl 8.0 strings are replaced with Tcl_Obj +structures ("objects") that can hold both a string value and an internal +form such as a binary integer or compiled bytecodes. The new objects make it +possible to store information in efficient internal forms and avoid the +constant translations to and from strings that occurred with the old +interpreter. There are new many new C APIs for managing objects. Some of the +new library procedures for objects (such as Tcl_EvalObj) resemble existing +string-based procedures (such as Tcl_Eval) but take advantage of the +internal form stored in Tcl objects for greater speed. Other new procedures +manage objects and allow extension writers to define new kinds of objects. +See the manual entries doc/*Obj*.3 (BL) + +10/24/96 (bug fix) Fixed memory leak on exit caused by some IO related +data structures not being deallocated on exit because their refcount was +artificially boosted. (JL) + +10/24/96 (bug fix) Fixed core dump in Tcl_Close if called with NULL +Tcl_Channel. (JL) + +11/19/96 (new feature) Added library procedures for finding word +breaks in strings in a platform specific manner. See the library.n +manual entry for more information. (SS) + +11/22/96 (feature improvements) Added support for different levels of +tracing during bytecode compilation and execution. This should help in +tracking down suspected problems with the compiler or with converting +existing code to use Tcl8.0. Two global Tcl variables, traceCompile +and traceExec, can be set to generate tracing information in stdout: + - traceCompile: 0 no tracing (default) + 1 trace compilations of top level commands and procs + 2 trace and display instructions for all compilations + - traceExec: 0 no tracing + 1 trace only calls to Tcl procs + 2 trace invocations of all commands including procs + 3 detailed trace showing the result of each instruction +traceExec >= 2 provides a one line summary of each called command and +its arguments. Commands that have been "compiled away" such as set are +not shown. (BL) + +11/30/96 (bug fix) The command "info nameofexecutable" could sometimes +return the name of a directory. (JO) + +11/30/96 (feature improvements) Changed the code in library/init.tcl +that reads in pkgIndex.tcl so that (a) it reads the files from child +directories before those in the parent, so that the parent gets +precedence, and (b) it doesn't quit if there is an error in a +pkgIndex.tcl file; instead, it prints an error message on standard +error and continues. (JO) + +10/5/96 (feature improvements) Partial implementation of binary string +support: the ability for Tcl string values to contain embedded null bytes. +Changed the Tcl object-based APIs to take a byte pointer and length pair +instead of a null-terminated C string. Modified several object type managers +to support binary strings but not, for example, the list type manager. +Existing string-based C APIs are unchanged and will truncate binary +strings. Compiled scripts containing nulls are also truncated. (BL) + +12/12/96 (feature change) Removed the commands "cp", "mkdir", "mv", +"rm", and "rmdir" from the Macintosh version of Tcl. They were never +officially supported and their functionality is now available via +the file command. (RJ) + +----------------- Released 8.0a1, 12/20/96 ----------------------- + +1/7/97 (bug fix) Under Windows, "file stat c:" was returning error instead +of stat for current dir on c: drive. + +1/10/97 (new feature) Added Tcl_GetIndexFromObj procedure for quick +lookups of keyword arguments. (JO) + +1/12/97 (new feature) Serial IO channel drivers for Windows and Unix, +available by using Tcl open command to open pseudo-files like "com1:" or +"/dev/ttya". New option to Tcl fconfigure command for serial files: +"-mode baud,parity,data,stop" to specify baud rate, parity, data bits, and +stop bits. Serial IO is not yet available on Mac. + +1/16/97 (feature change) Restored the Tcl7.x "two level substitution +semantics" for expressions. Expressions not enclosed in braces are +implemented, in general, by calling the expr command procedure +(Tcl_ExprObjCmd) at runtime after the Tcl interpreter has already done a +first round of substitutions. This is slow (about Tcl7.x speed) because new +code for the expression is generally compiled each time. However, if the +expression has only variable substitutions (and not command substitutions), +"optimistic" fast code is generated inline. This inline code will fail if a +second round of substitutions is needed (i.e., if the value of a substituted +variable itself requires more substitutions). The optimistic code will +catch the error and back off to call the slower but guaranteed correct +expr command procedure. (BL) + +1/16/97 (feature improvements) Added Tcl_ExprLongObj and Tcl_ExprDoubleObj +to round out expression-related procedures. (BL) + +1/16/97 (feature change) Under Windows, at startup the environment variables +"path", "comspec", and "windir" in any capitalization are converted +automatically to upper case. The PATH variable could be spelled as path, +Path, PaTh, etc. and it makes programming rather annoying. All other +environment variables are left alone. (CS) + +1/20/97 (new features) Rewrote the "lsort" command: + - The new version is based on reentrant merge sort code provided + by Richard Hipp, so it eliminates the reentrancy and stability + problems with the old qsort-based implementation. + - The new version supports a -dictionary option for sorting, and + it also supports a -index option for sorting lists using one + element for comparison. + - The new version is an object command, so it works well with the + Tcl compiler, especially in conjunction with the new -index + option. When the -index option is used, this version of lsort + is more than 100 times faster than the Tcl 7.6 lsort, which had + to use the -command option to get the same effect. (JO) + +1/20/97 (feature improvements) Added the improved debugging support for Tcl +objects prototyped by Karl Lehenbauer . +If TCL_MEM_DEBUG is defined, the object creation calls use Tcl_DbCkalloc +directly in order to record the caller's source file name and line +number. (BL) + +1/21/97 (removed feature) Desupported the tcl_precision variable: if +set, it is ignored. Tcl now uses the full 17 digits of precision when +converting real numbers to strings (with the new object system real +numbers are rarely converted to strings so there is no efficiency +disadvantage to printing all 17 digits; the new scheme improves +accuracy and simplifies several APIs). (JO) +*** POTENTIAL INCOMPATIBILITY *** + +1/21/97 (feature change) Removed the "interp" argument for the +procedures Tcl_GetStringFromObj, Tcl_StringObjAppend, and +Tcl_StringObjAppendObj. Also removed the "interp" argument for +the updateStringProc procedure in Tcl_ObjType structures. With +the tcl_precision changes above, these are no longer needed. (JO) +*** POTENTIAL INCOMPATIBILITY with Tcl 8.0a1, but not with Tcl 7.6 *** + +1/22/97 (bug fix) Fixed http.tcl so that http_reset does not result in +an extra call to the command callback. In addition, if the transaction +gets a premature eof, the state(status) is "eof", not "ok". (BW) + +----------------- Released 8.0a2, 1/24/97 ----------------------- + +1/29/97 (feature change) Changed how two digit years are parsed in the +clock command. The old interface just added 1900 which will seem +broken by the year 2000. The new scheme follows the POSIX standard +and treats dates 70-99 as 1970-1999 and dates 00-38 as 2000-2038. All +other two digit dates are undefined. (RJ) +*** POTENTIAL INCOMPATIBILITY *** + +2/4/97 (bug fix) Fixed bug in clock code that dealt with relative +dates. Using the relative month code you could get an invalid date +because it jumped into a non-existant day. (For example, Jan 31 +to Feb 31.) The code now will return the last valid day of the +month in these situations. Thanks to Hume Smith for sending in +this bug fix. (RJ) + +2/10/97 (feature change) Eliminated Tcl_StringObjAppend and +Tcl_StringObjAppendObj procedures, replaced them with Tcl_AppendToObj +and Tcl_AppendStringsToObj procedures. Added new procedure +Tcl_SetObjLength. (JO) +*** POTENTIAL INCOMPATIBILITY with Tcl 8.0a2, but not with Tcl 7.6 *** + +2/10/97 (new feature) Added Tcl_WrongNumArgs procedure for generating +error messages about incorrect number of arguments. (JO) + +2/11/97 (new feature, bug fix) http package. Added -accept to http_config +so you can set the Accept header. Added -handler option to http_get so +you can supply your own data handler. Also fixed POST operation to +set the correct MIME type on the request. (BW) + +2/22/97 (bug fix) Fixed bug that caused $tcl_platform(osVersion) to be +computed incorrectly under AIX. (JO) + +2/25/97 (new feature, feature change) Added support for both int and long +integer objects. Added Tcl_NewLongObj/Tcl_GetLongFromObj/Tcl_SetLongFromObj +procedures and renamed the Tcl_Obj internalRep intValue member to +longValue. Tcl_GetIntFromObj now checks for integer values too large to +represent as non-long integers. Changed Tcl_GetAllObjTypes to +Tcl_AppendAllObjTypes. (BL) + +3/5/97 (new feature) Added new Tcl_SetListObj procedure to round out +collection of procedures that set the type and value of existing Tcl +objects. (BL) + +3/6/97 (new feature) Added -global flag for interp invokehidden. (JL) + +3/6/97 (new feature, feature change) Added isNativeObjectProc field to the +Tcl_CmdInfo structure to indicate (when 1) if the command has an +object-based command procedure. Removed the nameLength arg from +Tcl_CreateObjCommand since command names can't contain null characters. (BL) + +3/6/97 (bug fix) Fixed bug in "unknown" procedure that caused auto- +loading to fail on commands whose names begin with digits. (JO) + +3/7/97 (bug fix) Auto-loading now works in Safe Base. Safe interpreters +only accept the Version 2 and onwards tclIndex files. (JL) + +3/13/97 (bug fix) Fixed core dump due to interaction between aliases and +hidden commands. Bug found by Lindsay Marshall. (JL) + +3/14/97 (bug fix) Fixed mac bugs relating to time. The -gmt option +now adjusts the time in the correct direction. (Thanks to Ed Hume for +reporting a fix to this problem.) Also fixed file "mtime" etc. to +return times from GMT rather than local time zone. (RJ) + +3/18/97 (feature change) Declaration of objv in Tcl_ObjCmdProc function +changed from "Tcl_Obj *objv[]" to "Tcl_Obj *CONST objv[]". All Tcl object +commands changed to use new declaration of objv. Naive translation of +string-based command procs to object-based command procs could very easily +have yielded code where the contents of the objv array were changed. This +is not a problem with string-based command procs, but doing something as +simple as objv[2] = objv[3] would corrupt the runtime stack and cause Tcl to +crash. Introduced CONST in declaration of objv so that attempted assignment +of new pointer values to elements of the objv array will be caught by the +compiler. (CCS) +*** POTENTIAL INCOMPATIBILITY with Tcl 8.0a2 *** + +3/19/97 (bug fix) Fixed panic due to object sharing. The root cause was +that old code was using Tcl_ResetResult instead of Tcl_ResetObjResult. (JL) + +3/20/97 (new feature) Added a new subcommand for the file +command. file attributes filename can give a list of platform-specific +options (such as file/creator type on the Mac, permissions on Unix) or +set the values of them. Added a new subcommand for the file +command. file nativename name gives back the platform-specific form +for the file. This is useful when the filename is needed to pass to +the OS, such as exec under Windows 95 or AppleScript on the Mac. For +more info, see file.n. (SRP) + +3/24/97 (removed feature) Removed the tcl_safePolicyPath procedure. Now +the policy path is computed from the auto_path by appending the directory +'policies' to each element. Also fixed several bugs in automatic tracking +of auto_path by computed policy path. (JL) +*** POTENTIAL INCOMPATIBILITY with Tcl 8.0a2 but not with Tcl 7.6 *** + +4/8/97 (new feature) If the variable whose name is passed to lappend doesn't +already exist, and there are no value arguments, lappend now creates the +variable with an empty value instead of returning an error. Change suggested +by Tom Tromey. (BL) + +4/9/97 (feature change) Changed the name of the TCL_PART1_NOT_PARSED flag to +TCL_PARSE_PART1. (BL) +*** POTENTIAL INCOMPATIBILITY with Tcl 8.0a2 but not with Tcl 7.6 *** + +4/10/97 (bug fixes) Fixed various compilation-related bugs: + - "UpdateStringOfCmdName should never be invoked" panic. + - Bad code generated for expressions not in {}'s inside catch commands. + - Segmentation fault in some command procedures when two argument + object pointers refer to the same object. + - Second level of substitutions were never done for expressions not + in {}'s that consist of a single variable reference: e.g., + "set x 27; set bool {$x}; if $bool {puts foo}" would fail with error. + - Bad code generated when code storage was grown while compiling some + expressions: ones with compilation errors or consisting of only a + variable reference. + - Bugs involving multiple interpreters: wasn't checking that a + procedure's code was compiled for the same interpreter as the one + executing it, and didn't invalidate code on hidden-exposed command + transitions. + - "Bad stack top" panic when executing scripts that require a huge + amount of stack space. + - Incorrect sharing of code for procedure bodies, and procedure code + deallocated before last execution of the procedure finished. + - Fixed compilation of expression words in quotes. For example, + if "0 < 3" {puts foo}. + - Fixed performance bug in array set command with large assignments. + - Tcl_SetObjLength segmentation fault setting length of empty object. + - If Tcl_SetObjectResult was passed the same object as the interpreter's + result object, it freed the object instead of doing nothing. Bug fix + by Michael J. McLennan. + - Tcl_ListObjAppendList inserted elements from the wrong list. Bug fix + by Michael J. McLennan. + - Segmentation fault if empty variable list was specified in a foreach + command. Bug fix by Jan Nijtmans. + - NULL command name was always passed to Tcl_CreateTrace callback + procedure. + - Wrong string representation generated for the value LONG_MIN. + For example, expr 1<<31 printed incorrectly on a 32 bit machine. + - "set {a($x)} 1" stored value in wrong variable. + - Tcl_GetBooleanFromObj was not checking for garbage after a numeric + value. + - Garbled "bad operand type" error message when evaluating expressions + not surrounded by {}'s. (BL) + +4/16/97 (new feature) The expr command now has the "rand()" and +"srand()" functions for getting random numbers in expr. (RJ) + +4/23/97 (bug fix) Fixed core dump in bgerror when the error handler command +deletes the current interpreter. Found by Juergen Schoenwald. (JL) + +4/23/97 (feature change) The notifier interfaces have been redesigned +to make embedding in applications with external event loops possible. +A number of interfaces in the notifier and the channel drivers have +changed. Refer to the Notifier.3 and CrtChannel.3 manual entries for +more details. (SS) +*** POTENTIAL INCOMPATIBILITY *** + +4/23/97 (removed feature) The Tcl_File interfaces have been removed. +The Tcl_CreateFileHandler/Tcl_DeleteFileHandler interfaces now take +Unix fd's and are only supported on the Unix platform. +Tcl_GetChannelFile has been replaced with Tcl_GetChannelHandle. +Tcl_MakeFileChannel now takes a platform specific file handle. (SS) +*** POTENTIAL INCOMPATIBILITY *** + +4/23/97 (removed feature) The modal timeout interface has been +removed (Tcl_CreateModalTimeout/Tcl_DeleteModalTimeout) (SS) +*** POTENTIAL INCOMPATIBILITY *** + +4/23/97 (feature change) Channel drivers are now required to correctly +implement blocking behavior when they are in blocking mode. (SS) +*** POTENTIAL INCOMPATIBILITY *** + +4/23/97 (new feature) Added the "binary" command for manipulating +binary strings. Also, changed the "puts", "gets", and "read" commands +to preserve embedded nulls. (SS) + +4/23/97 (new feature) Added tcl_platform(byteOrder) element to the +tcl_platform array to identify the native byte order for the current +host. (SS) + +4/23/97 (bug fix) Fixed bug in date parsing around year boundaries. (SS) + +4/24/97 (bug fix) In the process of copying a file owned by another user, +Tcl was changing the owner of the copy back to the owner of the original +file, therefore causing further file operations to fail because the current +user didn't own the copy anymore. The owner of the copy is now left as the +current user. (CCS) + +4/24/97 (feature change) Under Windows, don't automatically uppercase the +environment variable "windir" -- it's supposed to be lower case. (CCS) + +4/29/97 (new feature) Added namespace support based on a namespace +implementation by Michael J. McLennan of Lucent Technologies. A namespace +encapsulates a collection of commands and variables to ensure that they +won't interfere the commands and variables of other namespaces. The global +namespace holds all global variables and commands. Additional namespaces are +created with the new namespace command. The new variable command lets you +create Tcl variables inside a namespace. The names of Tcl variables and +commands may now be qualified by the name of the namespace containing them. +The key namespace-related commands are summarized below: + - namespace ?eval? name arg ?arg...? + Used to define the commands and variables in a namespace. + Optionally creates the namespace. + - namespace export ?-clear? ?pattern pattern...? + Specifies which commands are exported from a namespace. These + are the ones that can be imported into another namespace. + - namespace import ?-force? ?pattern pattern...? + Makes the specified commands accessible in the current namespace. + - namespace current + Returns the name of the current namespace. + - variable name ?value? ?name ?value?...? + Creates one or more namespace variables. (BTL) + +5/1/97 (bug fix) Under Windows, file times were reported in GMT. Should be +reported in local time. (CCS) + +5/2/97 (feature change) Changed the name of the two Tcl variables used for +tracing bytecode compilation and execution to tcl_traceCompile and +tcl_traceExec respectively. These variables are now documented in the +tclvars man page. (BL) + +5/5/97 (new feature) Support "end" as the index for "lsort -index". (BW) + +5/5/97 (bug fixes) Cleaned up the way the http package resets connections (BW) + +5/8/97 (feature change) Newly created Tcl objects now have a reference count +of zero instead of one. This simplifies C code that stores newly created +objects in Tcl variables or in data structures such as list objects. That C +code must increment the new object's reference count since the variable or +data structure will contain a long-term reference to the object. Formerly, +when new objects started out with reference count one, it was necessary to +decrement the new object's reference count after the store to make sure it +was left with the correct value; this is no longer necessary. (BL) + +5/9/97 (new feature) Added the Tcl_GetsObj interface that takes an +object reference instead of a dynamic string (as in Tcl_Gets). (SS) + +5/12/97 (new feature) Added Tcl_CreateAliasObj and Tcl_GetAliasObj C APIs +to allow an alias command to be created with a vector of Tcl_Obj structures +and to get the vector back later. (JL) + +5/12/97 (feature change) Changed Tcl_ExposeCommand and Tcl_HideCommand to +leave an object result instead of a string result. (JL) + +5/14/97 (feature change) Improved the handling of the interpreter result. +This is still either an object or a string, but the two values are now kept +consistent unless some C code reads or writes interp->result directly. See +the SetResult man page for details. Removed the Tcl_ResetObjResult +procedure. (BL) +*** POTENTIAL INCOMPATIBILITY with Tcl 8.0a2 *** + +5/16/97 (new feature) Added "fcopy" command to move data between +channels. Refer to the manual page for more information. Removed the +"unsupported0" command since it is obsolete now. (SS) + +5/16/97 (new feature) Added Tcl_GetStringResult procedure to allow programs +to get an interpreter's result as a string. If the result was previously set +to an object, this procedure will convert the object to a string. Use of +Tcl_GetStringResult is intended to replace direct access to interp->result, +which is not safe. (BL) + +5/20/97 (new features) Fixed "fcopy" to return the number of bytes +transferred in the blocking case. Updated the http package to use +fcopy instead of unsupported0. Added -timeout and -handler options to +http_get. http_get is now blocking by default. It is only non-blocking +if you supply a -command argument. (BW) + +5/22/97 (bug fix) Fixed several bugs in the "lsort" command having to do +with the -dictionary option and the presence of numbers embedded in the +strings. (JO) + +----------------- Released 8.0b1, 5/27/97 ----------------------- + +6/2/97 (bug fix) Fixed bug in startup code that caused a problem in +finding the library files when they are installed in a directory +containing a space in the name. (SS) + +6/2/97 (bug fix) Fixed bug in Unix notifier where the select mask was +not being cleared under some circumstances. (SS) + +6/4/97 (bug fix) Fixed bug that prevented creation of Tk widgets in +namespaces. Tcl_CreateObjCommand and Tcl_CreateCommand now always create +commands in the global namespace unless the command names are qualified. Tcl +procedures continue to be created in the current namespace by default. (BL) + +6/6/97 (new features) Added new namespace API procedures +Tcl_AppendExportList and Tcl_Export to allow C code to get and set a +namespace's export list. (BL) + +6/11/97 (new feature) Added Tcl_ConcatObj. This object-based routine +parallels the string-based routine Tcl_Concat. (SRP) + +6/11/97 (new feature) Added Tcl_SetObjErrorCode. This object-based +routines parallels the string-based routine Tcl_SetErrorCode. (SRP) + +6/12/97 (bug fix) Fix the "unknown" procedure so that wish under Windows +will exec an external program, instead of always complaining "console1 not +opened for writing". (CCS) + +6/12/97 (bug fix) Fixed core dump experienced by the following simple +script: + interp create x + x alias exec exec + interp delete x +This panic was caused by not installing the new CmdDeleteProc when exec +got redefined by the alias creation step. Reported by Lindsay Marshal (JL) + +6/13/97 (new features) Tcl objects newly created by Tcl_NewObj now have a +string representation that points to a shared heap string of length 1. (They +used to have NULL bytes and typePtr fields. This was treated as a special +case to indicate an empty string, but made type manager implementations +complex and error prone.) The new procedure Tcl_InvalidateStringRep is used +to mark an object's string representation invalid and to free any storage +associated with the old string representation. (BL) +*** POTENTIAL INCOMPATIBILITY with Tcl 8.0b1, but not with Tcl7.6 *** + +6/16/97 (bug fix) Tcl_ScanCountedElement could leave braces unmatched +if the string ended with a backslash. (JO) + +6/17/97 (bug fix) Fixed channel event bug where readable events would be +lost during recursive events loops if the input buffers contained +data. (SS) + +6/17/97 (bug fix) Fixed bug in Windows socket code that didn't +reenable read events in the case where an external entity is also +reading from the socket. (SS) + +6/18/97 (bug fix) Changed initial setting of the notifier service mode +to TCL_SERVICE_NONE to avoid unexpected event handling during +initialization. (SS) + +6/19/97 (bug fix/feature change) The command callback to fcopy is now +called in case of errors during the background copy. This adds a second, +optional argument to the callback that is the error string. The callback +in case of errors is required for proper cleanup by the user of fcopy. (BW) +*** POTENTIAL INCOMPATIBILITY with Tcl 8.0b1, but not with Tcl 7.6 *** + +6/19/97 (bug fix) Fixed a panic due to the following four line script: + interp create x + x alias foo bar + x eval rename foo blotz + x alias foo {} +The problem was that the interp code was not using the actual current name +of the command to be deleted as a result of un-aliasing foo. (JL) + +6/19/97 (feature change) Pass interp down to the ChannelOption and +driver specific calls so system errors can be differentiated from syntax +ones. Changed Tcl_DriverGetOptionProc type. Affects Tcl_GetChannelOption, +TcpGetOptionProc, TtyGetOptionProc, etc. (DL) +*** POTENTIAL INCOMPATIBILITY *** + +6/19/97 (new feature) Added Tcl_BadChannelOption for use by by driver +specific option procedures (Set and Get) to return a complete and +meaningful error message. (DL) + +6/19/97 (bug fixes) If a system call error occurs while doing an +fconfigure on tcp or tty/com channel: return the appropriate error +message (instead of the syntax error one or none). (Fixed for Unix and +most of the Win and Mac drivers). (DL) + +6/20/97 (feature change) Eval is no longer assumed as the subcommand name +in namespace commands: you must now write "namespace eval nsName {...}". +Abbreviations of namespace subcommand names are now allowed. (BL) +*** POTENTIAL INCOMPATIBILITY with Tcl 8.0b1, but not with Tcl7.6 *** + +6/20/97 (feature change) Changed the errorInfo traceback message for +compilation errors from "invoked from within" to "while compiling". (BL) + +6/20/97 (bug fixes) Fixed various compilation-related bugs: + - "UpdateStringOfCmdName should never be called" and + "UpdateStringOfByteCode should never be called" panics. + - Segfault in TclObjInterpProc getting procedure name after evaluation + stack is reallocated (grown). + - Could not use ":" at end of variable and command names. + - Bad code generated for while and for commands with test expressions + enclosed in quotes: e.g., "set i 0; while "$i > 5" {}". + - Command trace procedures would crash if they did a Tcl_EvalObj that + reallocated the evaluation stack. + - Break and continue commands did not reset the interpreter result. + - The Tcl_ExprXXX routines, both string- or object-based, always + modified the interpreter result even if there was no error. + - The argument parsing procedure used by several compile procedures + always treated "]" as end of a command: e.g., "set a ]" would fail. + - Changed errorInfo traceback message for compilation errors from + "invoked from within" to "while compiling". + - Problem initializing Tcl object managers during interpreter creation. + - Added check and error message if formal parameter to a procedure is + an array element. (BL) + +6/23/97 (new feature) Added "registry" package to allow manipulation +of the Windows system registry. See manual entry for details. (SS) + +6/24/97 (feature change) Converted http to a package and added the +http1.0 subdirectory of the Tcl script library. This means you have +to do a "package require http" to use this, as advertised in the man page. (BW) +*** POTENTIAL INCOMPATIBILITY with Tcl 8.0b1, but not with Tcl 7.6 *** + +6/24/97 (bug fix) Ensure that Tcl_Set/GetVar C APIs, when called without +TCL_LEAVE_ERR_MSG, don't touch the interp result. (DL) + +6/26/97 (feature change) Changed name of Tcl_ExprStringObj to +Tcl_ExprObj. (BL) +*** POTENTIAL INCOMPATIBILITY with Tcl 8.0b1, but not with Tcl 7.6 *** + +----------------- Released 8.0b2, 6/30/97 ----------------------- + +7/1/97 (new feature) TCL_BUILD_SHARED flag set in tclConfig.sh +when Tcl has been built with --enable-shared. A new tclLibObjs +make target, echoing the list of the .o's needed to build a tcl +library, is now provided. (DL) + +7/1/97 (feature change) compat/getcwd.c removed and changed the +only place where getcwd is used so a new USEGETWD flag selects +the use of the replacement "getwd". Adding this flag is recommended +for SunOS 4 (because getcwd on SunOS 4 uses a pipe to pwd(1)!). (DL) + +7/7/97 (feature change) The split command now supports binary data (i.e., +null characters in strings). (BL) + +7/7/97 (bug fix) string first returned the wrong result if the first +argument string was empty. (BL) + +7/8/97 (bug fix) Fixed core dump in fcopy that could occur when a command +callback was supplied and an error or eof condition caused no background +activity. A refcount bug triggered a panic in Tcl_ListObjAppendElement. (BW) + +7/8/97 (bug fix) Relaxed the pattern matching on http_get so you do not +need a trailing path component. You can now get away with just +http_get www.scriptics.com (BW) + +7/9/97 (bug fix) Creating anonymous interpreters no longer smashes existing +commands with names similar to the generated name. Previously creating an +anonymous interpreter could smash an existing command, now it skips until +it finds a command name that isn't being used. (JL) + +7/9/97 (feature change) Removed the policy management mechanism from the +Safe Base; left the aliases to source and load modules, and to do a limited +form of the "file" command. See entry of 11/15/96. (JL) + +7/9/97 (bug fixes) Fixed various compilation-related bugs: + - Line numbers in errorInfo now are the same as those in Tcl7.6 unless +there are compilation errors. Compilation error messages now include the +entire command in error. + - Trailing ::s after namespace names weren't being ignored. + - Could not refer to an namespace variable with an empty name using a +name of the form "n::". (BL) + +7/9/97 (bug fix) Fixed bug in Tcl_Export that prevented you from exporting +from other than the current namespace. (BL) + +7/9/97 (bug fix) env.test was removing env var needed for proper finding +of libraries in child process. (DL) + +7/10/97 (bug fixes/new feature) Cleanup in Tcl_MakeSafe. Less information +is leaked to safe interps. Error message fixes for interp sub commands. +Likewise changes in safealias.tcl; tcl_safeCreateInterp can now be called +without argument to generate the slave name (like in interp create). (DL) + +7/10/97 (bug fixes) Bytecode compiler now generates more detailed +command location information: subcommands as well as commands now have +location information. This means command trace procedures now get the +correct source string for each command in their command parameter. (BL) + +7/22/97 (bug fixes) Performance improvement in Safe interpreters +handling. Added new mask value to (tclInt.h) Interp.flags record. (DL) + +7/22/97 (bug fix) Fixed panic in 'interp target {} foo'. This bug +was present since Tcl 7.6. (JL) + +7/22/97 (bug fix) Fixed bug in compilation of procedures in namespaces: the +procedure's namespace must be used to look up compile procedures, not the +current namespace. (BL) + +7/22/97 (bug fix) Use of the -channel option of http_get was not setting +the end of line translations mode on the channel, so copying binary data +with the -channel option was corrupting the result on non-unix platforms. (BW) + +7/22/97 (bug fixes) file commands and ~user (seg fault and other +improper returns). (DL) + +7/23/97 (feature change) Reenabled "vwait" in Safe Base. (JL) + +7/23/97 (bug fixes) Fixed two bugs involving read traces on array variables +in procedures: trace procedures were sometimes not called, and reading +nonexistant array elements didn't create undefined element variables that +could later be defined by trace procedures. (BL) + +7/24/97 (bug fix) Windows memory allocation performance was +superlinear in some cases. Made the Mac allocator generic and changed +both the Mac and Windows platforms to use the new allocator instead of +malloc and free. (SS) + +7/24/97 - 8/12/97 (bug fixes/change of features) Completely revamped safe +sourcing/loading (see safe.n) to hide pathnames, use virtual +paths tokens instead, improved security in several respects and made it +more tunable. Multi level interp loading can work too now. Package auto +loading now works in safe interps as long as the package directory is in +the auto_path (no deep crawling allowed in safe interps). (DL) +*** POTENTIAL INCOMPATIBILITY with previous alpha and beta releases *** + +7/24/97 (bug fixes) Made Tcl_SetVar* and Tcl_NewString* treat a NULL value +as an empty string. (This fixes hairy crash case where you would crash +because load command for other interps assumed presence of +errorInfo...). (DL) + +7/28/97 (bug fix) Fixed pkg_mkIndex to understand namespaces. It will +use the export list of a namespace and create auto_index entries for +all export commands. Those names are in their fully qualified form in the +auto_index. Therefore, I tweaked unknown to try both $cmd and ::$cmd. +Also fixed pkg_mkIndex so you can have "package require" commands inside +your packages. These commands are ignored, which is mostly ok except +when you must load another package before loading yours because of +linking dependencies. (BW) + +7/28/97 (bug fix) A variable created by the variable command now persists +until the namespace is destroyed or the variable is unset. This is true even +if the variable has not been initialized; these variables used to be +destroyed if an error occurred when accessing them. In addition, the "info +vars" command lists uninitialized namespace variables, while the "info +exists" command returns 0 for them. (BL) + +7/29/97 (feature change) Changed the http package to use the ::http +namespace. http_get renamed to http::geturl, http_config renamed to +http::config, http_formatQuery renamed to http::formatQuery. +It now provides the 2.0 version of the package. +The 1.0 version is still available with the old names. +*** POTENTIAL INCOMPATIBILITY with Tcl 8.0b2 but not with Tcl 7.6 *** + +7/29/97 (bug fix, new feature) Tcl_Main now uses Tcl objects internally to +preserve NULLs in commands and command output. Added new API procedure +Tcl_RecordAndEvalObj that resembles Tcl_RecordAndEval but takes an object +containing a command. (BL) + +7/30/97 (bug fix) Tcl freed strings in the environ array even if it +did not allocate them. (SS) + +7/30/97 (bug fix) If a procedure is renamed into a different namespace, it +now executes in the context of that namespace. (BL) + +7/30/97 (bug fix) Prevent renaming of commands into and from namespaces as +part of hiding them. (JL) + +7/31/97 (feature change) Moved the history command from C to tcl. +This uses the ::history namespace. The "words" and "substitute" options +are no longer supported. In addition, the "keep" option without a value +returns the current keep limit. There is a new "clear" option. +The unknown command now supports !! again. (BW) +*** POTENTIAL INCOMPATIBILTY *** + +7/30/97 (bug fix) Made sure that a slave can not fool the master into +hiding the wrong command. Made sure we don't crash in hiding + namespaces +issues. (DL) + +8/4/97 (bug fix) Concat, eval, uplevel, and similar commands were +incorrectly trimming trailing space characters from their arguments +even when the space characters were preceded by a backslash. (JO) + +8/4/97 (bug fix) Removed the hard link between bgerror and tkerror. +Only bgerror is supported in tcl core. Tk will still look for a +tkerror but using regular tcl code for that feature. (DL) +*** POTENTIAL INCOMPATIBILTY with code relying on the hard link *** + +8/6/97 (bug fix) Reduced size required for compiled bytecodes by using a +more compact encoding for the command pc-to-source map. (BL) + +8/6/97 (new feature) Added support for additional compilation and execution +statistics when Tcl is compiled with the TCL_COMPILE_STATS flag. (BL) + +8/7/97 (bug fix) Expressions not in {}s that have a comparison operator as +the topmost operator must be compiled out-of-line (call the expr cmd at +runtime) to properly support expr's two-level substitution semantics. An +example is "set a 2; set b {$a}; puts [expr $b == 2]". (BL) + +8/11/97 (bug fix) The catch command would sometimes crash if a variable name +was given and the bytecode evaluation stack was grown when executing the +argument script. (BL) + +8/12/97 (feature change) Reinstated the variable tcl_precision to control +the number of digits used when floating-point values are converted to +strings, with default of 12 digits. However, had to make tcl_precision +shared among all interpreters (except that safe interpreters can't +modify it). This makes the Tcl 8.0 behavior almost identical to 7.6 +except that the default precision is 12 instead of 6. (JO) +*** POTENTIAL INCOMPATIBILITY *** + +----------------- Released 8.0, 8/18/97 ----------------------- + +8/19/97 (bug fix) Minimal fix for glob -nocomplain bugs: +"glob -nocomplain unreadableDir/*" was generating an anonymous +error. More in depth fixes will come with 8.1. (DL). + +8/20/97 (bug fix) Removed check for FLT_MIN in binary command so +underflow conditions are handled by the compiler automatic +conversions. (SS) + +8/20/97 (bug fixes) Fixed several compilation-related bugs: + - Array cmd wasn't detecting arrays that, while compiled, do not yet + exist (e.g., are marked undefined since they haven't been assigned + to yet). + - The GetToken procedure in tclCompExpr.c wasn't recognizing properly + whether an integer token was invalid. For example, "0x$" is not + a valid integer. + - Performance bug in TclExecuteByteCode: the size of its stack frame + was reduced by over 20% by moving errorInfo code elsewhere. + - Uninitialized memory read error in tclCompile.c. (BL) + +8/21/97 (bug fix) safe::interpConfigure now behave like Tk widget's +configure : it changes only the options you provide and you can get +the current value of any single option. New ?-nested boolean? and +?-statics boolean? for all safe::interp* commands but we still +accept (upward compatibility) the previously defined non valued +flags ?-noStatics? and ?-nestedLoadOk?. Improved the documentation. (DL). + +8/22/97 (bug fix) Updated PrintDbl.3 to reflect the fact that the +tcl_precision variable is still used and that it is now shared by all +interpreters. (BL) + +8/25/97 (bug fix) Fixed array access bug in IllegalExprOperandType +procedure in tclExecute.c: it was not properly supporting the || and && +operators. (BL) + +8/27/97 (bug fix) In cases where a channel handler was created with an +empty event mask while data was still buffered in the channel, the +channel code would get stuck spinning on a timer that would starve +idle handlers. This mostly happened in Tk when reading from stdin. (SS) + +9/4/97 (bug fix) Slave interps now inherit the maximum recursion limit +of their parent instead of starting back at the default. {nb: this still +does not prevent stack overflow by multi-interps recursion or aliasing} (DL) + +9/11/97 (bug fix) An uninitialized variable in Tcl_WaitPid caused +pipes to fail to report eof properly under Windows. (SS) + +9/12/97 (bug fix) "exec" was misidentifying some DOS executables as not +executable. (CCS) + +9/14/97 (bug fix) Was using the wrong structure in sizeof operation in +tclUnixChan.c. (JL) + +9/15/97 (bug fix) Fixed notifier to break out of do-one-event loop if +Tcl_WaitForEvent returns 1, so that callers of Tcl_DoOneEvent will get +a chance to check whether the event just handled is significant. This +affected mainly recursive calls to Tcl_VWaitCmd; these did not get a +chance to notice that the variable they were waiting for has been set +and thus they didn't terminate the vwait. (JL, DL, SS) + +9/15/97 (bug fix) Alignment problems in "binary format" would cause a +crash on some platforms when formatting floating point numbers. (SS) + +9/15/97 (bug fix) Fixed bug in Macintosh socket code. Now passes all +tests in socket.test that are not platform specific. (Thanks to Mark +Roseman for the pointer on the fix.) (RJ) + +9/18/97 (bug fix) Fixed bug -dictionary option of lsort that could +cause the compare function to run off the end of an array if the +number only contained 0's. (Thanks to Greg Couch for the report.) (RJ) + +9/18/97 (bug fix) TclFinalizeEnvironment was not cleaning up +properly. (DL, JI) + +9/18/97 (bug fix) Fixed long-standing bug where an "array get" command +did not trigger traces on the array or its elements. (BL) + +9/18/97 (bug fixes) Fixed compilation-related bugs: + - Fixed errorInfo traceback information for toplevel coomands that + contain nested commands. + - In the expr command, && and || now accept boolean operands as well + as numeric ones. (BL) + +9/22/97 (bug fix) Fixed bug that prevented translation modes from being +set independently for input and output on sockets if input was "auto". (JL) + +9/24/97 (bug fix) Tcl_EvalFile(3) and thus source(n) now works fine on +files containing NUL chars. (DL) + +9/26/97 (bug fix) Fixed use of uninitialized memory in the environ array +that later could cause random core dumps. Applies to all platforms. (JL) + +9/26/97 (bug fix) Fixed use of uninitialized memory in socket address data +structure under some circumstances. This could cause random core dumps. +This applies only to Unix. (JL) + +9/26/97 (bug fix) Opening files on PC-NFS volumes would cause a hang +until the system timed after the file was closed. (SS) + +10/6/97 (bug fix) The join(n) command, though objectified, was loosing +NULs in the joinString and in list elements after the 2nd one. +Now you can "join $list \0" for instance. (DL) + +10/9/97 (bug fix) Under windows, if env(TMP) or env(TEMP) referred to a +non-existent directory, exec would fail when trying to create its temporary +files. (CCS) + +10/9/97 (bug fix) Under mac and windows, "info hostname" would crash if +sockets were installed but the hostname could not be determined anyhow. +Tcl_GetHostName() was returning NULL when it should have been returning +an empty string. (CCS) + +10/10/97 (bug fix) "file attribute /" returned error on windows. (CCS) + +10/10/97 (bug fix) Fixed the auto_load procedure to handle procedures +defined in namespaces better. Also fixed pgk_mkIndex so it sees procedures +defined in nested namespaces. Index entries are still only made for +exported procedures. (BW) + +10/13/97 (bug fix) On unix, for files with unknown group or owner +attributes, querying the "file attributes" would return an error rather than +returning the group's or owner's id number, although tha command accepts +numbers when setting the file's group or owner. (CCS) + +10/22/97 (bug fix) "fcopy" did not eval the callback script at the +global scope. (SS) + +10/22/97 (bug fix) Fixed the signature of the CopyDone callback used in +the http package(s) so they can handle error cases properly. (BW) + +10/28/97 (bug fixes) Fixed a problem where lappend would free the Tcl object +in a variable if a Tcl_ObjSetVar2 failed because of an error calling a trace +on the variable. (BL) + +10/28/97 (bug fix) Changed binary scan to properly handle sign +extension of integers on 64-bit or larger machines. (SS) + +11/3/97 (bug fixes) Fixed several bugs: + - expressions such as "expr ($x)" must be compiled out-of-line + (call the expr command procedure at runtime) to ensure the correct + behavior when "$x" is an expression such as "5+10". + - "array set a {}" now creates a new array var with an empty array + value if the var didn't already exist. + - "lreplace $foo end end" no longer returns an error (just an empty + list) if foo is empty. + - upvar will no longer create a variable in a namespace that refers + to a variable in a procedure. + - deleting a command trace within a command trace callback would + make the code that calls traces to reference freed memory. + - significantly sped up "string first" and "string last" (fix from + darrel@gemstone.com). + - seg fault in Tcl_NewStringObj() when a NULL is passed as the byte + pointer argument and Tcl is compiled with -DTCL_MEM_DEBUG. + - documentation and error msg fixes. (BL) + +11/3/97 (bug fix) Fixed a number of I/O bugs related to word sizes on +64-bit machines. (SS) + +11/6/97 (bug fix) The exit code of the first process created by Tcl +on Windows was not properly reported due to an initialization +problem. (SS) + +----------------- Released 8.0p1, 11/7/97 ----------------------- + +11/19/97 (bug fix) Fixed bug in linsert where it sometimes accidently +cleared out a shared argument list object. (BL). + +11/19/97 (bug fix) Autoloading in namespaces was not working properly. +auto_mkindex is still not really namespace aware but most common +cases should now be handled properly (see init.test). (BW, DL) + +11/20/97 (enhancement) Made the changes required by the new Apple +Universal Headers V.3.0, so that Tcl will compile with CW Pro 2. + +11/24/97 (bug fix) Fixed tests in clock test suite that needed the +-gmt flag set. Thanks to Jan Nijtmans for reporting the problem. (RJ) + +----------------- Released 8.0p2, 11/25/97 ----------------------- + +12/3/97 (bug fix/optimization) Removed uneeded and potentially dangerous +instances of double evaluations if "if" and "expr" statements from +the library files. It is recommended that unless you need a double +evaluation you always use "expr {...}" instead of "expr ..." and +"if {...} ..." instead of "if ... ...". It will also be faster +thanks to the byte compiler. (DL) + +---- Shipped as part of the plugin2.0b5 as 8.0p2Plugin1, Dec 8th 97 ---- + +12/8/97 (bug fix) Need to protect the newly accepted channel in an +accept callback on a socket, otherwise the callback may close it and +cause an error, which would cause the C code to attempt to close the +now deleted channel. Bumping the refcount assures that the channel sticks +around to be really closed in this case. (JL) + +12/8/97 (bug fix) Need to protect the channel in a fileevent so that it +is not deleted before the fileevent handler returns. (CS, JL) + +12/18/97 (bug fix) In the opt argument parsing package: if the description +had only flags, the "too many arguments" case was not detected. The default +value was not used for the special "args" ending argument. (DL) + +1/15/98 (improvement) Moved common part of initScript in common file. +Moved windows specific initialization to init.tcl so you can initialize +Tcl in windows without having to call Tcl_Init which is now only +searching for init.tcl {back ported from 8.1}. (DL) + +---- Shipped as part of the plugin as 8.0p2Plugin2, Jan 15th 98 ---- + +5/27/98 (bug fix) Windows socket driver did not notice new data arriving +on nonblocking sockets until the event loop was entered. (SS) + +5/27/98 (bug fix) Windows socket driver used FIONREAD, which is not +supported correctly by WinSock. (SS) + +6/9/98 (bug fix) Generic channel code failed to report readable file +events on buffered data that was left behind by a gets or read that +did not consume all available data. (SS) + +6/18/98 (bug fix) Compilation of loop expressions was too aggressive +and incorrectly inlined non-literal expressions. (SS) + +6/18/98 (bug fix) "info var" and "info locals" incorrectly reported +the existence of compiler temporary variables. (SS) + +6/18/98 (bug fix) Dictionary sorting used signed character +comparisons. (SS) + +6/18/98 (bug fix) Compile procs corrupted the exception stack in some +cases. (SS) + +6/18/98 (bug fix) Array set had erratic behavior when initializing a +variable from an empty value list. (SS) + +6/18/98 (bug fix) The Windows registry package had a bad bounds check +that could lead to a crash. (SS) + +6/18/98 (bug fix) The foreach compile proc did not correctly handle +non-local variable references. (SS) + +6/25/98 (new features) Added name resolution hooks to support [incr Tcl]. +There are new internal Tcl_*Resolver* APIs to add, query and remove the hooks. +With this changes it should be possible to dynamically load [incr Tcl] +as an extension. (MM) + +7/1/97 (bug fix) The commands "info args, body, default, procs" did +not correctly handle imported procedures. (RJ) + +7/6/98 (improvement) pkg_mkIndex now implements the "package require" +command. This makes it possible to create index files for packages +that require another package and then execute code from that package in +their file. Previously, this would throw an error because the required +package had not been loaded. The -nopkgrequied flag is provided to +revert back to the old functionality. (EMS) + +7/6/98 (improvement) back-ported the -direct flag from 8.1 into +pkg_mkIndex. This results in pkgIndex.tcl files that contain direct +source or load commands instead of tclPkgSetup commands. (EMS) + +7/6/98 (improvement) made changes to the AuxData items structures to support +storage of compiled scripts on disk. Also some related minor changes in +the compilation and execution engine. (EMS) + +6/4/98 (enhancement) Added new internal routines to support inserting +and deleting from the stat, access, and open-file-channel mechanisms. +TclAccessInsertProc, TclStatInsertProc, & TclOpenFileChannelInsertProc +insert pointers to such routines; TclAccessDeleteProc, TclStatDeleteProc, +& TclOpenFileChannelDeleteProc delete pointers to such routines. See +the file generic/tclIOUtils.c for more details. (SKS) + +7/1/98 (enhancement) Added a new internal C variable +tclPreInitScript. This is a pointer to a string that may hold an +initialization script; If this pointer is non-NULL it is evaluated in +Tcl_Init() prior to the built-in initialization script defined in the +file generic/tclInitScript.h. (SKS) + +7/6/98 (bug fix) Removed dead code in PlatformInitExitHandler so that +the TCL_LIBRARY value can be safely patched in binaries. (BW) + +7/24/98 (enhancement) Incorporated a new version of auto_mkindex that +can support the [incr Tcl] class structures. This version will index +all procedures in a source file, not just those where "proc" starts +at the beginning of the line. If you want the old behavior, use the +auto_mkindex_old procedure. (MM) + +7/24/98 (feature change) Changed the Windows registry key to be +HKEY_LOCAL_MACHINE\Software\Scriptics\Tcl\8.0, and to store the path +in the default value instead of "Root". Also, this key can be +specified at compile time in case Tcl is being used in a different +context where it needs an alternate library path from the standard Tcl +installation. (SS) + +7/24/98 (feature change) Changed the search order for init.tcl. The +tcl_library variable can now be set before calling Tcl_Init to avoid +doing any searches. If it isn't set, then Tcl checks +env(TCL_LIBRARY), the static value set at compile time, an install +directory relative to the executable, a source directory relative to +the executable, and a tcl directory relative to the source heirarchy +containing the executable. See the comment at the top of +generic/tclInitScript.h for more details. (SS) + +7/27/98 (config change) Changed the use of the DBGX flag in configure.in +and the makefile to be TCL_DBGX. Users of tclConfig.sh may need to pass +this through their configure files with AC_SUBST. (BW) + +729/98 (bug fix) Changed [info body] to return a copy of the body of a +compiled procedure instead of the body itself, to avoid invalidation +of the internal rep and loss of the byte-codes. (EMS) + +8/5/98 (bug fix) The platform init code could walk off the end of a +buffer when reading the PkgPath registry value on Windows. (SS) + +8/5/98 (Windows makefile change) Introduced a set of macros to deal with +exporting symbols when compiling DLLS on Windows. See win/README for +details. (EMS) + +8/5/98 (addendum) Added a second Windows registry key under +HKEY_LOCAL_MACHINE\Software\Scriptics\Tcl\8.0, named "pkgPath". +This is a multi-string value used to initialize the tcl_pkgPath +variable. This is required if extension DLLs are in architecture specific +subdirectories. (SS) + +8/6/98 (new feature) Added tcl_findLibrary to init.tcl for use by +extensions, including Tk. This searches in a canonical way for +an extensions library directory and initialization file. (BW) + +8/10/98 (bug fix) Imported commands used to get lost if the target +of the import was redefined. Tcl_CreateCommand and Tcl_CreateObjCommand +were updated to restore import links. (Note that if you rename a command, +the import links move to the new name, and if you delete a command then +the import links get lost. These semantics have not changed.) (MC) + +-------- Released 8.0.3 to the Tcl Consortium CD-ROM project, 8/10/98 ------ + +9/3/98 (bug fix) Tcl_Realloc was failing under Windows because the +GlobalReAlloc API was not correctly re-allocating blocks that were +32k+. The fix was to use newer Win32 APIs (HeapAlloc, HeapFree, and +HeapReAlloc.) (BS) + +10/5/98 (bug fix) Fixed bug in pkg_mkIndex that caused some files that do +a "package require" of packages in the Tcl libraries to give a warning like + warning: "xx.tcl" provides more than one package ({xx 2.0} {yy 0.3}) +and generate a broken pkgIndex.tcl file. (EMS) + +10/5/98 (bug fix) Pkg_mkIndex was not doing a case-insensitive comparison +of extensions to determine whether to load or source a file. Thus, under +Windows, MYDLLNAME.DLL was sourced, and mydllname.dll loaded. (EMS) + +10/5/98 (new feature) Created a new Tcl_Obj type, "procbody". This object's +internal representation holds a pointer to a Proc structure. Extended +TclCreateProc to take both strings and "procbody". (EMS) + +10/13/98 (bug fix) The "info complete" command can now handle strings +with NULLs embedded. Thanks to colin@field.medicine.adelaide.edu.au +for providing this fix. (RJ) + +10/13/98 (bug fix) The "lsort -dictionary" command did not properly +handle some numbers starting with 0. Thanks to Richard Hipp + for submitting the fix to Scriptics. (RJ) + +10/13/98 (bug fix) The function Tcl_SetListObj was creating an invalid +Tcl_Obj if the list had zero elements (despite what the comments said +it would do). Thanks to Sebastian Wangnick for reporting the +problem. (RJ) + +10/20/98 (new feature) Added tcl_platform(debug) element to the +tcl_platform array on Windows platform. The existence of the debug +element of the tcl_platform array indicates that the particular Tcl +shell has been compiled with debug information. Using +"info exists tcl_platform(debug)" a Tcl script can direct the +interpreter to load debug versions of DLLs with the load +command. (SKS) + +10/20/98 (feature change) The Makefile and configure scripts have been +changed for IRIX to build n32 binaries instead of the old 32 abi +format. If you have extensions built with the o32 abi's you will need +to update them to n32 for them to work with Tcl. (RJ) +*** POTENTIAL INCOMPATIBILITY *** + +10/23/98 (bug fix) tcl_findLibrary had a stray ] in one of the +pathnames it searched for the initialization script. tclInitScript.h +was incorrectly adding the parent of tcl_library to tcl_pkgPath. This +logic was moved into init.tcl, and the initialization of auto_path was +documented. Thanks to Donald Porter and Tom Silva for related +patches. (BW) + +10/29/98 (bug fix) Fixed Tcl_NotifyChannel to use Tcl_Preserve instead +of Tcl_RegisterChannel so that 1) unregistered channels do not get +closed after their first fileevent, and 2) errors that occur during +close in a fileevent script are actually reflected by the close +command. (BW) + +10/30/98 (bug fix) Overhaul of pkg_mkIndex to deal with transitive +package requires and packages split among scripts and binary files. +Also fixed ommision of global for errorInfo in tcl_findLibrary. (BW) + +11/08/98 (bug fix) Fixed the resource command to always detect +the case where a file is opened a second time with the same +permissions. IM claims that this will always cause the same +FileRef to be returned, but in MacOS 8.1+, this is no longer the case, +so we have to test for this explicitly. (JI) + +11/10/98 (feature change) When compiling with Metrowerk's MSL, use the +exit function from MSL rather than ExitToShell. This allows MSL to +clean up its temporary files. Thanks to Vince Darley for this +improvement. (JI) + +----------------- Released 8.0.4, 11/19/98 ------------------------- + +11/20/98 (bug fix) Handle possible NULL return in TclGetStdFiles. (RJ) + +11/20/98 (bug fix) The dltests would not build on SGI. They reported +that you could not mix n32 with 032 binaries. The configure script +has been modified to get the EXTRA_CFLAGS from the tcl configure +script. [Bug id: 840] (RJ) + +12/3/98 (bug fix) Windows NT creates sockets so they are inheritable +by default. Fixed socket code so it turns off this bit right after +creation so sockets aren't kept open by exec'ed processes. [Bug: 892] +Thanks to Kevin Kenny for this fix. (SS) + +1/11/98 (bug fix) On HP, "info sharedlibextension" was returning +empty string on static apps. It now always returns ".sl". (RJ) + +1/28/99 (configure change) Now support -pipe option on gcc. (RJ) + +2/2/99 (bug fix) Fixed initialization problem on Windows where no +searching for init.tcl would be performed if the registry keys were +missing. (stanton) + +2/2/99 (bug fix) Added support for HKEY_PERFORMANCE_DATA and +HKEY_DYN_DATA keys in the "registry" command. (stanton) + +2/2/99 (bug fix) ENOTSUP and EOPNOTSUPP clashed on some Linux +variants. (stanton) + +2/2/99 (enhancement) The "open" command has been changed to use the +object interfaces. (stanton) + +2/2/99 (bug fix) In some cases Tcl would crash due to an overflow of +the exception stack resulting from a missing byte code in some +expressions. (stanton) + +2/2/99 (bug fix) Changed configure so Linux and IRIX shared libraries +are linked with the system libraries. (stanton) + +2/2/99 (bug fix) Added support for BSDI 4.x (BSD/OS-4*) to the +configure script. (stanton) + +2/2/99 (bug fix) Fixed bug where upvar could resurrect a namespace +variable after the namespace had been deleted. (stanton) + +2/2/99 (bug fix) In some cases when creating variables, the +interpreter result was being modified even if the TCL_LEAVE_ERR_MSG +flag was set. (stanton) + +2/2/99 (bug fix & new feature) Changed the socket drivers to properly +handle failures during an async socket connection. Added a new +fconfigure option "-error" to retrieve the failure message. See the +socket.n manual entry for details. (stanton) + +2/2/99 (bug fix) Deleting a renamed interp alias could result in a +panic. (stanton) + +2/2/99 (feature change/bug fix) Changed the behavior of "file +extension" so that it splits at the last period. Now the extension of +a file like "foo..o" is ".o" instead of "..o" as in previous versions. +*** POTENTIAL INCOMPATIBILITY *** + +----------------- Released 8.0.5, 3/9/99 ------------------------- + +======== Changes for 8.0 go above this line ======== +======== Changes for 8.1 go below this line ======== + +6/18/97 (new feature) Tcl now supports international character sets: + - All C APIs now accept UTF-8 strings instead of iso8859-1 strings, + wherever you see "char *", unless explicitly noted otherwise. + - All Tcl strings represented in UTF-8, which is a convenient + multi-byte encoding of Unicode. Variable names, procedure names, + and all other values in Tcl may include arbitrary Unicode characters. + For example, the Tcl command "string length" returns how many + Unicode characters are in the argument string. + - For Java compatibility, embedded null bytes in C strings are + represented as \xC080 in UTF-8 strings, but the null byte at the end + of a UTF-8 string remains \0. Thus Tcl strings once again do not + contain null bytes, except for termination bytes. + - For Java compatibility, "\uXXXX" is used in Tcl to enter a Unicode + character. "\u0000" through "\uffff" are acceptable Unicode + characters. + - "\xXX" is used to enter a small Unicode character (between 0 and 255) + in Tcl. + - Tcl automatically translates between UTF-8 and the normal encoding for + the platform during interactions with the system. + - The fconfigure command now supports a -encoding option for specifying + the encoding of an open file or socket. Tcl will automatically + translate between the specified encoding and UTF-8 during I/O. + See the directory library/encoding to find out what encodings are + supported (eventually there will be an "encoding" command that + makes this information more accessible). + - There are several new C APIs that support UTF-8 and various encodings. + See Utf.3 for procedures that translate between Unicode and UTF-8 + and manipulate UTF-8 strings. See Encoding.3 for procedures that + create new encodings and translate between encodings. See + ToUpper.3 for procedures that perform case conversions on UTF-8 + strings. + +9/18/97 (enhancement) Literal objects are now shared by the ByteCode +structures created when compiled different scripts. This saves up to 45% +of the total memory needed for all literals. (BL) + +9/24/97 (bug fixes) Fixed Tcl_ParseCommand parsing of backslash-newline +sequences at start of command words. Suppressed Tcl_EvalDirect error logging +if non-TCL_OK result wasn't an error. (BL) + +10/17/97 (feature enhancement) "~username" now refers to the users' home +directory on Windows (previously always returned failure). (CCS) + +10/20/97 (implementation change) The Tcl parser has been completely rewritten +to make it more modular. It can now be used to parse a script without actually +executing it. The APIs for the new parser are not correctly exported, but +they will eventually be exported and augmented with Tcl commands so that +Tcl scripts can parse other Tcl scripts. (JO) + +10/21/97 (API change) Added "flags" argument to Tcl_EvalObj, removed +Tcl_GlobalEvalObj procedure. Added new procedures Tcl_Eval2 and +Tcl_EvalObjv. (JO) +*** POTENTIAL INCOMPATIBILITY *** + +10/22/97 (API change) Renamed Tcl_ObjSetVar2 and Tcl_ObjGetVar2 to +Tcl_SetObjVar2 and Tcl_GetObjVar2 (for consistency with other C APIs) +and changed the name arguments to be strings instead of objects. (JO) +*** POTENTIAL INCOMPATIBILITY *** + +10/27/97 (enhancement) Bytecode compiler rewritten to use the new Tcl +parser. (BL) + +11/3/97 (New routines) Added Tcl_AppendObjToObj, which appends the +string rep of one Tcl_Obj to another. Added Tcl_GetIndexFromObjStruct, +which is similar to Tcl_GetIndexFromObj, except that you can give an +offset between strings. This allows Tcl_GetIndexFromObjStruct to be +called with a table of records which have strings in them. (SRP) + +12/4/97 (enhancement) New Tcl expression parser added. Added new procedure +Tcl_ParseExpr and new token types TCL_TOKEN_SUB_EXPR and +TCL_TOKEN_OPERATOR. Expression compiler is reimplemented to use this +parser. (BL) + +12/9/97 (bug fix) Tcl_EvalObj() increments/decrements the refcount of the +script object to prevent the object from deleting itself while in the +middle of being evaluated. (CCS) + +12/9/97 (bug fix) Memory leak in Tcl_GetsObjCmd(). (CCS) + +12/11/97 (bug fix) Environment array leaked memory when compiled with +Visual C++. (SS) + +12/11/97 (bug fix) File events and non-blocking I/O did not work on +pipes under Windows. Changed to use threads to achieve non-blocking +behavior. (SS) + +12/18/97 (bug fixes) Fixed segfault in "namespace import"; importing a +procedure that causes a cycle now returns an error. Modified "info procs", +"info args", "info body", and "info default" to return information about +imported procedures as well as procedures defined in a namespace. (BL) + +12/19/97 (enhancement) Added new Tcl_GetString() procedure that can be used +in place of Tcl_GetStringFromObj() if the string representation's length +isn't needed. (BL) + +12/18/97 (bug fix) In the opt argument parsing package: if the description +had only flags, the "too many arguments" case was not detected. The default +value was not used for the special "args" ending argument. (DL) + +1/7/98 (clean up) Moved everything not absolutly necessary out of init.tcl +procs now in auto.tcl and package.tcl can be autoloaded if needed. (DL) + +1/7/98 (enhancement) tcltest made at install time will search for it's +init.tcl where it is, even when using virtual path compilation. (DL) + +1/8/98 (os bug workaround) when needed, using a replacement for memcmp so +string compare "char with high bit set" "char w/o high bit set" returns +the expected value on all platforms. (DL) + +1/8/98 (unix portability/configure) building from .../unix/targetName/ +subdirectories and simply using "../configure" should now work fine. (DL) + +1/14/98 (enhancement) Added new regular expression package that +supports AREs, EREs, and BREs. The new package includes new escape +characters, meta-syntax, and character classes inside brackets. +Regexps involving backslashes may behave differently. (MH) +*** POTENTIAL INCOMPATIBILITY *** + +1/16/98 (os workaround) Under windows, "file volume" was causing chatter +and/or several seconds of hanging when querying empty floppy drives. +Changed implementation to call an empirically-derived function that doesn't +cause this. (CCS) + +1/16/98 (enhancement) Converted regular expressions to a Tcl_Obj type so +their compiled form gets cached automatically. Reduced NSUBEXP from 100 +to 20. (BW) + +1/16/98 (documentation) Change unclear documentation and comments for +functions like Tcl_TranslateFileName() and Tcl_ExternalToUtfDString(). Now +it explicitly says they take an uninitialized or free DString. A DString +that is "empty" or "not holding anything" could have been interpreted as one +currently with a zero length, but with a large dynamically allocated buffer. +(CCS) + +----------------- Released 8.1a1, 1/22/98 ----------------------- + +1/28/98 (new feature) Added a "-direct" optional flag to pkg_mkIndex +to generate direct loading package indexes (such those you need +if you use namespaces and plan on using namespace import just after +package require). pkg_mkIndex still has limitations regarding +package dependencies but errors are now ignored and with -direct, correct +package indexes can be generated even if there are dependencies as long +as the "package provide" are done early enough in the files. (DL) + +1/28/98 (enhancement) Performance tuning of regexp and regsub. (CCS) + +1/28/98 (bug fix) regexp and regsub with "-indices" returned the byte-offsets +of the characters in the UTF-8 representation, not the character offsets +themselves. (CCS) + +1/28/98 (bug fix) "clock format 0 -format %Z -gmt 1" would return the local +timezone string instead of "GMT" on Solaris and Windows. + +1/28/98 (bug fix) Restore tty settings when closing serial device on Unix. +This is good behavior when closing real serial devices, essential when +closing the pseudo-device /dev/tty because the user's terminal settings +would be left useless, in raw mode, when tcl quit. (CCS) + +1/28/98 (bug fix) Tcl_OpenCommandChannel() was modifying the contents of the +argv array passed to it, causing problems for any caller that wanted to +continue to use the argv array after calling Tcl_OpenCommandChannel(). (CCS) + +2/1/98 (bug fix) More bugs with %Z in format string argument to strftime(): +1. Borland always returned empty string. +2. MSVC always returned the timezone string for the current time, not the + timezone string for the specified time. +3. With MSVC, "clock format 0 -format %Z -gmt 1" would return "GMT" the first + time it was called, but would return the current timezone string on all + subsequent calls. (CCS) + +2/1/98 (bug fix) "file stat" was broken on Windows. +1. "file stat" of a root directory (local or network) or a relative path that + resolved to a root directory (c:. when in pwd was c:/) was returning error. +2. "file stat" on a regular file (S_IFREG), the st_mode was sign extended to + a negative int if the platform-dependant type "mode_t" was declared as a + short instead of an unsigned short. +3. "file stat" of a network directory, the st_dev was incorrectly reported + as the id of the last accessed local drive rather than the id of the + network drive. (CCS) + +2/1/98 (bug fix) "file attributes" of a relative path that resolved to a +root directory was returning error. (CCS) + +2/1/98 (bug fix) Change error message when "file attribute" could not +determine the attributes for a file. Previously it would return different +error messages on Unix vs. Windows vs. Mac. (CCS) + +2/4/98 (bug fixes) Fixed several instances of bugs where the parser/compiler +would reach outside the range of allocated memory. Improved the array +lookup algorithm in set compilation. (DL) + +2/5/98 (change) The TCL_PARSE_PART1 flag for Set/Get(Obj)Var2 C APIs is now +deprecated and ignored. The part1 is always parsed when the part2 argument +is NULL. This is to avoid a pattern of errors for extension writers converting +from string based Tcl_SetVar() to new Tcl_SetObjVar2() and who could easily +forget to provide the flag and thus get code working for normal variables +but not for array elements. The performance hit is minimal. A side effect +of that change is that is is no longer possible to create scalar variables +that can't be accessed by tcl scripts because of their invalid name +(ending with parenthesis). Likewise it is also parsed and checked to +ensure that you don't create array elements of array whose name is a valid +array element because they would not be accessible from scripts anyway. +Note: There is still duplicate array elements parsing code. (DL) +*** POTENTIAL INCOMPATIBILITY *** + +2/11/98 (bug fix) Sharing objects between interps, such as by "interp +eval" or "send" could cause a crash later when dereferencing an interp +that had been deleted, given code such as: + set a {set x y} + interp create foo + interp eval foo $a + interp delete foo + unset a +Interp "foo" was gone, but "a" had a internal rep consisting of bytecodes +containing a dangling pointer to "foo". Unsetting "a" would attempt to +return resources back to "foo", causing a crash as random memory was +accessed. The lesson is that that if an object's internal rep depends on +an interp (or any other data structure) it must preserve that data in +some fashion. (CCS) + +2/11/98 (enhancement) The "interp" command was returning inconsistent error +messages when the specified slave interp could not be found. (CCS) + +2/11/98 (bug fix) Result codes like TCL_BREAK and TCL_CONTINUE were not +propagating through the master/slave interp boundaries, such as "interp +eval" and "interp alias". TCL_OK, TCL_ERROR, and non-standard codes like +teh integer 57 work. There is still a question as to whether TCL_RETURN +can/should propagate. (CCS) + +2/11/98 (bug fix) TclCompileScript() was derefering memory 1 byte before +start of the string to compile, looking for ']'. (CCS,DL) + +2/11/98 (bug fix) Tcl_Eval2() was derefering memory 1 byte before start +of the string to eval, looking for ']'. (CCS,DL) + +2/11/98 (bug fix) Compiling "set a(b" was running off end of string. (CCS,DL) + +2/11/98 (bug fix) Windows initialization code was dereferencing +uninitialized memory if TCL_LIBRARY environment didn't exist. (CCS) + +2/11/98 (bug fix) Windows "registry" command was dereferencing +uninitialized memory when constructing the $errorCode for a failed +registry call. (CCS) + +2/11/98 (enhancement) Eliminate the TCL_USE_TIMEZONE_VAR definition from +configure.in, because it was the same information as the already existing +HAVE_TM_ZONE definition. The lack of HAVE_TM_ZONE is used to work around a +Solaris and Windows bug where "clock format [clock sec] -format %Z -gmt 1" +produces the local timezone string instead of "GMT". (CCS) + +2/11/98 (bug fix) Memleaks and dereferencing of uninitialized memory in +regexp if an error occurred while compiling a regular expression. (CCS). + +2/18/98 (new feature) Added mutexes and thread local storage in order +to make Tcl thread safe. For testing purposes, there is a testthread +command that creates a new thread and an interpreter inside it. See +thread.test for examples, but this script-level interface is not fixed. +Each thread has its own notifier instance to manage its own events, +and threads can post messages to each other's message queue. +This uses pthreads on UNIX, and native thread support on other platforms. +You enable this by configuring with --enable-threads. Note that at +this time *Tk* is still not thread safe. Special thanks to +Richard Hipp: his earlier implementation inspired this work. (BW, SS, JI) + +2/18/98 (hidden feature change) The way the env() array is shared among +interpreters changed. Updates to env used to trigger write traces in +other interpreters. This undocumented feature is no longer implemented. +Instead, variable tracing is used to keep the C-level environ array in sync +with the Tcl-level env array. This required adding TCL_TRACE_ARRAY support +to Tcl_TraceVar2 so that array names works properly. (BW) +*** POTENTIAL INCOMPATIBILITY *** + +2/18/98 (enhancement) Conditional compilation for unix systems (e.g., +IRIX, SCO) that use f_bsize instead of st_blksize to determine disk block +size. (CCS) + +2/23/98 (bug fix) Fixed the emulation of polling selects in the threaded +version of the Unix notifier. The bug was showing up on a multiprocessor +as starvation of the notifier thread. (BW) + +----------------- Released 8.1a2, Feb 23 1998 ----------------------- + +9/22/98 (bug fix) Changed the value of TCL_TRACE_ARRAY so it no longer +conflicts with the deprecated TCL_PARSE_PART1 flag. This should +improve portability of C code. (stanton) + +10/6/98 (bug fix) The compile procedure for "if" incorrectly attempted +to match against the literal string "if", resulting in a stack +overflow when "::if" was compiled. It also would incorrectly accept +"if" instead of "elsif" in later clauses. (stanton) + +10/15/98 (new feature) Added a "totitle" subcommand to the "string" +command to convert strings to capitalize the first character of a string +and lowercase all of the other characters. (stanton) + +10/15/98 (bug fix) Changed regexp and string commands to properly +handle case folding according to the Unicode character +tables. (stanton) + +10/21/98 (new feature) Added an "encoding" command to facilitate +translations of strings between different character encodings. See +the encoding.n manual entry for more details. (stanton) + +11/3/98 (bug fix) The regular expression character classification +syntax now includes Unicode characters in the supported +classes. (stanton) + +11/6/98 (bug fix) Variable traces were causing crashes when upvar +variables went out of scope. [Bug: 796] (stanton) + +11/9/98 (bug fix) "format" now correctly handles multibyte characters +in %s format strings. (stanton) + +11/10/98 (new feature) "regexp" now accepts three new switches +("-line", "-lineanchor", and "-linestop") that control how regular +expressions treat line breaks. See the regexp manual entry for more +details. (stanton) + +11/17/98 (bug fix) "scan" now correctly handles Unicode +characters. (stanton) + +11/17/98 (new feature) "scan" now supports XPG3 position specifiers +and the "%n" conversion character. See the "scan" manual entry for +more details. (stanton) + +11/17/98 (bug fix) The Tcl memory allocator now returns 8-byte aligned +chunks of memory which improves performance on Windows and avoids +crashes on other platforms. [Bug: 834] (stanton) + +11/23/98 (bug fix) Applied various regular expression performance bug +fixes supplied by Henry Spencer. (stanton) + +11/30/98 (bug fix) Fixed various thread related race conditions. [Bug: +880 & 607] (stanton) + +11/30/98 (bug fix) Fixed a number of memory overflow and leak +bugs. [Bug: 584] (stanton) + +12/1/98 (new feaure) Added support for Korean encodings. (stanton) + +12/1/98 (feature change) Changed the Tcl_EvalObjv interface to remove +the string and length arguments. +*** POTENTIAL INCOMPATIBILITY with previous alpha releases *** + +12/2/98 (bug fix) Fixed various bugs related to line feed +translation. [Bug: 887] (stanton) + +12/4/98 (new feature) Added a message catalog facility to help with +localizing Tcl scripts. Thanks to Mark Harrison for contributing the +initial implementation of the "msgcat" package. (stanton) + +12/7/98 (bug fix) The memory allocator was failing to update the +block list for large memory blocks that were reallocated into a +different address. [Bug: 933] (stanton) + +----------------- Released 8.1b1, Dec 10 1998 ----------------------- + +12/22/98 (performance improvement) Improved the -command option of the +lsort command to better use the object system for improved +performance (about 5x speed up). Thanks to Syd Polk for suppling the +patch. [RFE: 726] (rjohnson) + +2/10/99 (bug fix) Restored the Tcl_ObjSetVar2/Tcl_ObjGetVar2 +interfaces from 8.0 and renamed the Tcl_GetObjVar2/Tcl_SetObjVar2 +interfaces to Tcl_GetVar2Ex and Tcl_SetVar2Ex. This should provide +better compatibility with 8.0. (stanton) +*** POTENTIAL INCOMPATIBILITY with previous alpha/beta releases *** + +2/10/99 (bug fix) Made the eval interfaces compatible with 8.0 by +renaming Tcl_EvalObj to Tcl_EvalObjEx, renaming Tcl_Eval2 to +Tcl_EvalEx and restoring Tcl_EvalObj and Tcl_GlobalEvalObj interfaces +so they match Tcl 8.0. (stanton) +*** POTENTIAL INCOMPATIBILITY with previous alpha/beta releases *** + +2/25/99 (bug fix/new feature) On Windows, the channel drivers for +consoles and serial ports now completely support file events. (redman) + +3/5/99 (bug fix) Integrated patches to fix various configure problems +that affected HP-UX-11, 64-bit IRIX, Linux, and Solaris. (stanton) + +3/9/99 (bug fix) Integrated various AIX related patches to improve +support for shared libraries. (stanton) + +3/9/99 (new feature) Added tcl_platform(user) to provide a portable +way to get the name of the current user. (welch) + +3/9/99 (new feature) Integrated the stub library mechanism contributed +by Jan Nijtmans, Paul Duffin, and Jean-Claude Wippler. This feature +should make it possible to write extensions that support multiple +versions of Tcl simultaneously. It also makes it possible to +dynamically load extensions into statically linked interpreters. This +patch includes the following changes: + - Added a Tcl_InitStubs() interface + - Added Tcl_PkgProvideEx, Tcl_PkgRequireEx, Tcl_PkgPresentEx, + and Tcl_PkgPresent. + - Added va_list versions of all VARARGS functions so they can be + invoked from wrapper functions. +See the manual for more information. (stanton) + + +3/10/99 (feature change) Replaced Tcl_AlertNotifier with +Tcl_ThreadAlert since the Tcl_AlertNotifier function relied on passing +internal data structures. (stanton) +*** POTENTIAL INCOMPATIBILITY with previous alpha/beta releases *** + +3/10/99 (new feature) Added a Tcl_GetVersion API to make it easier to +check the Tcl version and patch level from C. (redman) + +3/14/99 (feature change) Tried to unify the TclpInitLibrary path +routines to look in similar places from Windows to UNIX. The new +library search path is: TCL_LIBRARY, TCL_LIBRARY/../tcl8.1, relative +to DLL (Windows Only) relative to installed executable, relative to +develop executable, and relative to compiled-in in location (UNIX +Only.) This fix included: + - Defining a TclpFindExecutable + - Moving Tcl_FindExecutable to a common area in tclEncoding.c + - Modifying the TclpInitLibraryPath routines. +(surles) + +3/14/99 (feature change) Added hooks for TclPro Wrapper to initialize +the location of the encoding files and libraries. This fix included: + - Adding the TclSetPerInitScript routine. + - Modifying the Tcl_Init routines to evaluate the non-NULL + pre-init script. + - Adding the Tcl_SetdefaultEncodingDir and Tcl_GetDefaultEncodingDir + routines. + - Modifying the TclpInitLibrary routines to append the default + encoding dir. +(surles) + +3/14/99 (feature change) Test suite now uses "test" namespace to +define the test procedure and other auxiliary procedures as well as +global variables. + - Global array testConfige is now called ::test::testConfig. + - Global variable VERBOSE is now called ::test::verbose, and + ::test::verbose no longer works with numerical values. We've + switched to a bitwise character string. You can set + ::test::verbose by using the -verbose option on the Tcl command + line. + - Global variable TESTS is now called ::test::matchingTests, and + can be set on the Tcl command line via the -match option. + - There is now a ::test::skipTests variable (works similarly to + ::test::matchTests) that can be set on the Tcl command line via + the -match option. + - The test suite can now be run in any working directory. When + you run "make test", the working directory is nolonger switched + to ../tests. +(hirschl) +*** POTENTIAL INCOMPATIBILITY *** + +--------------- Released 8.1b2, March 16, 1999 ---------------------- + +3/18/99 (bug fix) Fixed missing/incorrect characters in shift-jis table +(stanton) + +3/18/99 (feature change) The glob command ignores the +FS_CASE_IS_PRESERVED bit on file systesm and always returns +exactly what it gets from the system. (stanton) +*** POTENTIAL INCOMPATIBILITY *** + +3/19/99 (new feature) Added support for --enable-64bit. For now, +this is only supported on Solaris 7 64bit (SunOS 5.7) using the Sun +compiler. (redman) + +3/23/99 (bug fix) Fixed fileevents and gets on Windows consoles and +serial devices so that non-blocking channels do not block on partial +input lines. (redman) + +3/23/99 (bug fix) Added a new Tcl_ServiceModeHook interface. +This is used on Windows to avoid the various problems that people +have been seeing where the system hangs when tclsh is running +outside of the event loop. As part of this, renamed +TclpAlertNotifier back to Tcl_AlertNotifier since it is public. +(stanton) + +3/23/99 (feature change) Test suite now uses "tcltest" namespace to +define the test procedure and other auxiliary procedures as well as +global variables. The previously chosen "test" namespace was thought +to be too generic and likely to create conflits. +(hirschl) +*** POTENTIAL INCOMPATIBILITY *** + +3/24/99 (bug fix) Make sockets thread safe on Windows. +(redman) + +3/24/99 (bug fix) Fix cases where expr would incorrect return +a floating point value instead of an integer. (stanton) + +3/25/99 (bug fix) Added ASCII to big5 and gb2312 encodings. +(stanton) + +3/25/99 (feature change) Changed so aliases are invoked at current +scope in the target interpreter instead of at the global scope. This +was an incompatibility introduced in 8.1 that is being removed. +(stanton) +*** POTENTIAL INCOMPATIBILITY with previous beta releases *** + +3/26/99 (feature change) --enable-shared is now the default and build +Tcl as a shared library; specify --disable-shared to build a static Tcl +library and shell. +*** POTENTIAL INCOMPATIBILITY *** + +3/29/99 (bug fix) Removed the stub functions and changed the stub +macros to just use the name without params. Pass &tclStubs into the +interp (don't use tclStubsPtr because of collisions with the stubs on +Solaris). (redman) + +3/30/99 (bug fix) Loadable modules are now unloaded at the last +possible moment during Tcl_Finalize to fix various exit-time crashes. +(welch) + +3/30/99 (bug fix) Tcl no longer calls setlocale(). It looks at +env(LANG) and env(LC_TYPE) instead. (stanton) + +4/1/99 (bug fix) Fixed the Ultrix multiple symbol definition problem. +Now, even Tcl includes a copy of the Tcl stub library. (redman) + +4/1/99 (bug fix) Internationalized the registry package. + +4/1/99 (bug fix) Changed the implemenation of Tcl_ConditionWait and +Tcl_ConditionNotify on Windows. The new algorithm eliminates a race +condition and was suggested by Jim Davidson. (welch) + +4/2/99 (new apis) Made various Unicode utility functions public. +Tcl_UtfToUniCharDString, Tcl_UniCharToUtfDString, Tcl_UniCharLen, +Tcl_UniCharNcmp, Tcl_UniCharIsAlnum, Tcl_UniCharIsAlpha, +Tcl_UniCharIsDigit, Tcl_UniCharIsLower, Tcl_UniCharIsSpace, +Tcl_UniCharIsUpper, Tcl_UniCharIsWordChar, Tcl_WinUtfToTChar, +Tcl_WinTCharToUtf (stanton) + +4/2/99 (feature change) Add new DDE package and removed the Tk +send command from the Windows version. Changed DDE-based send +code into "dde eval" command. The DDE package can be loaded +into tclsh, not just wish. Windows only. (redman) + +4/5/99 (bug fix) Changed safe-tcl so that the encoding command +is an alias that masks out the "encoding system" subcommand. +(redman) + +4/5/99 (bug fix) Configure patches to improve support for +OS/390 and BSD/OS 4.*. (stanton) + +4/5/99 (bug fix) Fixed crash in the clock command that occurred +with negative time values in timezones east of GMT. (stanton) + +4/6/99 (bug fix) Moved the "array set" C level code into a common +routine (TclArraySet). The TclSetupEnv routine now uses this API to +create an env array w/ no elements. This fixes the bug caused when +every environ varaible is removed, and the Tcl env variable is +synched. If no environ vars existed, the Tcl env var would never be +created. (surles) + +4/6/99 (bug fix) Made the Env module I18N compliant. (surles) + +4/6/99 (bug fix) Changed the FindVariable routine to TclpFindVariable, +that now does a case insensitive string comparison on Windows, and not +on UNIX. (surles) + +--------------- Released 8.1b3, April 6, 1999 ---------------------- + +4/9/99 (bug fix) Fixed notifier deadlock situation when the pipe used +to talk back notifier thread is filled with data. Found as a result of the +focus.test for Tk hanging. (redman) + +4/13/99 (bug fix) Fixed bug where socket -async combined with +fileevent for writing did not work under Windows NT. (redman) + +4/13/99 (encoding fix) Restored the double byte definition of GB2312 +and added the EUC-CN encoding. EUC-CN is a variant of GB2312 that +shifts the characters into bytes with the high bit set and includes +ASCII as a subset. (stanton) + +4/27/99 (bug fix) Added 'extern "C" {}' block around the stub table +pointer declaration so the stub library can be used from C++. (stanton) + +--------------- Released 8.1 final, April 29, 1999 ---------------------- + +4/22/99 (bug fix) Changed Windows NT socket implementation to avoid +creating a communication window. This avoids the problem where the +system hangs waiting for tclsh to respond to a system-wide synchronous +broadcast (e.g. if you change system colors). (redman) + +4/22/99 (bug fix) Added call to TclWinInit from TclpInitPlatform when +building a static library since DllMain will not be invoked. This +could break old code that explicitly called TclWinInit, but should be +simpler in the long run. (stanton) +*** POTENTIAL INCOMPATIBILITY *** + +4/23/99 (bug fix) Added support for the koi8-r Cyrillic +encoding. [Bug: 1771] (stanton) + +4/28/99 (bug fix) Changed internal Tcl_Obj usage to avoid freeing the +internal representation after the string representation has been +freed. This makes it easier to debug extensions. (stanton) + +4/30/99 (bug fix) Fixed a memory leak in CommandComplete. (stanton) + +5/3/99 (bug fix) Fixed a bug where the Tcl_ObjType was not being set +in a duplicated Tcl_Obj. [Bug: 1975, 2047] (stanton) + +5/3/99 (bug fix) Changed Tcl_ParseCommand to avoid modifying eval'ed +strings that are already null terminated. [Bug: 1793] (stanton) + +5/3/99 (new feature) Applied Jeff Hobbs's string patch which includes +the following changes: + - added new subcommands: equal, repeat, map, is, replace + - added -length option to "string compare|equal" + - added -nocase option to "string compare|equal|match" + - string and list indices can be an integer or end?-integer?. + - added optional first and last index args to string toupper, et al. +See the string.n manual entry for more details about the new string +features. [Bug: 1845] (stanton) + +5/6/99 (new feature) Added Tcl_UtfNcmp and Tcl_UtfNcasecmp to make Utf +string comparision easier. (stanton) + +5/7/99 (bug fix) Improved OS/390 support. [Bug: 1976, 1997] (stanton) + +5/12/99 (bug fix) Changed Windows initialization code to avoid using +GetUserName system call in favor of the env(USERNAME) variable. This +provides a significant startup speed improvement. (stanton) + +5/12/99 (bug fix) Replaced the per-interpreter regexp cache with a +per-thread cache. Changed the Regexp object to take advantage of this +extra cache. Added a reference count to the TclRegexp type so regexps +can be shared by multiple objects. Removed the per-interp regexp cache +from the interpreter. Now regexps can be used with no need for an +interpreter. This set of changes should provide significant speed +improvements for many Tcl scripts. [Bug: 1063] (stanton) + +5/14/99 (bug fix) Durining initialization on Unix, Tcl now extracts the +encoding subfield from the LANG/LC_ALL environment variables in cases +where the locale is not found in the built-in locale table. It also +attempts to initialize the locale subsystem so X11 is happy. [Bug: 1989] +(stanton) + +5/14/99 (bug fix) Applied the patch to fix 100-year and 400-year +boundaries in leap year code, from Isaac Hollander. [Bug: 2066] (redman) + +5/14/99 (bug fix) Fixed a crash caused by a failure to reset the result +before evaluating the test expression in an uncompiled for +statement. (stanton) + +5/18/99 (bug fix) Modified initialization code on Windows to avoid +inherenting closed or invalid channels. If the standard input is +anything other than a console, file, serial port, or pipe, then we fall +back to the standard Tk window console. (stanton) + +5/19/99 (bug fix) Added an extern "C" block around the entire tcl.h +header file to avoid C++ linkage issues. (redman) + +5/19/99 (new feature) Applied Jeff Hobb's patch to add +Tcl_StringCaseMatch to support case insensitive glob style matching and +Tcl_UniCharIs* character classification functions. (stanton) + +5/20/99 (bug fix) Added the directory containing the executuble and the +../lib directory relative to that to the auto_path variable. (redman) + +--------------- Released 8.1.1, May 25, 1999 ---------------------- + +5/21/99 (bug fix) Fixed launching command.com on Win95/98, no longer +hangs. [Bug: 2105] (redman) + +5/28/99 (bug fix) Fixed bug where dde calls were being passed an +invalid dde handle. [Bug: 2124] (stanton) + +6/1/99 (bug fix) Small configure.in patches. [Bug: 2121] (stanton) + +6/1/99 (bug fix) Applied latest regular expression patches to fix an +infinite loop bug and add support for testing whether a string could +match with additional input. [Bug: 2117] (stanton) + +6/2/99 (bug fix) Fixed incorrect computation of relative ordering in +Utf case-insensitive comparison. [Bug: 2135] (stanton) + +6/3/99 (bug fix) Fxied bug where string equal/compare -nocase +reported wrong result on null strings. [Bug: 2138] (stanton) + +6/4/99 (new feature) Windows build now uses Cygwin tools plus GNU +make and autoconf to build static/dynamic and debug/nodebug. (stanton) + +6/7/99 (new feature) Optimized string index, length, range, and +append commands. Added a new Unicode object type. (hershey) + +6/8/99 (bug fix) Rolled back Windows socket driver to 8.1.0 +version. (stanton) + +6/9/99 (new feature) Added Tcl_RegExpMatchObj and Tcl_RegExpGetInfo +to public Tcl API, these functions are needed by Expect. Changed +tools/genStubs.tcl to always write output in LF mode. (stanton) + +6/14/99 (new feature) Merged string and Unicode object types. Added +new public Tcl API functions: Tcl_NewUnicodeObj, Tcl_SetUnicodeObj, +Tcl_GetUnicode, Tcl_GetUniChar, Tcl_GetCharLength, Tcl_GetRange, +Tcl_AppendUnicodeToObj. (hershey) + +6/16/99 (new feature) Changed to conform to TEA specification, added +tcl.m4 and aclocal.m4 macro libraries for configure. (wart) + +6/17/99 (new feature) Added new regexp interfaces: -expanded, -line, +-linestop, and -lineanchor switches. Renamed Tcl_RegExpMatchObj to +Tcl_RegExpExecObj and added new Tcl_RegExpMatchObj that is equivalent +to Tcl_RegExpMatch. Added public macros for regexp flags. Added +REG_BOSONLY flag to allow Expect to iterate through a string and only +find matches that start at the current position within the +string. (stanton) + +6/21/99 (bug fix) Fixed memory leak in TclpThreadCreate where thread +attributes were not being released. [Bug: 2254] (stanton) + +6/23/99 (new feature) Updated Unicode character tables to reflect +Unicode 2.1 data. (stanton) + +6/25/99 (new feature) Fixed bugs in non-greedy quantifiers for regular +expression code. (stanton) + +6/25/99 (new feature) Added initial implementation of new Tcl test +harness package. Modified test files to use new tcltest package. +(jenn) + +6/26/99 (new feature) Applied patch from Peter Hardie to add poke +command to dde and changed the dde package version number to +1.1. (redman) + +6/28/99 (bug fix) Applied patch from Peter Hardie to fix problem in +Tcl_GetIndexFromObj() when the key being passed is the empty string. +[Bug: 1738] (redman) + +6/29/99 (new feature) Added options to tcltest package: -preservecore, +-limitconstraints, -help, -file, -notfile, and flags. (jenn) + +7/3/99 (new feature) Changed parsing of variable names to allow empty +array names. Now "$(foo)" is a variable reference. Previously you +had to use something line $::(foo), which is slower. This change was +requested by Jean-Luc Fontaine for his STOOOP package. (welch) + +7/3/99 (new feature) Added Tcl_SetNotifier (public API) and +associated hook points in the notifiers to be able to replace the +notifier calls at runtime. The Xt notifier and test program use this +hook. (welch) + +7/3/99 (new feature) Added a new variant of the "Trf core patch" from +Andreas Kupries that adds new C APIs Tcl_StackChannel, +Tcl_UnstackChannel, and Tcl_GetStackedChannel. This allows the Trf +extension to work without applying patches to the Tcl core. (welch) + +7/6/99 (new feature) Added -timeout option to http.tcl to handle +timeouts that occur during connection attempts to hosts that are +down. (welch) + +7/6/99 (bug fix) Applied new implementation of the Windows serial +port driver from Rolf Schroedter that fixes reading only one byte from +the port at a time. Uses polling every 10ms to implement +fileevents. [Bug: 1980 2217] (redman) + +7/8/99 (bug fix) Applied fix for bug in DFA state caching under +lookahead conditions (regular expressions). [Bug: 2318] (stanton) + +7/8/99 (bug fix) Fixed bug in string range bounds checking +code. (stanton) + +--------------- Released 8.2b1, July 14, 1999 ---------------------- + +7/16/99 (bug fix) Added Tcl_SetNotifier to stub table. [Bug: 2364] +Added check for Alpha/Linux to correct the IEEE floating point flag, +patch from Don Porter. (redman) + +7/20/99 (bug fix) Merged 8.0.5 code to handle tcl_library properly, +also fixed a bug that caused TCL_LIBRARY to be ignored. (hershey) + +7/21/99 (bug fix) Implemented modified socket driver for Windows that +uses a thread to manage the socket event window. Code works the same +on all supported versions of Windows and was based on original 8.1.0 +code. [Bug: 2178 2256 2259 2329 2323 2355] (redman) + +7/21/99 (new feature) Applied patch from Rolf Schroedter to add +-pollinterval option to fconfigure for Windows serial ports. Allows +the maxblocktime to be modified to control how often serial ports are +checked for fileevents. Also added documentation for \\.\comX +notation for opening serial ports on Windows. (redman) + +7/21/99 (bug fix) Changed APIs in stub tables to use "unsigned long" +instead of the platform-specific "size_t", primarily after SunOS 4 +users could no longer compile. (redman) + +7/22/99 (bug fix) Fixed crashing during "array set a(b) {}". +[Bug: 2427] (redman) + +7/22/99 (bug fix) The install-sh script must be given execute +permissions prior to running. [Bug: 2413] (redman) + +7/22/99 (bug fix) Applied patch from Ulrich Ring to remove ANSI-style +prototypes in the code. [Bug: 2391] (redman) + +7/22/99 (bug fix) Added #if blocks around #includes of sys/*.h header +files, to allow an extension author on Windows to use the MetroWerks +compiler. [Bug: 2385] (redman) + +7/22/99 (bug fix) Fixed running the safe.test test suite, one change +to the Windows Makefile.in to fix paths and another in safe.test to +check for the tcl_platform(threaded) variable properly. (redman) + +7/22/99 (bug fix) Fixed hanging in new Win32 socket driver with +threads enabled. (redman) + +7/26/99 (bug fix) Fixed terminating of helper threads by holding any +mutexes from the primary thread while waiting for the helper thread to +terminate. Fixes dual-CPU WinNT hangs, only one rare sporadic hang +that still exists with dual-CPU WinNT. Also fixed test cases so that +they would not depend as much on timing for dual-CPU WinNT. (redman) + +7/27/99 (bug fix) Some test suite cleanup. (jenn) + +7/29/99 (bug fix) Applied patch to fix typo in .SH NAME line in +doc/Encoding.n [Bug: 2451]. Applied patch to avoid linking pack.n to +pack-old.n [Bug: 2469]. Patches from Don Porter. (redman) + +7/29/99 (bug fix) Allow tcl to open CON and NUL, even for redirection +of std channels. [Bug: 2393 2392 2209 2458] (redman) + +7/30/99 (bug fix) Applied fixed Trf patch from Andreas Kupries. +[Bug: 2386] (hobbs) + +7/30/99 (bug fix) Fixed bug in info complete. [Bug: 2383 2466] (hobbs) + +7/30/99 (bug fix) Applied patch to fix threading on Irix 6.5, patch +provided by James Dennett. [Bug: 2450] (redman) + +7/30/99 (bug fix) Fixed launching of 16bit applications on Win9x from +wish. The command line was being primed with tclpip82.dll, but it was +ignored later. + +7/30/99 (bug fix) Added functions to stub table, patch provided by Jan +Nijtmans. [Bug: 2445] (hobbs) + +8/1/99 (bug fix) Changed Windows socket driver to terminate threads +by sending a message to the window rather than calling +TerminateThread(), which seems to leak about 4k from the helper +thread's stack space. (redman) + +--------------- Released 8.2b2, August 5, 1999 ---------------------- + +8/4/99 (bug fix) Applied patches supplied by Henry Spencer to greatly +enhance performance of certain classes of regular expressions. +[Bug: 2440 2447] (stanton) + +8/5/99 (doc change) Made it clear that tcl_pkgPath was not set for +Windows. [Bug: 2455] (hobbs) + +8/5/99 (bug fix) Fixed reference to bytes that might not be null +terminated in tclLiteral.c. [Bug: 2496] (hobbs) + +8/5/99 (bug fix) Fixed typo in http.tcl. [Bug: 2502] (hobbs) + +8/9/99 (bug fix) Fixed test suite to handle larger integers +(64bit). Patch from Don Porter. (hobbs) + +8/9/99 (documentation fix) Clarified Tcl_DecrRefCount docs +[Bug: 1952]. Clarified array pattern docs [Bug: 1330]. Fixed clock docs +[Bug: 693]. Fixed formatting errors [Bug: 2188 2189]. Fixed doc error +in tclvars.n [Bug: 2042]. (hobbs) + +8/9/99 (bug fix) Fixed path handling in auto_execok [Bug: 1276] (hobbs) + +8/9/99 (internal api change) Removed the TclpMutexLock and TclpMutexUnlock +APIs and added a new exported api, Tcl_GetAllocMutex. These APIs are all for +the mutex used in the simple memory allocators. By making this change +we are able to substitute different implementations of the thread-related +APIs without having to recompile the Tcl core. (welch) + +8/9/99 (new C API) Tcl_GetChannelNames returns a list of open channel +names in the interpreter result. Still no Tcl-level version of this, +but server-like applications can use this to clean up files without +deleting interpreters. (welch) + +8/9/99 (bug fix) Traces were not firing on "info exists", which used to +happen in Tcl 7.6 and earlier. An "info exists" now fires a read trace, +if defined. This makes it possible to fully implement variables that +are defined via traces. (welch) + +8/10/99 (bug fix) Fixed Brent's changes so that they work on +Windows. (redman) + +--------------- Released 8.2b3, August 11, 1999 ---------------------- + +8/12/99 (Mac) Rearrange projects in tclMacProjects.sea.hqx so that the +build directory is separate from the sources. (Jim Ingham) + +8/12/99 (bug fix) Fixed bug in Tcl_EvalEx where the termOffset was not +being updated in cases where the evaluation returned a non TCL_OK +error code. [Bug: 2535] (stanton) + +--------------- Released 8.2.0, August 17, 1999 ---------------------- + +9/21/99 (config fixes) fixed several AIX configuration issues. gcc and +threading may still cause problems on AIX. (hobbs) + +9/21/99 (bug fix) fixed expr double-eval problem. [Bug: 732] (hobbs) + +9/21/99 (bug fix) fixed static buffer overflow problem. [Bug: 2483] (hobbs) + +9/21/99 (bug fix) fixed end-int linsert interpretation. [Bug: 2693] (hobbs) + +9/21/99 (bug fix) fixed bug when setting array in non-existent +namespace. [Bug: 2613] (hobbs) + +--- Released 8.2.1, October 04, 1999 --- See ChangeLog for details --- + +10/30/99 (feature enhancement) new regexp engine from Henry Spencer +was patched in - should greatly reduce stack space usage. (spencer) + +10/30/99 (bug fix) fixed Purify reported memory leaks in findexecutable +test command, TclpCreateProcess on Unix, in handling of C environ array, +and in testthread code. No more known (reported) mem leaks for Tcl +built using gcc on Solaris 2.5.1. Also none reported for Tcl on NT +(using Purify 6.0). (hobbs) + +10/30/99 (bug fix) fixed improper bytecode handling of +'eval {set array($unknownvar) 5}' (also for incr) (hobbs) + +10/30/99 (bug fix) fixed event/io threading problems by making +triggerPipe non-blocking (nick kisserbeth) + +10/30/99 (bug fix) fixed Tcl_AppendStringsToObjVA and Tcl_AppendResultVA +to only iterates once over the va_list (avoiding non-portable memcpy). +(joe english, hobbs) + +10/30/99 (bug fix) removed savedChar trick in tclCompile.c that appeared +to be causing a segv when the literal table was released. +[Bug: 2459, 2515] (David Whitehouse) + +10/30/99 (bug fix) fixed [string index] to return ByteArrayObj +when indexing into one (test case string-5.16) [Bug: 2871] (hobbs) + +10/30/99 (bug fix) fixes for mac UTF filename handling (ingham) + +--- Released 8.2.2, November 04, 1999 --- See ChangeLog for details --- + +11/19/99 (feature enhancement) bug fixes for http package as well as +patch required by TLS (SSL) extension that adds http::(un)register +and -type to http::geturl. Up'd http pkg version to 2.2. + +11/19/99 (bug fix) removed extra decr of numLevels in Tcl_EvalObjEx +that could cause seg fault (mjansen@wendt.de) + +11/19/99 (bug fixes) numerous minor big fixes, including correcting the +installation of the koi8-r encoding and tcltest1.0 on Windows. + +11/30/99 (bug fix) fixes scan where %[..] didn't match anything + +11/30/99 (bug fix) fixed setting of isNonBlocking flag in PipeBlockModeProc +so you can now close a non-blocking channel without waiting. + +11/30/99 (bug work-around) prevented the unloading of DLLs for Unix in +TclFinalizeLoad. This stops the seg fault on exit that some users would +see (ie with oratcl) when using DLLs that do nasty things like register +atexit handlers. + +12/07/99 (bug fix) fixes for 'expr + {[incr]}' and 'expr + {[error]}' +cases (different causes). + +--- Released 8.2.3, December 16, 1999 --- See ChangeLog for details --- + +1999-09-14 (feature enhancement) added -start switch to regexp and regsub. + +1999-09-15 (feature enhancement) add 'array unset' command. + +1999-09-15 (feature enhancement) rewrote runtime libraries to use new +string functions + +1999-08-18 (feature enhancement) added 'file channels' command, along with +Tcl_GetChannelNames(Ex) public C APIs. + +1999-10-19 (feature enhancement) enhanced tcltest package + +1999-09-16 (feature enhancement) added -milliseconds switch to 'clock clicks' + +1999-10-28 (feature enhancement) added support for inline 'scan' + +1999-10-28 (feature enhancement) added support for touch functionality by +extendeding 'file atime' and 'file mtime' to take an optional time argument + +1999-11-24 (feature enhancement) added 'fconfigure $sock -lasterror' +command to Windows to query the last error received on a serial socket. + +1999-11-30 (bug fix) fixed handling of %Z on NT for timezones that don't +have DST + +1999-12-03 (feature enhancement) improved error message in bad octal cases +and improper use of comments. (hobbs) + +1999-12-07 (bug fix) fixed Tcl_ScanCountedElement to not step +beyond the end of the counted string + +1999-12-09 (feature enhancement) removed all references to 16 bit +compatibility code for Windows (hobbs) + +1999-12-10 (bug fix) removed check for vfork - Tcl now uses only fork in +exec. (hobbs) + +1999-12-10 (optimization) changed Tcl_ConcatObj to return a list +object when it receives all pure list objects as input (used by 'concat'), +added optimizations in Tcl_EvalObjEx for pure list case, and optimized +INST_TRY_CVT_TO_NUMERIC in TclExecuteByteCode for boolean objects. +(oakley, hobbs) + +1999-12-12 (feature enhancement) enhanced glob command with -type, -path, +-directory and -join switches. (darley, hobbs) + +1999-12-21 (bug fix) changed CreateThread to _beginthreadex and +ExitThread to _endthreadex to prevent 4K mem leak (gravereaux) + +1999-12-21 (bug fix) fixed applescript for I18N + +1999-12-21 (feature enhancement) added -unique option to lsort (hobbs) + +1999-12-21 (bug fix) changed thread ids to longs (for 64bit systems) + +--- Released 8.3b1, December 22, 1999 --- See ChangeLog for details --- + +2000-01-10 (feature enhancement) clock scan now supports the common +ISO 8601 date/time formats. See docs for details. (melski) + +2000-01-10 (bug fix) prevented \ooo substitution from accepting +non-octal digits [Bug: 3975] (hobbs) + +2000-01-11 (bug fix) fixed improper handling of DST by clock when +using relative times (like "1 month" or "tomorrow"). (melski) + +2000-01-12 (bug fix) improved build support for Tru64 v5, NetBSD +and Reliant Unix (hobbs) + +2000-01-12 (bug fix) made imported commands also import their +compile procedure (duffin) + +2000-01-12 (bug fix) fixed 'info procs ::namesp::*' behavior to return +procs in a namespace (dejong) + +2000-01-12 (feature enhancement) added support for setting permissions +symbolicly (like chmod) in [file attributes $file -permissions ...] (schoebel) + +2000-01-13 (bug fix) fixed lsort -dictionary problem when sorting +characters between 'Z' and 'a' (flawed upper/lower comparison logic) (melski) + +--- Released 8.3b2, January 13, 2000 --- See ChangeLog for details --- + +2000-01-14 (feature enhancement) clock format %Q added, clock scan updated + +2000-01-20 (bug fix) corrected complex array elem compiling (Spjuth) + +2000-01-20 (bug fix) made [info body] always return a string type arg, +to prevent possible misuse of bytecodes in the wrong context (hobbs) + +2000-01-20 (bug fixes) several fixes to variable handling to prevent +possible crashes, and further definition of correct behavior (melski) + +2000-01-25 (bug fixes) improved QNX, Ultrix and OSF1 (Tru64) config and +compatibility (edge, furukawa) + +2000-01-25 (bug fix) fixed mem leak when calling lsort with a bad -command +argument (hobbs) + +2000-01-27 (feature enhancement) package mechanism overhaul: changed +behavior of pkg_mkIndex to do -direct by default, added -lazy option. +Fixed pkg_mkIndex to handle odd proc names and auto_mkIndex to use platform +independent file paths. Other fixes for odd package quirks. Added +::pkg namespace and ::pkg::create helper function. (melski) + +2000-02-01 (bug fix) fixed problem where http POST would send one extra +newline (vasiljevic) + +2000-02-02 (feature enhancement) added docs for new regexp -inline and +-all switches. (hobbs) + +2000-02-08 (bug fix) corrected handling of "next monthname" in clock scan +(melski) + +2000-02-09 (bug fix) restored Mac source to build readiness and prevented +mac panic from an error when closing an async socket (steffen, ingham) + +2000-02-10 (feature enhancement) improved error reporting for failed +loads on Windows (dejong, hobbs) + +--- Released 8.3.0, February 10, 2000 --- See ChangeLog for details --- + +2000-03 (bug fixes, feature enhancement) overhaul of http package for +proper handling of async callbacks (new options), version is now at 2.3 +(tamhankar, welch) + +2000-03 (speed improvements) speedup in Windows filename handling (newman) +and ==/!= empty string in exprs. (hobbs) + +2000-03-27 (bug fix) added uniq'ing test to namespace export list to +prevent unnecessary mem growth (hobbs) + +2000-03-29 (bug fix) fixed mem leak when repeatedly sourcing the same +bytecompiled (tbc) code repeatedly across different interpreters (hobbs) + +2000-03-29 (config enhancement) improved build support for gcc/mingw on +Windows (nijtmans, hobbs) and added RPM target (melski) + +2000-03-31 (bug fix) corrected data encoding problem when using +"exec << $data" construct (melski) + +2000-04 (feature enhancement) overhaul of threading mechanism to better +support tcl level thread command (new APIs Tcl_ConditionFinalize, +Tcl_MutexFinalize, Tcl_CreateThread, etc, all docs in Thread.3). +(kupries, graveraux) +This enables the tcl level thread extension. (welch) + +2000-04-10 (bug fix) fixed infinite loop case in regexp -all (melski) + +2000-04-13 (config enhancement) added support for --enable-64bit-vis +Sparc target. (hobbs) + +2000-04-18 (bug fix) moved tclLibraryPath to thread-local storage to fix +possible race condition on MP machines (hobbs) + +2000-04-18 (config enhancement) added MacOS X build target and +tclLoadDyld.c dl type. (sanchez) + +2000-04-23 (bug fix) several Mac socket fixes (ingham) + +2000-04-24 (bug fix) fixed hang in threaded Unix case when backgrounded +exec process was running (dejong) + +--- Released 8.3.1, April 26, 2000 --- See ChangeLog for details --- + +2000-05-29 (bug fix) corrected resource cleanup in http error cases. +Improved handling of error cases in http. (tamhankar) + +2000-07 (feature rewrite) complete rewrite of the Tcl IO channel subsystem +to correct problems (hangs, core dumps) with the initial stacked channel +implementation. The new system has many more tests for robustness and +scalability. There are new C APIs (see Tcl_CreateChannel), but only +stacked channel drivers are affected (ie: TLS, Trf, iogt). The iogt +extension has been added to the core test code to test the system. +(hobbs, kupries) + **** POTENTIAL INCOMPATABILITY **** + +2000-07 (build improvements) cleanup of the makefiles and configure scripts +to correct support for building under gcc for Windows. (dejong) + +2000-08-07 (bug fix) corrected sizeof error in Tcl_GetIndexFromObjStruct. +(perkins) + +2000-08-07 (bug fix) correct off-by-one error in HistIndex, which was +causing [history redo] to start its search at the wrong event index. (melski) + +2000-08-07 (bug fix) corrected setlocale calls for XIM support and locale +issues in startup. (takahashi) + +2000-08-07 (bug fix) correct code to handle locale specific return values +from strftime, if any. (wagner) + +2000-08-07 (bug fix) tweaked grammar to properly handle the "ago" keyword +when it follows multiple relative unit specifiers, as in +"2 days 2 hours ago". (melski) + +2000-08-07 (doc fixes) numerous doc fixes to correct SEE ALSO and NAME +sections. (english) + +2000-08-07 (bug fix) new man pages memory.n, TCL_MEM_DEBUG.3, Init.3 and +DumpActiveMemory.3. (melski) + +--- Released 8.3.2, August 9, 2000 --- See ChangeLog for details --- + +2001-04-04 (build improvements) redid Mac build structure (steffen) +Corrected IRIX-5* configure (english). Added support for AIX-5 (hobbs). +Added support for Win64 (hobbs). + +2001-04-03 (doc fixes) numerous doc corrections and clarifications. +Update of READMEs. + +2001-03-30 (bug fix) corrected Windows memory error on exit (wu) +Fixed race condition in readability of socket on Windows. + +2001-03-29 (bug fix) prevent potential race condition and security leak in +tmp filename creation on Unix. (max) +Fixed handling of timeout for threads (corrects excessive CPU usage issue +for Tk on Unix in threaded Tcl environment). (ruppert) + +2001-03-13 (bug fix) Correctly possible memory corruption in string map {} +$str (fellows) + +2001-02-15 (feature enhancement) improved efficiency of [string split] +(fellows) + +2001-01-30 (bug fix) Fixed possible hangs in fcopy. (porter) + +2001-01-04 (bug fix) corrected parsing of $tcl_libPath at startup on +Windows (porter) + +2000-12-14 (feature enhancement) improved (s)rand for 64-bit platforms +(porter) + +2000-12-09 (feature enhancement) changed %o and %x to use strtoul instead +of strtol to correctly preserve scan<>format conversion of large integers +(hobbs) +Fixed handling of {!} in expressions (hobbs, fellows) + +2000-11-23 (mem leak) fixed potential memory leak in error case of lsort +(fellows) + +2000-11-02 (bug fix) Corrected sharing of tclLibraryPath in threaded +environment (gravereaux) + +2000-11-01 (mem leak) Corrected excessive mem use of info exists on a +non-existent array element (hobbs) + +2000-10-20 (feature enhancement) call stat only when necessary in 'glob' to +speed up command significantly in base cases (hobbs) + +2000-10-06 (bug fix) corrected [file channels] to only return channels in +the current interpreter (hobbs) + +2000-09-29 (bug fix) corrected reporting of space parity on Windows (Eason) + +2000-09-27 (bug fix) fixed a bug introduced by a partial fix in 8.3.2 that +didn't set nonBlocking correctly when resetting the flags for the write +side (mem leak) Correct mem leak in channels when statePtr was released +(hobbs) + +--- Released 8.3.3, April 6, 2001 --- See ChangeLog for details --- + +2001-06-27 (bug fix) corrected backslash substitution of non-ASCII characters. +(hobbs, riefenstahl) + +2001-07-02 (bug fix) corrected [concat] treatment of UTF-8 strings (hobbs, +barras) + +2001-07-16 (bug fix) corrected thread-enabled pipe closing on Windows +(hobbs, jsmith) + +2001-07-18 (bug fix) corrected memory overwrite error when buffer size +of a channel is changed after channel use has already begun (kupries, porter) + +2001-08-06 (bug fix) corrected object reference counting in [gets] (jikamens) + +2001-08-06 (new feature) added GNU (HURD) configuration target. (brinkmann) + +2001-08-07 (bug fix) corrected bytecode stack management during [break] +(see test foreach-5.5) (sofer, tallneil, jstrot) + +2001-08-08 (new features) updated packages msgcat 1.1.1, opt 0.4.3, +tcltest 1.0.1, dependencies checked (porter) + +2001-08-20 (new feature) http 2.3.2: include port number in Host: header +to comply with HTTP/1.1 spec (RFC 2068) (hobbs, tils) + +2001-08-23 (new feature) added QNX-6 build support (loverso) + +2001-08-23 (bug fix) corrected handling of spaces in path name passed to +[exec] on Windows (kenpoole) + +2001-08-24 (bug fix) corrected [package forget] stopping on non-existent +package (porter) + +2001-08-24 (bug fix) corrected construction of script library search path +relative to executable (porter) + +2001-08-24 (bug fix) [auto_import] now matches patterns like +[namespace import], not like [string match] (porter) + **** POTENTIAL INCOMPATABILITY **** + +2001-08-27 (new feature) added Tcl_SetMainLoop() to enable loading Tk as a +true package (hobbs) + +2001-08-30 (bug fix) build support for Crays (andreasen) + +2001-09-01 (bug fix) rewrite of Tcl_Async* APIs to better manage thread +cleanup (gravereaux) + +2001-09-06 (new feature) http 2.4: honor the Content-encoding and charset +parameters; add -binary switch for forcing the issue (hobbs, saoukhi, orwell) + +2001-09-06 (speed improvement) rewrite of file I/O flush management on +Windows. Approximately 100x speedup for some operations. (kupries, traum) + +2001-09-10 (bug fix) corrected finalization error in TclInExit (darley) + +2001-09-10 (bug fix) protect against alias loops (hobbs) + +2001-09-12 (bug fix) added missing #include in tclLoadShl.c (techentin) + +2001-09-12 (bug fix) script library path construction on Windows no longer +uses registry, nor adds the current working directory to the path (porter) + +2001-09-12 (bug fix) correct bugs in compatibility strtod() (porter) + +2001-09-13 (bug fix) Tcl_UtfPrev now returns the proper location when the +middle of a UTF-8 byte is passed in (hobbs) + +2001-09-19 (bug fix) [format] and [scan] corrected for 64-bit machines (rmax) + +2001-09-19 (new feature) --enable-64-bit support for HP-11. (hobbs) + +2001-09-19 (new feature) native memory allocator now default on Windows +(hobbs) + +2001-09-20 (new feature) WIN64 support and extra processor definitions +(hobbs, mstacy) + +2001-09-26 (bug fix) corrected potential deadlock in channels that do not +provide a BlockModeProc (kupries, kogorman) + +2001-10-03 (new feature) WIN64 build support (hobbs) + +2001-10-03 (bug fix) correction in thread finalization (rbrunner) + +2001-10-04 (new feature) updated encodings with latest mappings from +www.unicode.org (hobbs) + +2001-10-11 (bug fix) corrected cleanup of self-referential bytecodes at +interpreter deletion (sofer, rbrunner) + +2001-10-16 (new feature) config support for MacOSX / Darwin (steffen) + +2001-10-16 (new feature, Mac) change in binary extension format from MachO +bundles to standard .dylib dynamic libraries like on other unices. + **POTENTIAL INCOMPATIBILITY*** + +2001-10-18 (bug fix) corrected off-by-one-day error in clock scan with +relative months and years during swing hours. (lavana) + +--- Released 8.3.4, October 19, 2001 --- See ChangeLog for details --- + diff --git a/mk4/modtcl/tcl8.3.4/compat/CVS/Entries b/mk4/modtcl/tcl8.3.4/compat/CVS/Entries new file mode 100644 index 0000000..c475a6e --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/compat/CVS/Entries @@ -0,0 +1,24 @@ +/README/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/dirent.h/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/dirent2.h/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/dlfcn.h/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/fixstrtod.c/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/float.h/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/gettod.c/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/license.terms/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/limits.h/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/memcmp.c/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/opendir.c/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/stdlib.h/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/strftime.c/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/string.h/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/strncasecmp.c/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/strstr.c/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/strtod.c/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/strtol.c/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/strtoul.c/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/tclErrno.h/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/tmpnam.c/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/unistd.h/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/waitpid.c/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +D diff --git a/mk4/modtcl/tcl8.3.4/compat/CVS/Repository b/mk4/modtcl/tcl8.3.4/compat/CVS/Repository new file mode 100644 index 0000000..635f87c --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/compat/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/modtcl/tcl8.3.4/compat diff --git a/mk4/modtcl/tcl8.3.4/compat/CVS/Root b/mk4/modtcl/tcl8.3.4/compat/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/compat/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/modtcl/tcl8.3.4/compat/CVS/Tag b/mk4/modtcl/tcl8.3.4/compat/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/compat/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/modtcl/tcl8.3.4/compat/README b/mk4/modtcl/tcl8.3.4/compat/README new file mode 100644 index 0000000..7b65583 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/compat/README @@ -0,0 +1,8 @@ +This directory contains various header and code files that are +used make Tcl compatible with various releases of UNIX and UNIX-like +systems. Typically, files from this directory are used to compile +Tcl when a system doesn't contain the corresponding files or when +they are known to be incorrect. When the whole world becomes POSIX- +compliant this directory should be unnecessary. + +RCS: @(#) $Id: README,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ diff --git a/mk4/modtcl/tcl8.3.4/compat/dirent.h b/mk4/modtcl/tcl8.3.4/compat/dirent.h new file mode 100644 index 0000000..1a4a912 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/compat/dirent.h @@ -0,0 +1,23 @@ +/* + * dirent.h -- + * + * This file is a replacement for in systems that + * support the old BSD-style with a "struct direct". + * + * Copyright (c) 1991 The Regents of the University of California. + * Copyright (c) 1994 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id: dirent.h,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ + */ + +#ifndef _DIRENT +#define _DIRENT + +#include + +#define dirent direct + +#endif /* _DIRENT */ diff --git a/mk4/modtcl/tcl8.3.4/compat/dirent2.h b/mk4/modtcl/tcl8.3.4/compat/dirent2.h new file mode 100644 index 0000000..54e192c --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/compat/dirent2.h @@ -0,0 +1,59 @@ +/* + * dirent.h -- + * + * Declarations of a library of directory-reading procedures + * in the POSIX style ("struct dirent"). + * + * Copyright (c) 1991 The Regents of the University of California. + * Copyright (c) 1994 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id: dirent2.h,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ + */ + +#ifndef _DIRENT +#define _DIRENT + +#ifndef _TCL +#include +#endif + +/* + * Dirent structure, which holds information about a single + * directory entry. + */ + +#define MAXNAMLEN 255 +#define DIRBLKSIZ 512 + +struct dirent { + long d_ino; /* Inode number of entry */ + short d_reclen; /* Length of this record */ + short d_namlen; /* Length of string in d_name */ + char d_name[MAXNAMLEN + 1]; /* Name must be no longer than this */ +}; + +/* + * State that keeps track of the reading of a directory (clients + * should never look inside this structure; the fields should + * only be accessed by the library procedures). + */ + +typedef struct _dirdesc { + int dd_fd; + long dd_loc; + long dd_size; + char dd_buf[DIRBLKSIZ]; +} DIR; + +/* + * Procedures defined for reading directories: + */ + +extern void closedir _ANSI_ARGS_((DIR *dirp)); +extern DIR * opendir _ANSI_ARGS_((char *name)); +extern struct dirent * readdir _ANSI_ARGS_((DIR *dirp)); + +#endif /* _DIRENT */ diff --git a/mk4/modtcl/tcl8.3.4/compat/dlfcn.h b/mk4/modtcl/tcl8.3.4/compat/dlfcn.h new file mode 100644 index 0000000..a7a364f --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/compat/dlfcn.h @@ -0,0 +1,65 @@ +/* + * dlfcn.h -- + * + * This file provides a replacement for the header file "dlfcn.h" + * on systems where dlfcn.h is missing. It's primary use is for + * AIX, where Tcl emulates the dl library. + * + * This file is subject to the following copyright notice, which is + * different from the notice used elsewhere in Tcl but rougly + * equivalent in meaning. + * + * Copyright (c) 1992,1993,1995,1996, Jens-Uwe Mager, Helios Software GmbH + * Not derived from licensed software. + * + * Permission is granted to freely use, copy, modify, and redistribute + * this software, provided that the author is not construed to be liable + * for any results of using the software, alterations are clearly marked + * as such, and this notice is not modified. + * + * RCS: @(#) $Id: dlfcn.h,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ + */ + +/* + * @(#)dlfcn.h 1.4 revision of 95/04/25 09:36:52 + * This is an unpublished work copyright (c) 1992 HELIOS Software GmbH + * 30159 Hannover, Germany + */ + +#ifndef __dlfcn_h__ +#define __dlfcn_h__ + +#ifndef _TCL +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Mode flags for the dlopen routine. + */ +#define RTLD_LAZY 1 /* lazy function call binding */ +#define RTLD_NOW 2 /* immediate function call binding */ +#define RTLD_GLOBAL 0x100 /* allow symbols to be global */ + +/* + * To be able to intialize, a library may provide a dl_info structure + * that contains functions to be called to initialize and terminate. + */ +struct dl_info { + void (*init) _ANSI_ARGS_((void)); + void (*fini) _ANSI_ARGS_((void)); +}; + +VOID *dlopen _ANSI_ARGS_((const char *path, int mode)); +VOID *dlsym _ANSI_ARGS_((void *handle, const char *symbol)); +char *dlerror _ANSI_ARGS_((void)); +int dlclose _ANSI_ARGS_((void *handle)); + +#ifdef __cplusplus +} +#endif + +#endif /* __dlfcn_h__ */ diff --git a/mk4/modtcl/tcl8.3.4/compat/fixstrtod.c b/mk4/modtcl/tcl8.3.4/compat/fixstrtod.c new file mode 100644 index 0000000..a068b65 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/compat/fixstrtod.c @@ -0,0 +1,38 @@ +/* + * fixstrtod.c -- + * + * Source code for the "fixstrtod" procedure. This procedure is + * used in place of strtod under Solaris 2.4, in order to fix + * a bug where the "end" pointer gets set incorrectly. + * + * Copyright (c) 1995 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id: fixstrtod.c,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ + */ + +#include + +#undef strtod + +/* + * Declare strtod explicitly rather than including stdlib.h, since in + * somes systems (e.g. SunOS 4.1.4) stdlib.h doesn't declare strtod. + */ + +extern double strtod(); + +double +fixstrtod(string, endPtr) + char *string; + char **endPtr; +{ + double d; + d = strtod(string, endPtr); + if ((endPtr != NULL) && (*endPtr != string) && ((*endPtr)[-1] == 0)) { + *endPtr -= 1; + } + return d; +} diff --git a/mk4/modtcl/tcl8.3.4/compat/float.h b/mk4/modtcl/tcl8.3.4/compat/float.h new file mode 100644 index 0000000..bf0705b --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/compat/float.h @@ -0,0 +1,16 @@ +/* + * float.h -- + * + * This is a dummy header file to #include in Tcl when there + * is no float.h in /usr/include. Right now this file is empty: + * Tcl contains #ifdefs to deal with the lack of definitions; + * all it needs is for the #include statement to work. + * + * Copyright (c) 1993 The Regents of the University of California. + * Copyright (c) 1994 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id: float.h,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ + */ diff --git a/mk4/modtcl/tcl8.3.4/compat/gettod.c b/mk4/modtcl/tcl8.3.4/compat/gettod.c new file mode 100644 index 0000000..bee7c3d --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/compat/gettod.c @@ -0,0 +1,32 @@ +/* + * gettod.c -- + * + * This file provides the gettimeofday function on systems + * that only have the System V ftime function. + * + * Copyright (c) 1995 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id: gettod.c,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ + */ + +#include "tcl.h" +#include "tclPort.h" +#include + +#undef timezone + +int +gettimeofday(tp, tz) +struct timeval *tp; +struct timezone *tz; +{ + struct timeb t; + ftime(&t); + tp->tv_sec = t.time; + tp->tv_usec = t. millitm * 1000; + return 0; +} + diff --git a/mk4/modtcl/tcl8.3.4/compat/license.terms b/mk4/modtcl/tcl8.3.4/compat/license.terms new file mode 100644 index 0000000..9df3e60 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/compat/license.terms @@ -0,0 +1,39 @@ +This software is copyrighted by the Regents of the University of +California, Sun Microsystems, Inc., Scriptics Corporation, +and other parties. The following terms apply to all files associated +with the software unless explicitly disclaimed in individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, provided +that existing copyright notices are retained in all copies and that this +notice is included verbatim in any distributions. No written agreement, +license, or royalty fee is required for any of the authorized uses. +Modifications to this software may be copyrighted by their authors +and need not follow the licensing terms described here, provided that +the new terms are clearly indicated on the first page of each file where +they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE +IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE +NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR +MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" +in the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you +are acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. diff --git a/mk4/modtcl/tcl8.3.4/compat/limits.h b/mk4/modtcl/tcl8.3.4/compat/limits.h new file mode 100644 index 0000000..0ae75ea --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/compat/limits.h @@ -0,0 +1,24 @@ +/* + * limits.h -- + * + * This is a dummy header file to #include in Tcl when there + * is no limits.h in /usr/include. There are only a few + * definitions here; also see tclPort.h, which already + * #defines some of the things here if they're not arleady + * defined. + * + * Copyright (c) 1991 The Regents of the University of California. + * Copyright (c) 1994 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id: limits.h,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ + */ + +#define LONG_MIN 0x80000000 +#define LONG_MAX 0x7fffffff +#define INT_MIN 0x80000000 +#define INT_MAX 0x7fffffff +#define SHRT_MIN 0x8000 +#define SHRT_MAX 0x7fff diff --git a/mk4/modtcl/tcl8.3.4/compat/memcmp.c b/mk4/modtcl/tcl8.3.4/compat/memcmp.c new file mode 100644 index 0000000..09a5724 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/compat/memcmp.c @@ -0,0 +1,61 @@ +/* + * memcmp.c -- + * + * Source code for the "memcmp" library routine. + * + * Copyright (c) 1998 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) memcmp.c 1.2 98/01/19 10:48:58 + */ + +#include "tcl.h" +#include "tclPort.h" + +/* + * Here is the prototype just in case it is not included + * in tclPort.h. + */ + +int memcmp _ANSI_ARGS_((CONST VOID *s1, + CONST VOID *s2, size_t n)); + +/* + *---------------------------------------------------------------------- + * + * memcmp -- + * + * Compares two bytes sequences. + * + * Results: + * compares its arguments, looking at the first n + * bytes (each interpreted as an unsigned char), and returns + * an integer less than, equal to, or greater than 0, accord- + * ing as s1 is less than, equal to, or + * greater than s2 when taken to be unsigned 8 bit numbers. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +memcmp(s1, s2, n) + CONST VOID *s1; /* First string. */ + CONST VOID *s2; /* Second string. */ + size_t n; /* Length to compare. */ +{ + unsigned char u1, u2; + + for ( ; n-- ; s1++, s2++) { + u1 = * (unsigned char *) s1; + u2 = * (unsigned char *) s2; + if ( u1 != u2) { + return (u1-u2); + } + } + return 0; +} diff --git a/mk4/modtcl/tcl8.3.4/compat/opendir.c b/mk4/modtcl/tcl8.3.4/compat/opendir.c new file mode 100644 index 0000000..c49c8d8 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/compat/opendir.c @@ -0,0 +1,108 @@ +/* + * opendir.c -- + * + * This file provides dirent-style directory-reading procedures + * for V7 Unix systems that don't have such procedures. The + * origin of this code is unclear, but it seems to have come + * originally from Larry Wall. + * + * + * RCS: @(#) $Id: opendir.c,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ + */ + +#include "tclInt.h" +#include "tclPort.h" + +#undef DIRSIZ +#define DIRSIZ(dp) \ + ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3)) + +/* + * open a directory. + */ +DIR * +opendir(name) +char *name; +{ + register DIR *dirp; + register int fd; + char *myname; + + myname = ((*name == '\0') ? "." : name); + if ((fd = open(myname, 0, 0)) == -1) + return NULL; + if ((dirp = (DIR *)ckalloc(sizeof(DIR))) == NULL) { + close (fd); + return NULL; + } + dirp->dd_fd = fd; + dirp->dd_loc = 0; + return dirp; +} + +/* + * read an old style directory entry and present it as a new one + */ +#ifndef pyr +#define ODIRSIZ 14 + +struct olddirect { + ino_t od_ino; + char od_name[ODIRSIZ]; +}; +#else /* a Pyramid in the ATT universe */ +#define ODIRSIZ 248 + +struct olddirect { + long od_ino; + short od_fill1, od_fill2; + char od_name[ODIRSIZ]; +}; +#endif + +/* + * get next entry in a directory. + */ +struct dirent * +readdir(dirp) +register DIR *dirp; +{ + register struct olddirect *dp; + static struct dirent dir; + + for (;;) { + if (dirp->dd_loc == 0) { + dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, + DIRBLKSIZ); + if (dirp->dd_size <= 0) + return NULL; + } + if (dirp->dd_loc >= dirp->dd_size) { + dirp->dd_loc = 0; + continue; + } + dp = (struct olddirect *)(dirp->dd_buf + dirp->dd_loc); + dirp->dd_loc += sizeof(struct olddirect); + if (dp->od_ino == 0) + continue; + dir.d_ino = dp->od_ino; + strncpy(dir.d_name, dp->od_name, ODIRSIZ); + dir.d_name[ODIRSIZ] = '\0'; /* insure null termination */ + dir.d_namlen = strlen(dir.d_name); + dir.d_reclen = DIRSIZ(&dir); + return (&dir); + } +} + +/* + * close a directory. + */ +void +closedir(dirp) +register DIR *dirp; +{ + close(dirp->dd_fd); + dirp->dd_fd = -1; + dirp->dd_loc = 0; + ckfree((char *) dirp); +} diff --git a/mk4/modtcl/tcl8.3.4/compat/stdlib.h b/mk4/modtcl/tcl8.3.4/compat/stdlib.h new file mode 100644 index 0000000..42ea640 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/compat/stdlib.h @@ -0,0 +1,45 @@ +/* + * stdlib.h -- + * + * Declares facilities exported by the "stdlib" portion of + * the C library. This file isn't complete in the ANSI-C + * sense; it only declares things that are needed by Tcl. + * This file is needed even on many systems with their own + * stdlib.h (e.g. SunOS) because not all stdlib.h files + * declare all the procedures needed here (such as strtod). + * + * Copyright (c) 1991 The Regents of the University of California. + * Copyright (c) 1994-1998 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id: stdlib.h,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ + */ + +#ifndef _STDLIB +#define _STDLIB + +#include + +extern void abort _ANSI_ARGS_((void)); +extern double atof _ANSI_ARGS_((CONST char *string)); +extern int atoi _ANSI_ARGS_((CONST char *string)); +extern long atol _ANSI_ARGS_((CONST char *string)); +extern char * calloc _ANSI_ARGS_((unsigned int numElements, + unsigned int size)); +extern void exit _ANSI_ARGS_((int status)); +extern int free _ANSI_ARGS_((char *blockPtr)); +extern char * getenv _ANSI_ARGS_((CONST char *name)); +extern char * malloc _ANSI_ARGS_((unsigned int numBytes)); +extern void qsort _ANSI_ARGS_((VOID *base, int n, int size, + int (*compar)(CONST VOID *element1, CONST VOID + *element2))); +extern char * realloc _ANSI_ARGS_((char *ptr, unsigned int numBytes)); +extern double strtod _ANSI_ARGS_((CONST char *string, char **endPtr)); +extern long strtol _ANSI_ARGS_((CONST char *string, char **endPtr, + int base)); +extern unsigned long strtoul _ANSI_ARGS_((CONST char *string, + char **endPtr, int base)); + +#endif /* _STDLIB */ diff --git a/mk4/modtcl/tcl8.3.4/compat/strftime.c b/mk4/modtcl/tcl8.3.4/compat/strftime.c new file mode 100644 index 0000000..caff1ca --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/compat/strftime.c @@ -0,0 +1,393 @@ +/* + * strftime.c -- + * + * This file contains a modified version of the BSD 4.4 strftime + * function. + * + * This file is a modified version of the strftime.c file from the BSD 4.4 + * source. See the copyright notice below for details on redistribution + * restrictions. The "license.terms" file does not apply to this file. + * + * RCS: @(#) $Id: strftime.c,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ + */ + +/* + * Copyright (c) 1989 The Regents of the University of California. + * 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +#if defined(LIBC_SCCS) +static char *rcsid = "$Id: strftime.c,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $"; +#endif /* LIBC_SCCS */ + +#include +#include +#include +#include "tclInt.h" +#include "tclPort.h" + +#define TM_YEAR_BASE 1900 +#define IsLeapYear(x) ((x % 4 == 0) && (x % 100 != 0 || x % 400 == 0)) + +typedef struct { + const char *abday[7]; + const char *day[7]; + const char *abmon[12]; + const char *mon[12]; + const char *am_pm[2]; + const char *d_t_fmt; + const char *d_fmt; + const char *t_fmt; + const char *t_fmt_ampm; +} _TimeLocale; + +static const _TimeLocale _DefaultTimeLocale = +{ + { + "Sun","Mon","Tue","Wed","Thu","Fri","Sat", + }, + { + "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", + "Friday", "Saturday" + }, + { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" + }, + { + "January", "February", "March", "April", "May", "June", "July", + "August", "September", "October", "November", "December" + }, + { + "AM", "PM" + }, + "%a %b %d %H:%M:%S %Y", + "%m/%d/%y", + "%H:%M:%S", + "%I:%M:%S %p" +}; + +static const _TimeLocale *_CurrentTimeLocale = &_DefaultTimeLocale; + +static size_t gsize; +static char *pt; +static int _add _ANSI_ARGS_((const char* str)); +static int _conv _ANSI_ARGS_((int n, int digits, int pad)); +static int _secs _ANSI_ARGS_((const struct tm *t)); +static size_t _fmt _ANSI_ARGS_((const char *format, + const struct tm *t)); + +size_t +TclpStrftime(s, maxsize, format, t) + char *s; + size_t maxsize; + const char *format; + const struct tm *t; +{ + if (format[0] == '%' && format[1] == 'Q') { + /* Format as a stardate */ + sprintf(s, "Stardate %2d%03d.%01d", + (((t->tm_year + TM_YEAR_BASE) + 377) - 2323), + (((t->tm_yday + 1) * 1000) / + (365 + IsLeapYear((t->tm_year + TM_YEAR_BASE)))), + (((t->tm_hour * 60) + t->tm_min)/144)); + return(strlen(s)); + } + + tzset(); + + pt = s; + if ((gsize = maxsize) < 1) + return(0); + if (_fmt(format, t)) { + *pt = '\0'; + return(maxsize - gsize); + } + return(0); +} + +#define SUN_WEEK(t) (((t)->tm_yday + 7 - \ + ((t)->tm_wday)) / 7) +#define MON_WEEK(t) (((t)->tm_yday + 7 - \ + ((t)->tm_wday ? (t)->tm_wday - 1 : 6)) / 7) + +static size_t +_fmt(format, t) + const char *format; + const struct tm *t; +{ + for (; *format; ++format) { + if (*format == '%') { + ++format; + if (*format == 'E') { + /* Alternate Era */ + ++format; + } else if (*format == 'O') { + /* Alternate numeric symbols */ + ++format; + } + switch(*format) { + case '\0': + --format; + break; + case 'A': + if (t->tm_wday < 0 || t->tm_wday > 6) + return(0); + if (!_add(_CurrentTimeLocale->day[t->tm_wday])) + return(0); + continue; + case 'a': + if (t->tm_wday < 0 || t->tm_wday > 6) + return(0); + if (!_add(_CurrentTimeLocale->abday[t->tm_wday])) + return(0); + continue; + case 'B': + if (t->tm_mon < 0 || t->tm_mon > 11) + return(0); + if (!_add(_CurrentTimeLocale->mon[t->tm_mon])) + return(0); + continue; + case 'b': + case 'h': + if (t->tm_mon < 0 || t->tm_mon > 11) + return(0); + if (!_add(_CurrentTimeLocale->abmon[t->tm_mon])) + return(0); + continue; + case 'C': + if (!_conv((t->tm_year + TM_YEAR_BASE) / 100, + 2, '0')) + return(0); + continue; + case 'c': + if (!_fmt(_CurrentTimeLocale->d_t_fmt, t)) + return(0); + continue; + case 'D': + if (!_fmt("%m/%d/%y", t)) + return(0); + continue; + case 'd': + if (!_conv(t->tm_mday, 2, '0')) + return(0); + continue; + case 'e': + if (!_conv(t->tm_mday, 2, ' ')) + return(0); + continue; + case 'H': + if (!_conv(t->tm_hour, 2, '0')) + return(0); + continue; + case 'I': + if (!_conv(t->tm_hour % 12 ? + t->tm_hour % 12 : 12, 2, '0')) + return(0); + continue; + case 'j': + if (!_conv(t->tm_yday + 1, 3, '0')) + return(0); + continue; + case 'k': + if (!_conv(t->tm_hour, 2, ' ')) + return(0); + continue; + case 'l': + if (!_conv(t->tm_hour % 12 ? + t->tm_hour % 12: 12, 2, ' ')) + return(0); + continue; + case 'M': + if (!_conv(t->tm_min, 2, '0')) + return(0); + continue; + case 'm': + if (!_conv(t->tm_mon + 1, 2, '0')) + return(0); + continue; + case 'n': + if (!_add("\n")) + return(0); + continue; + case 'p': + if (!_add(_CurrentTimeLocale->am_pm[t->tm_hour >= 12])) + return(0); + continue; + case 'R': + if (!_fmt("%H:%M", t)) + return(0); + continue; + case 'r': + if (!_fmt(_CurrentTimeLocale->t_fmt_ampm, t)) + return(0); + continue; + case 'S': + if (!_conv(t->tm_sec, 2, '0')) + return(0); + continue; + case 's': + if (!_secs(t)) + return(0); + continue; + case 'T': + if (!_fmt("%H:%M:%S", t)) + return(0); + continue; + case 't': + if (!_add("\t")) + return(0); + continue; + case 'U': + if (!_conv(SUN_WEEK(t), 2, '0')) + return(0); + continue; + case 'u': + if (!_conv(t->tm_wday ? t->tm_wday : 7, 1, '0')) + return(0); + continue; + case 'V': + { + /* ISO 8601 Week Of Year: + If the week (Monday - Sunday) containing + January 1 has four or more days in the new + year, then it is week 1; otherwise it is + week 53 of the previous year and the next + week is week one. */ + + int week = MON_WEEK(t); + + int days = (((t)->tm_yday + 7 - \ + ((t)->tm_wday ? (t)->tm_wday - 1 : 6)) % 7); + + + if (days >= 4) { + week++; + } else if (week == 0) { + week = 53; + } + + if (!_conv(week, 2, '0')) + return(0); + continue; + } + case 'W': + if (!_conv(MON_WEEK(t), 2, '0')) + return(0); + continue; + case 'w': + if (!_conv(t->tm_wday, 1, '0')) + return(0); + continue; + case 'x': + if (!_fmt(_CurrentTimeLocale->d_fmt, t)) + return(0); + continue; + case 'X': + if (!_fmt(_CurrentTimeLocale->t_fmt, t)) + return(0); + continue; + case 'y': + if (!_conv((t->tm_year + TM_YEAR_BASE) % 100, + 2, '0')) + return(0); + continue; + case 'Y': + if (!_conv((t->tm_year + TM_YEAR_BASE), 4, '0')) + return(0); + continue; + case 'Z': { + char *name = TclpGetTZName(t->tm_isdst); + if (name && !_add(name)) { + return 0; + } + continue; + } + case '%': + /* + * X311J/88-090 (4.12.3.5): if conversion char is + * undefined, behavior is undefined. Print out the + * character itself as printf(3) does. + */ + default: + break; + } + } + if (!gsize--) + return(0); + *pt++ = *format; + } + return(gsize); +} + +static int +_secs(t) + const struct tm *t; +{ + static char buf[15]; + register time_t s; + register char *p; + struct tm tmp; + + /* Make a copy, mktime(3) modifies the tm struct. */ + tmp = *t; + s = mktime(&tmp); + for (p = buf + sizeof(buf) - 2; s > 0 && p > buf; s /= 10) + *p-- = (char)(s % 10 + '0'); + return(_add(++p)); +} + +static int +_conv(n, digits, pad) + int n, digits; + int pad; +{ + static char buf[10]; + register char *p; + + for (p = buf + sizeof(buf) - 2; n > 0 && p > buf; n /= 10, --digits) + *p-- = (char)(n % 10 + '0'); + while (p > buf && digits-- > 0) + *p-- = (char) pad; + return(_add(++p)); +} + +static int +_add(str) + const char *str; +{ + for (;; ++pt, --gsize) { + if (!gsize) + return(0); + if (!(*pt = *str++)) + return(1); + } +} diff --git a/mk4/modtcl/tcl8.3.4/compat/string.h b/mk4/modtcl/tcl8.3.4/compat/string.h new file mode 100644 index 0000000..7eed98c --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/compat/string.h @@ -0,0 +1,71 @@ +/* + * string.h -- + * + * Declarations of ANSI C library procedures for string handling. + * + * Copyright (c) 1991-1993 The Regents of the University of California. + * Copyright (c) 1994-1996 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id: string.h,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ + */ + +#ifndef _STRING +#define _STRING + +#include + +/* + * The following #include is needed to define size_t. (This used to + * include sys/stdtypes.h but that doesn't exist on older versions + * of SunOS, e.g. 4.0.2, so I'm trying sys/types.h now.... hopefully + * it exists everywhere) + */ + +#ifndef MAC_TCL +#include +#endif + +extern char * memchr _ANSI_ARGS_((CONST VOID *s, int c, size_t n)); +extern int memcmp _ANSI_ARGS_((CONST VOID *s1, CONST VOID *s2, + size_t n)); +extern char * memcpy _ANSI_ARGS_((VOID *t, CONST VOID *f, size_t n)); +#ifdef NO_MEMMOVE +#define memmove(d, s, n) bcopy ((s), (d), (n)) +#else +extern char * memmove _ANSI_ARGS_((VOID *t, CONST VOID *f, + size_t n)); +#endif +extern char * memset _ANSI_ARGS_((VOID *s, int c, size_t n)); + +extern int strcasecmp _ANSI_ARGS_((CONST char *s1, + CONST char *s2)); +extern char * strcat _ANSI_ARGS_((char *dst, CONST char *src)); +extern char * strchr _ANSI_ARGS_((CONST char *string, int c)); +extern int strcmp _ANSI_ARGS_((CONST char *s1, CONST char *s2)); +extern char * strcpy _ANSI_ARGS_((char *dst, CONST char *src)); +extern size_t strcspn _ANSI_ARGS_((CONST char *string, + CONST char *chars)); +extern char * strdup _ANSI_ARGS_((CONST char *string)); +extern char * strerror _ANSI_ARGS_((int error)); +extern size_t strlen _ANSI_ARGS_((CONST char *string)); +extern int strncasecmp _ANSI_ARGS_((CONST char *s1, + CONST char *s2, size_t n)); +extern char * strncat _ANSI_ARGS_((char *dst, CONST char *src, + size_t numChars)); +extern int strncmp _ANSI_ARGS_((CONST char *s1, CONST char *s2, + size_t nChars)); +extern char * strncpy _ANSI_ARGS_((char *dst, CONST char *src, + size_t numChars)); +extern char * strpbrk _ANSI_ARGS_((CONST char *string, + CONST char *chars)); +extern char * strrchr _ANSI_ARGS_((CONST char *string, int c)); +extern size_t strspn _ANSI_ARGS_((CONST char *string, + CONST char *chars)); +extern char * strstr _ANSI_ARGS_((CONST char *string, + CONST char *substring)); +extern char * strtok _ANSI_ARGS_((char *s, CONST char *delim)); + +#endif /* _STRING */ diff --git a/mk4/modtcl/tcl8.3.4/compat/strncasecmp.c b/mk4/modtcl/tcl8.3.4/compat/strncasecmp.c new file mode 100644 index 0000000..4dc16b2 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/compat/strncasecmp.c @@ -0,0 +1,142 @@ +/* + * strncasecmp.c -- + * + * Source code for the "strncasecmp" library routine. + * + * Copyright (c) 1988-1993 The Regents of the University of California. + * Copyright (c) 1995-1996 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id: strncasecmp.c,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ + */ + +#include "tclPort.h" + +/* + * This array is designed for mapping upper and lower case letter + * together for a case independent comparison. The mappings are + * based upon ASCII character sequences. + */ + +static unsigned char charmap[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xe1, 0xe2, 0xe3, 0xe4, 0xc5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, +}; + +/* + * Here are the prototypes just in case they are not included + * in tclPort.h. + */ +int strncasecmp _ANSI_ARGS_((CONST char *s1, + CONST char *s2, size_t n)); + +int strcasecmp _ANSI_ARGS_((CONST char *s1, + CONST char *s2)); + +/* + *---------------------------------------------------------------------- + * + * strcasecmp -- + * + * Compares two strings, ignoring case differences. + * + * Results: + * Compares two null-terminated strings s1 and s2, returning -1, 0, + * or 1 if s1 is lexicographically less than, equal to, or greater + * than s2. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +strcasecmp(s1, s2) + CONST char *s1; /* First string. */ + CONST char *s2; /* Second string. */ +{ + unsigned char u1, u2; + + for ( ; ; s1++, s2++) { + u1 = (unsigned char) *s1; + u2 = (unsigned char) *s2; + if ((u1 == '\0') || (charmap[u1] != charmap[u2])) { + break; + } + } + return charmap[u1] - charmap[u2]; +} + +/* + *---------------------------------------------------------------------- + * + * strncasecmp -- + * + * Compares two strings, ignoring case differences. + * + * Results: + * Compares up to length chars of s1 and s2, returning -1, 0, or 1 + * if s1 is lexicographically less than, equal to, or greater + * than s2 over those characters. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +strncasecmp(s1, s2, length) + CONST char *s1; /* First string. */ + CONST char *s2; /* Second string. */ + size_t length; /* Maximum number of characters to compare + * (stop earlier if the end of either string + * is reached). */ +{ + unsigned char u1, u2; + + for (; length != 0; length--, s1++, s2++) { + u1 = (unsigned char) *s1; + u2 = (unsigned char) *s2; + if (charmap[u1] != charmap[u2]) { + return charmap[u1] - charmap[u2]; + } + if (u1 == '\0') { + return 0; + } + } + return 0; +} diff --git a/mk4/modtcl/tcl8.3.4/compat/strstr.c b/mk4/modtcl/tcl8.3.4/compat/strstr.c new file mode 100644 index 0000000..7284a2d --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/compat/strstr.c @@ -0,0 +1,68 @@ +/* + * strstr.c -- + * + * Source code for the "strstr" library routine. + * + * Copyright (c) 1988-1993 The Regents of the University of California. + * Copyright (c) 1994 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id: strstr.c,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ + */ + +/* + *---------------------------------------------------------------------- + * + * strstr -- + * + * Locate the first instance of a substring in a string. + * + * Results: + * If string contains substring, the return value is the + * location of the first matching instance of substring + * in string. If string doesn't contain substring, the + * return value is 0. Matching is done on an exact + * character-for-character basis with no wildcards or special + * characters. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +char * +strstr(string, substring) + register char *string; /* String to search. */ + char *substring; /* Substring to try to find in string. */ +{ + register char *a, *b; + + /* First scan quickly through the two strings looking for a + * single-character match. When it's found, then compare the + * rest of the substring. + */ + + b = substring; + if (*b == 0) { + return string; + } + for ( ; *string != 0; string += 1) { + if (*string != *b) { + continue; + } + a = string; + while (1) { + if (*b == 0) { + return string; + } + if (*a++ != *b++) { + break; + } + } + b = substring; + } + return (char *) 0; +} diff --git a/mk4/modtcl/tcl8.3.4/compat/strtod.c b/mk4/modtcl/tcl8.3.4/compat/strtod.c new file mode 100644 index 0000000..9c308ee --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/compat/strtod.c @@ -0,0 +1,263 @@ +/* + * strtod.c -- + * + * Source code for the "strtod" library procedure. + * + * Copyright (c) 1988-1993 The Regents of the University of California. + * Copyright (c) 1994 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id: strtod.c,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ + */ + +#include "tcl.h" +#ifdef NO_STDLIB_H +# include "../compat/stdlib.h" +#else +# include +#endif +#include +#include "tclPort.h" + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif +#ifndef NULL +#define NULL 0 +#endif + +static int maxExponent = 511; /* Largest possible base 10 exponent. Any + * exponent larger than this will already + * produce underflow or overflow, so there's + * no need to worry about additional digits. + */ +static double powersOf10[] = { /* Table giving binary powers of 10. Entry */ + 10., /* is 10^2^i. Used to convert decimal */ + 100., /* exponents into floating-point numbers. */ + 1.0e4, + 1.0e8, + 1.0e16, + 1.0e32, + 1.0e64, + 1.0e128, + 1.0e256 +}; + +/* + *---------------------------------------------------------------------- + * + * strtod -- + * + * This procedure converts a floating-point number from an ASCII + * decimal representation to internal double-precision format. + * + * Results: + * The return value is the double-precision floating-point + * representation of the characters in string. If endPtr isn't + * NULL, then *endPtr is filled in with the address of the + * next character after the last one that was part of the + * floating-point number. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +double +strtod(string, endPtr) + CONST char *string; /* A decimal ASCII floating-point number, + * optionally preceded by white space. + * Must have form "-I.FE-X", where I is the + * integer part of the mantissa, F is the + * fractional part of the mantissa, and X + * is the exponent. Either of the signs + * may be "+", "-", or omitted. Either I + * or F may be omitted, or both. The decimal + * point isn't necessary unless F is present. + * The "E" may actually be an "e". E and X + * may both be omitted (but not just one). + */ + char **endPtr; /* If non-NULL, store terminating character's + * address here. */ +{ + int sign, expSign = FALSE; + double fraction, dblExp, *d; + register CONST char *p; + register int c; + int exp = 0; /* Exponent read from "EX" field. */ + int fracExp = 0; /* Exponent that derives from the fractional + * part. Under normal circumstatnces, it is + * the negative of the number of digits in F. + * However, if I is very long, the last digits + * of I get dropped (otherwise a long I with a + * large negative exponent could cause an + * unnecessary overflow on I alone). In this + * case, fracExp is incremented one for each + * dropped digit. */ + int mantSize; /* Number of digits in mantissa. */ + int decPt; /* Number of mantissa digits BEFORE decimal + * point. */ + CONST char *pExp; /* Temporarily holds location of exponent + * in string. */ + + /* + * Strip off leading blanks and check for a sign. + */ + + p = string; + while (isspace(*p)) { + p += 1; + } + if (*p == '-') { + sign = TRUE; + p += 1; + } else { + if (*p == '+') { + p += 1; + } + sign = FALSE; + } + + /* + * Count the number of digits in the mantissa (including the decimal + * point), and also locate the decimal point. + */ + + decPt = -1; + for (mantSize = 0; ; mantSize += 1) + { + c = *p; + if (!isdigit(c)) { + if ((c != '.') || (decPt >= 0)) { + break; + } + decPt = mantSize; + } + p += 1; + } + + /* + * Now suck up the digits in the mantissa. Use two integers to + * collect 9 digits each (this is faster than using floating-point). + * If the mantissa has more than 18 digits, ignore the extras, since + * they can't affect the value anyway. + */ + + pExp = p; + p -= mantSize; + if (decPt < 0) { + decPt = mantSize; + } else { + mantSize -= 1; /* One of the digits was the point. */ + } + if (mantSize > 18) { + fracExp = decPt - 18; + mantSize = 18; + } else { + fracExp = decPt - mantSize; + } + if (mantSize == 0) { + fraction = 0.0; + p = string; + goto done; + } else { + int frac1, frac2; + frac1 = 0; + for ( ; mantSize > 9; mantSize -= 1) + { + c = *p; + p += 1; + if (c == '.') { + c = *p; + p += 1; + } + frac1 = 10*frac1 + (c - '0'); + } + frac2 = 0; + for (; mantSize > 0; mantSize -= 1) + { + c = *p; + p += 1; + if (c == '.') { + c = *p; + p += 1; + } + frac2 = 10*frac2 + (c - '0'); + } + fraction = (1.0e9 * frac1) + frac2; + } + + /* + * Skim off the exponent. + */ + + p = pExp; + if ((*p == 'E') || (*p == 'e')) { + p += 1; + if (*p == '-') { + expSign = TRUE; + p += 1; + } else { + if (*p == '+') { + p += 1; + } + expSign = FALSE; + } + if (!isdigit(*p)) { + p = pExp; + goto done; + } + while (isdigit(*p)) { + exp = exp * 10 + (*p - '0'); + p += 1; + } + } + if (expSign) { + exp = fracExp - exp; + } else { + exp = fracExp + exp; + } + + /* + * Generate a floating-point number that represents the exponent. + * Do this by processing the exponent one bit at a time to combine + * many powers of 2 of 10. Then combine the exponent with the + * fraction. + */ + + if (exp < 0) { + expSign = TRUE; + exp = -exp; + } else { + expSign = FALSE; + } + if (exp > maxExponent) { + exp = maxExponent; + errno = ERANGE; + } + dblExp = 1.0; + for (d = powersOf10; exp != 0; exp >>= 1, d += 1) { + if (exp & 01) { + dblExp *= *d; + } + } + if (expSign) { + fraction /= dblExp; + } else { + fraction *= dblExp; + } + +done: + if (endPtr != NULL) { + *endPtr = (char *) p; + } + + if (sign) { + return -fraction; + } + return fraction; +} diff --git a/mk4/modtcl/tcl8.3.4/compat/strtol.c b/mk4/modtcl/tcl8.3.4/compat/strtol.c new file mode 100644 index 0000000..c56dc19 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/compat/strtol.c @@ -0,0 +1,83 @@ +/* + * strtol.c -- + * + * Source code for the "strtol" library procedure. + * + * Copyright (c) 1988 The Regents of the University of California. + * Copyright (c) 1994 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id: strtol.c,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ + */ + +#include + + +/* + *---------------------------------------------------------------------- + * + * strtol -- + * + * Convert an ASCII string into an integer. + * + * Results: + * The return value is the integer equivalent of string. If endPtr + * is non-NULL, then *endPtr is filled in with the character + * after the last one that was part of the integer. If string + * doesn't contain a valid integer value, then zero is returned + * and *endPtr is set to string. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +long int +strtol(string, endPtr, base) + char *string; /* String of ASCII digits, possibly + * preceded by white space. For bases + * greater than 10, either lower- or + * upper-case digits may be used. + */ + char **endPtr; /* Where to store address of terminating + * character, or NULL. */ + int base; /* Base for conversion. Must be less + * than 37. If 0, then the base is chosen + * from the leading characters of string: + * "0x" means hex, "0" means octal, anything + * else means decimal. + */ +{ + register char *p; + int result; + + /* + * Skip any leading blanks. + */ + + p = string; + while (isspace(*p)) { + p += 1; + } + + /* + * Check for a sign. + */ + + if (*p == '-') { + p += 1; + result = -(strtoul(p, endPtr, base)); + } else { + if (*p == '+') { + p += 1; + } + result = strtoul(p, endPtr, base); + } + if ((result == 0) && (endPtr != 0) && (*endPtr == p)) { + *endPtr = string; + } + return result; +} diff --git a/mk4/modtcl/tcl8.3.4/compat/strtoul.c b/mk4/modtcl/tcl8.3.4/compat/strtoul.c new file mode 100644 index 0000000..6115aff --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/compat/strtoul.c @@ -0,0 +1,183 @@ +/* + * strtoul.c -- + * + * Source code for the "strtoul" library procedure. + * + * Copyright (c) 1988 The Regents of the University of California. + * Copyright (c) 1994 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id: strtoul.c,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ + */ + +#include + +/* + * The table below is used to convert from ASCII digits to a + * numerical equivalent. It maps from '0' through 'z' to integers + * (100 for non-digit characters). + */ + +static char cvtIn[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, /* '0' - '9' */ + 100, 100, 100, 100, 100, 100, 100, /* punctuation */ + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, /* 'A' - 'Z' */ + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, + 100, 100, 100, 100, 100, 100, /* punctuation */ + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, /* 'a' - 'z' */ + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35}; + +/* + *---------------------------------------------------------------------- + * + * strtoul -- + * + * Convert an ASCII string into an integer. + * + * Results: + * The return value is the integer equivalent of string. If endPtr + * is non-NULL, then *endPtr is filled in with the character + * after the last one that was part of the integer. If string + * doesn't contain a valid integer value, then zero is returned + * and *endPtr is set to string. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +unsigned long int +strtoul(string, endPtr, base) + char *string; /* String of ASCII digits, possibly + * preceded by white space. For bases + * greater than 10, either lower- or + * upper-case digits may be used. + */ + char **endPtr; /* Where to store address of terminating + * character, or NULL. */ + int base; /* Base for conversion. Must be less + * than 37. If 0, then the base is chosen + * from the leading characters of string: + * "0x" means hex, "0" means octal, anything + * else means decimal. + */ +{ + register char *p; + register unsigned long int result = 0; + register unsigned digit; + int anyDigits = 0; + + /* + * Skip any leading blanks. + */ + + p = string; + while (isspace(*p)) { + p += 1; + } + + /* + * If no base was provided, pick one from the leading characters + * of the string. + */ + + if (base == 0) + { + if (*p == '0') { + p += 1; + if (*p == 'x') { + p += 1; + base = 16; + } else { + + /* + * Must set anyDigits here, otherwise "0" produces a + * "no digits" error. + */ + + anyDigits = 1; + base = 8; + } + } + else base = 10; + } else if (base == 16) { + + /* + * Skip a leading "0x" from hex numbers. + */ + + if ((p[0] == '0') && (p[1] == 'x')) { + p += 2; + } + } + + /* + * Sorry this code is so messy, but speed seems important. Do + * different things for base 8, 10, 16, and other. + */ + + if (base == 8) { + for ( ; ; p += 1) { + digit = *p - '0'; + if (digit > 7) { + break; + } + result = (result << 3) + digit; + anyDigits = 1; + } + } else if (base == 10) { + for ( ; ; p += 1) { + digit = *p - '0'; + if (digit > 9) { + break; + } + result = (10*result) + digit; + anyDigits = 1; + } + } else if (base == 16) { + for ( ; ; p += 1) { + digit = *p - '0'; + if (digit > ('z' - '0')) { + break; + } + digit = cvtIn[digit]; + if (digit > 15) { + break; + } + result = (result << 4) + digit; + anyDigits = 1; + } + } else { + for ( ; ; p += 1) { + digit = *p - '0'; + if (digit > ('z' - '0')) { + break; + } + digit = cvtIn[digit]; + if (digit >= base) { + break; + } + result = result*base + digit; + anyDigits = 1; + } + } + + /* + * See if there were any digits at all. + */ + + if (!anyDigits) { + p = string; + } + + if (endPtr != 0) { + *endPtr = p; + } + + return result; +} diff --git a/mk4/modtcl/tcl8.3.4/compat/tclErrno.h b/mk4/modtcl/tcl8.3.4/compat/tclErrno.h new file mode 100644 index 0000000..5229847 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/compat/tclErrno.h @@ -0,0 +1,100 @@ +/* + * tclErrno.h -- + * + * This header file contains the various POSIX errno definitions that + * are used by Tcl. This file is derived from the spec POSIX 2.4 and + * previous implementations for Berkeley UNIX. + * + * Copyright (c) 1982, 1986, 1989 Regents of the University of California. + * Copyright (c) 1996 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id: tclErrno.h,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ + */ + +extern int errno; /* global error number */ + +#define EPERM 1 /* Operation not permitted */ +#define ENOENT 2 /* No such file or directory */ +#define ESRCH 3 /* No such process */ +#define EINTR 4 /* Interrupted system call */ +#define EIO 5 /* Input/output error */ +#define ENXIO 6 /* Device not configured */ +#define E2BIG 7 /* Argument list too long */ +#define ENOEXEC 8 /* Exec format error */ +#define EBADF 9 /* Bad file descriptor */ +#define ECHILD 10 /* No child processes */ +#define EDEADLK 11 /* Resource deadlock avoided */ + /* 11 was EAGAIN */ +#define ENOMEM 12 /* Cannot allocate memory */ +#define EACCES 13 /* Permission denied */ +#define EFAULT 14 /* Bad address */ +#define ENOTBLK 15 /* Block device required */ +#define EBUSY 16 /* Device busy */ +#define EEXIST 17 /* File exists */ +#define EXDEV 18 /* Cross-device link */ +#define ENODEV 19 /* Operation not supported by device */ +#define ENOTDIR 20 /* Not a directory */ +#define EISDIR 21 /* Is a directory */ +#define EINVAL 22 /* Invalid argument */ +#define ENFILE 23 /* Too many open files in system */ +#define EMFILE 24 /* Too many open files */ +#define ENOTTY 25 /* Inappropriate ioctl for device */ +#define ETXTBSY 26 /* Text file busy */ +#define EFBIG 27 /* File too large */ +#define ENOSPC 28 /* No space left on device */ +#define ESPIPE 29 /* Illegal seek */ +#define EROFS 30 /* Read-only file system */ +#define EMLINK 31 /* Too many links */ +#define EPIPE 32 /* Broken pipe */ +#define EDOM 33 /* Numerical argument out of domain */ +#define ERANGE 34 /* Result too large */ +#define EAGAIN 35 /* Resource temporarily unavailable */ +#define EWOULDBLOCK EAGAIN /* Operation would block */ +#define EINPROGRESS 36 /* Operation now in progress */ +#define EALREADY 37 /* Operation already in progress */ +#define ENOTSOCK 38 /* Socket operation on non-socket */ +#define EDESTADDRREQ 39 /* Destination address required */ +#define EMSGSIZE 40 /* Message too long */ +#define EPROTOTYPE 41 /* Protocol wrong type for socket */ +#define ENOPROTOOPT 42 /* Protocol not available */ +#define EPROTONOSUPPORT 43 /* Protocol not supported */ +#define ESOCKTNOSUPPORT 44 /* Socket type not supported */ +#define EOPNOTSUPP 45 /* Operation not supported on socket */ +#define EPFNOSUPPORT 46 /* Protocol family not supported */ +#define EAFNOSUPPORT 47 /* Address family not supported by protocol family */ +#define EADDRINUSE 48 /* Address already in use */ +#define EADDRNOTAVAIL 49 /* Can't assign requested address */ +#define ENETDOWN 50 /* Network is down */ +#define ENETUNREACH 51 /* Network is unreachable */ +#define ENETRESET 52 /* Network dropped connection on reset */ +#define ECONNABORTED 53 /* Software caused connection abort */ +#define ECONNRESET 54 /* Connection reset by peer */ +#define ENOBUFS 55 /* No buffer space available */ +#define EISCONN 56 /* Socket is already connected */ +#define ENOTCONN 57 /* Socket is not connected */ +#define ESHUTDOWN 58 /* Can't send after socket shutdown */ +#define ETOOMANYREFS 59 /* Too many references: can't splice */ +#define ETIMEDOUT 60 /* Connection timed out */ +#define ECONNREFUSED 61 /* Connection refused */ +#define ELOOP 62 /* Too many levels of symbolic links */ +#define ENAMETOOLONG 63 /* File name too long */ +#define EHOSTDOWN 64 /* Host is down */ +#define EHOSTUNREACH 65 /* No route to host */ +#define ENOTEMPTY 66 /* Directory not empty */ +#define EPROCLIM 67 /* Too many processes */ +#define EUSERS 68 /* Too many users */ +#define EDQUOT 69 /* Disc quota exceeded */ +#define ESTALE 70 /* Stale NFS file handle */ +#define EREMOTE 71 /* Too many levels of remote in path */ +#define EBADRPC 72 /* RPC struct is bad */ +#define ERPCMISMATCH 73 /* RPC version wrong */ +#define EPROGUNAVAIL 74 /* RPC prog. not avail */ +#define EPROGMISMATCH 75 /* Program version wrong */ +#define EPROCUNAVAIL 76 /* Bad procedure for program */ +#define ENOLCK 77 /* No locks available */ +#define ENOSYS 78 /* Function not implemented */ +#define EFTYPE 79 /* Inappropriate file type or format */ + diff --git a/mk4/modtcl/tcl8.3.4/compat/tmpnam.c b/mk4/modtcl/tcl8.3.4/compat/tmpnam.c new file mode 100644 index 0000000..d392269 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/compat/tmpnam.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 1988 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that this notice is preserved and that due credit is given + * to the University of California at Berkeley. The name of the University + * may not be used to endorse or promote products derived from this + * software without specific written prior permission. This software + * is provided ``as is'' without express or implied warranty. + * + * RCS: @(#) $Id: tmpnam.c,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ + */ + +#include +#include +#include +#include + +/* + * Use /tmp instead of /usr/tmp, because L_tmpname is only 14 chars + * on some machines (like NeXT machines) and /usr/tmp will cause + * buffer overflows. + */ + +#ifdef P_tmpdir +# undef P_tmpdir +#endif +#define P_tmpdir "/tmp" + +char * +tmpnam(s) + char *s; +{ + static char name[50]; + char *mktemp(); + + if (!s) + s = name; + (void)sprintf(s, "%s/XXXXXX", P_tmpdir); + return(mktemp(s)); +} diff --git a/mk4/modtcl/tcl8.3.4/compat/unistd.h b/mk4/modtcl/tcl8.3.4/compat/unistd.h new file mode 100644 index 0000000..c59a68d --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/compat/unistd.h @@ -0,0 +1,84 @@ +/* + * unistd.h -- + * + * Macros, CONSTants and prototypes for Posix conformance. + * + * Copyright 1989 Regents of the University of California + * 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. The University of California + * makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without + * express or implied warranty. + * + * RCS: @(#) $Id: unistd.h,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ + */ + +#ifndef _UNISTD +#define _UNISTD + +#include +#ifndef _TCL +# include "tcl.h" +#endif + +#ifndef NULL +#define NULL 0 +#endif + +/* + * Strict POSIX stuff goes here. Extensions go down below, in the + * ifndef _POSIX_SOURCE section. + */ + +extern void _exit _ANSI_ARGS_((int status)); +extern int access _ANSI_ARGS_((CONST char *path, int mode)); +extern int chdir _ANSI_ARGS_((CONST char *path)); +extern int chown _ANSI_ARGS_((CONST char *path, uid_t owner, gid_t group)); +extern int close _ANSI_ARGS_((int fd)); +extern int dup _ANSI_ARGS_((int oldfd)); +extern int dup2 _ANSI_ARGS_((int oldfd, int newfd)); +extern int execl _ANSI_ARGS_((CONST char *path, ...)); +extern int execle _ANSI_ARGS_((CONST char *path, ...)); +extern int execlp _ANSI_ARGS_((CONST char *file, ...)); +extern int execv _ANSI_ARGS_((CONST char *path, char **argv)); +extern int execve _ANSI_ARGS_((CONST char *path, char **argv, char **envp)); +extern int execvp _ANSI_ARGS_((CONST char *file, char **argv)); +extern pid_t fork _ANSI_ARGS_((void)); +extern char *getcwd _ANSI_ARGS_((char *buf, size_t size)); +extern gid_t getegid _ANSI_ARGS_((void)); +extern uid_t geteuid _ANSI_ARGS_((void)); +extern gid_t getgid _ANSI_ARGS_((void)); +extern int getgroups _ANSI_ARGS_((int bufSize, int *buffer)); +extern pid_t getpid _ANSI_ARGS_((void)); +extern uid_t getuid _ANSI_ARGS_((void)); +extern int isatty _ANSI_ARGS_((int fd)); +extern long lseek _ANSI_ARGS_((int fd, long offset, int whence)); +extern int pipe _ANSI_ARGS_((int *fildes)); +extern int read _ANSI_ARGS_((int fd, char *buf, size_t size)); +extern int setgid _ANSI_ARGS_((gid_t group)); +extern int setuid _ANSI_ARGS_((uid_t user)); +extern unsigned sleep _ANSI_ARGS_ ((unsigned seconds)); +extern char *ttyname _ANSI_ARGS_((int fd)); +extern int unlink _ANSI_ARGS_((CONST char *path)); +extern int write _ANSI_ARGS_((int fd, CONST char *buf, size_t size)); + +#ifndef _POSIX_SOURCE +extern char *crypt _ANSI_ARGS_((CONST char *, CONST char *)); +extern int fchown _ANSI_ARGS_((int fd, uid_t owner, gid_t group)); +extern int flock _ANSI_ARGS_((int fd, int operation)); +extern int ftruncate _ANSI_ARGS_((int fd, unsigned long length)); +extern int ioctl _ANSI_ARGS_((int fd, int request, ...)); +extern int readlink _ANSI_ARGS_((CONST char *path, char *buf, int bufsize)); +extern int setegid _ANSI_ARGS_((gid_t group)); +extern int seteuid _ANSI_ARGS_((uid_t user)); +extern int setreuid _ANSI_ARGS_((int ruid, int euid)); +extern int symlink _ANSI_ARGS_((CONST char *, CONST char *)); +extern int ttyslot _ANSI_ARGS_((void)); +extern int truncate _ANSI_ARGS_((CONST char *path, unsigned long length)); +extern int vfork _ANSI_ARGS_((void)); +#endif /* _POSIX_SOURCE */ + +#endif /* _UNISTD */ + diff --git a/mk4/modtcl/tcl8.3.4/compat/waitpid.c b/mk4/modtcl/tcl8.3.4/compat/waitpid.c new file mode 100644 index 0000000..74852a5 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/compat/waitpid.c @@ -0,0 +1,174 @@ +/* + * waitpid.c -- + * + * This procedure emulates the POSIX waitpid kernel call on + * BSD systems that don't have waitpid but do have wait3. + * This code is based on a prototype version written by + * Mark Diekhans and Karl Lehenbauer. + * + * Copyright (c) 1993 The Regents of the University of California. + * Copyright (c) 1994 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id: waitpid.c,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ + */ + +#include "tclInt.h" +#include "tclPort.h" + +#ifndef pid_t +#define pid_t int +#endif + +/* + * A linked list of the following structures is used to keep track + * of processes for which we received notification from the kernel, + * but the application hasn't waited for them yet (this can happen + * because wait may not return the process we really want). We + * save the information here until the application finally does + * wait for the process. + */ + +typedef struct WaitInfo { + pid_t pid; /* Pid of process that exited. */ + WAIT_STATUS_TYPE status; /* Status returned when child exited + * or suspended. */ + struct WaitInfo *nextPtr; /* Next in list of exited processes. */ +} WaitInfo; + +static WaitInfo *deadList = NULL; /* First in list of all dead + * processes. */ + +/* + *---------------------------------------------------------------------- + * + * waitpid -- + * + * This procedure emulates the functionality of the POSIX + * waitpid kernel call, using the BSD wait3 kernel call. + * Note: it doesn't emulate absolutely all of the waitpid + * functionality, in that it doesn't support pid's of 0 + * or < -1. + * + * Results: + * -1 is returned if there is an error in the wait kernel call. + * Otherwise the pid of an exited or suspended process is + * returned and *statusPtr is set to the status value of the + * process. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +#ifdef waitpid +# undef waitpid +#endif + +pid_t +waitpid(pid, statusPtr, options) + pid_t pid; /* The pid to wait on. Must be -1 or + * greater than zero. */ + int *statusPtr; /* Where to store wait status for the + * process. */ + int options; /* OR'ed combination of WNOHANG and + * WUNTRACED. */ +{ + register WaitInfo *waitPtr, *prevPtr; + pid_t result; + WAIT_STATUS_TYPE status; + + if ((pid < -1) || (pid == 0)) { + errno = EINVAL; + return -1; + } + + /* + * See if there's a suitable process that has already stopped or + * exited. If so, remove it from the list of exited processes and + * return its information. + */ + + for (waitPtr = deadList, prevPtr = NULL; waitPtr != NULL; + prevPtr = waitPtr, waitPtr = waitPtr->nextPtr) { + if ((pid != waitPtr->pid) && (pid != -1)) { + continue; + } + if (!(options & WUNTRACED) && (WIFSTOPPED(waitPtr->status))) { + continue; + } + result = waitPtr->pid; + *statusPtr = *((int *) &waitPtr->status); + if (prevPtr == NULL) { + deadList = waitPtr->nextPtr; + } else { + prevPtr->nextPtr = waitPtr->nextPtr; + } + ckfree((char *) waitPtr); + return result; + } + + /* + * Wait for any process to stop or exit. If it's an acceptable one + * then return it to the caller; otherwise store information about it + * in the list of exited processes and try again. On systems that + * have only wait but not wait3, there are several situations we can't + * handle, but we do the best we can (e.g. can still handle some + * combinations of options by invoking wait instead of wait3). + */ + + while (1) { +#if NO_WAIT3 + if (options & WNOHANG) { + return 0; + } + if (options != 0) { + errno = EINVAL; + return -1; + } + result = wait(&status); +#else + result = wait3(&status, options, 0); +#endif + if ((result == -1) && (errno == EINTR)) { + continue; + } + if (result <= 0) { + return result; + } + + if ((pid != result) && (pid != -1)) { + goto saveInfo; + } + if (!(options & WUNTRACED) && (WIFSTOPPED(status))) { + goto saveInfo; + } + *statusPtr = *((int *) &status); + return result; + + /* + * Can't return this info to caller. Save it in the list of + * stopped or exited processes. Tricky point: first check for + * an existing entry for the process and overwrite it if it + * exists (e.g. a previously stopped process might now be dead). + */ + + saveInfo: + for (waitPtr = deadList; waitPtr != NULL; waitPtr = waitPtr->nextPtr) { + if (waitPtr->pid == result) { + waitPtr->status = status; + goto waitAgain; + } + } + waitPtr = (WaitInfo *) ckalloc(sizeof(WaitInfo)); + waitPtr->pid = result; + waitPtr->status = status; + waitPtr->nextPtr = deadList; + deadList = waitPtr; + + waitAgain: continue; + } +} diff --git a/mk4/modtcl/tcl8.3.4/doc/Access.3 b/mk4/modtcl/tcl8.3.4/doc/Access.3 new file mode 100644 index 0000000..b326959 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/Access.3 @@ -0,0 +1,71 @@ +'\" +'\" Copyright (c) 1998-1999 Scriptics Corportation +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: Access.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_Access 3 8.1 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_Access, Tcl_Stat \- check file permissions and other attributes +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +int +\fBTcl_Access\fR(\fIpath\fR, \fImode\fR) +.sp +int +\fBTcl_Stat\fR(\fIpath\fR, \fIstatPtr\fR) +.SH ARGUMENTS +.AS stat *statPtr in +.AP char *path in +Native name of the file to check the attributes of. +.AP int mode in +Mask consisting of one or more of R_OK, W_OK, X_OK and F_OK. R_OK, +W_OK and X_OK request checking whether the file exists and has read, +write and execute permissions, respectively. F_OK just requests +checking for the existence of the file. +.AP stat *statPtr out +The structure that contains the result. +.BE + +.SH DESCRIPTION +.PP +There are two reasons for calling \fBTcl_Access\fR and \fBTcl_Stat\fR +rather than calling system level functions \fBaccess\fR and \fBstat\fR +directly. First, the Windows implementation of both functions fixes +some bugs in the system level calls. Second, both \fBTcl_Access\fR +and \fBTcl_Stat\fR (as well as \fBTcl_OpenFileChannelProc\fR) hook +into a linked list of functions. This allows the possibity to reroute +file access to alternative media or access methods. +.PP +\fBTcl_Access\fR checks whether the process would be allowed to read, +write or test for existence of the file (or other file system object) +whose name is pathname. If pathname is a symbolic link on Unix, +then permissions of the file referred by this symbolic link are +tested. +.PP +On success (all requested permissions granted), zero is returned. On +error (at least one bit in mode asked for a permission that is denied, +or some other error occurred), -1 is returned. +.PP +\fBTcl_Stat\fR fills the stat structure \fIstatPtr\fR with information +about the specified file. You do not need any access rights to the +file to get this information but you need search rights to all +directories named in the path leading to the file. The stat structure +includes info regarding device, inode (always 0 on Windows), +priviledge mode, nlink (always 1 on Windows), user id (always 0 on +Windows), group id (always 0 on Windows), rdev (same as device on +Windows), size, last access time, last modification time, and creation +time. +.PP +If \fIpath\fR exists, \fBTcl_Stat\fR returns 0 and the stat structure +is filled with data. Otherwise, -1 is returned, and no stat info is +given. + +.SH KEYWORDS +stat access diff --git a/mk4/modtcl/tcl8.3.4/doc/AddErrInfo.3 b/mk4/modtcl/tcl8.3.4/doc/AddErrInfo.3 new file mode 100644 index 0000000..e4c30c7 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/AddErrInfo.3 @@ -0,0 +1,191 @@ +'\" +'\" Copyright (c) 1989-1993 The Regents of the University of California. +'\" Copyright (c) 1994-1997 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: AddErrInfo.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_AddErrorInfo 3 8.0 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_AddObjErrorInfo, Tcl_AddErrorInfo, Tcl_SetObjErrorCode, Tcl_SetErrorCode, Tcl_SetErrorCodeVA, Tcl_PosixError, Tcl_LogCommandInfo \- record information about errors +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +\fBTcl_AddObjErrorInfo\fR(\fIinterp, message, length\fR) +.sp +\fBTcl_AddErrorInfo\fR(\fIinterp, message\fR) +.sp +\fBTcl_SetObjErrorCode\fR(\fIinterp, errorObjPtr\fR) +.sp +\fBTcl_SetErrorCode\fR(\fIinterp, element, element, ... \fB(char *) NULL\fR) +.sp +\fBTcl_SetErrorCodeVA\fR(\fIinterp, argList\fR) +.sp +char * +\fBTcl_PosixError\fR(\fIinterp\fR) +.sp +void +\fBTcl_LogCommandInfo\fR(\fIinterp, script, command, commandLength\fR) +.SH ARGUMENTS +.AS Tcl_Interp *message +.AP Tcl_Interp *interp in +Interpreter in which to record information. +.AP char *message in +For \fBTcl_AddObjErrorInfo\fR, +this points to the first byte of an array of bytes +containing a string to record in the \fBerrorInfo\fR variable. +This byte array may contain embedded null bytes +unless \fIlength\fR is negative. +For \fBTcl_AddErrorInfo\fR, +this is a conventional C string to record in the \fBerrorInfo\fR variable. +.AP int length in +The number of bytes to copy from \fImessage\fR when +setting the \fBerrorInfo\fR variable. +If negative, all bytes up to the first null byte are used. +.AP Tcl_Obj *errorObjPtr in +This variable \fBerrorCode\fR will be set to this value. +.AP char *element in +String to record as one element of \fBerrorCode\fR variable. +Last \fIelement\fR argument must be NULL. +.AP va_list argList in +An argument list which must have been initialised using +\fBTCL_VARARGS_START\fR, and cleared using \fBva_end\fR. +.AP char *script in +Pointer to first character in script containing command (must be <= command) +.AP char *command in +Pointer to first character in command that generated the error +.AP int commandLength in +Number of bytes in command; -1 means use all bytes up to first NULL byte +.BE + +.SH DESCRIPTION +.PP +These procedures are used to manipulate two Tcl global variables +that hold information about errors. +The variable \fBerrorInfo\fR holds a stack trace of the +operations that were in progress when an error occurred, +and is intended to be human-readable. +The variable \fBerrorCode\fR holds a list of items that +are intended to be machine-readable. +The first item in \fBerrorCode\fR identifies the class of +error that occurred +(e.g. POSIX means an error occurred in a POSIX system call) +and additional elements in \fBerrorCode\fR hold additional pieces +of information that depend on the class. +See the Tcl overview manual entry for details on the various +formats for \fBerrorCode\fR. +.PP +The \fBerrorInfo\fR variable is gradually built up as an +error unwinds through the nested operations. +Each time an error code is returned to \fBTcl_EvalObjEx\fR +(or \fBTcl_Eval\fR, which calls \fBTcl_EvalObjEx\fR) +it calls the procedure \fBTcl_AddObjErrorInfo\fR to add +additional text to \fBerrorInfo\fR describing the +command that was being executed when the error occurred. +By the time the error has been passed all the way back +to the application, it will contain a complete trace +of the activity in progress when the error occurred. +.PP +It is sometimes useful to add additional information to +\fBerrorInfo\fR beyond what can be supplied automatically +by \fBTcl_EvalObjEx\fR. +\fBTcl_AddObjErrorInfo\fR may be used for this purpose: +its \fImessage\fR and \fIlength\fR arguments describe an additional +string to be appended to \fBerrorInfo\fR. +For example, the \fBsource\fR command calls \fBTcl_AddObjErrorInfo\fR +to record the name of the file being processed and the +line number on which the error occurred; +for Tcl procedures, the procedure name and line number +within the procedure are recorded, and so on. +The best time to call \fBTcl_AddObjErrorInfo\fR is just after +\fBTcl_EvalObjEx\fR has returned \fBTCL_ERROR\fR. +In calling \fBTcl_AddObjErrorInfo\fR, you may find it useful to +use the \fBerrorLine\fR field of the interpreter (see the +\fBTcl_Interp\fR manual entry for details). +.PP +\fBTcl_AddErrorInfo\fR resembles \fBTcl_AddObjErrorInfo\fR +but differs in initializing \fBerrorInfo\fR from the string +value of the interpreter's result +if the error is just starting to be logged. +It does not use the result as a Tcl object +so any embedded null characters in the result +will cause information to be lost. +It also takes a conventional C string in \fImessage\fR +instead of \fBTcl_AddObjErrorInfo\fR's counted string. +.PP +The procedure \fBTcl_SetObjErrorCode\fR is used to set the +\fBerrorCode\fR variable. \fIerrorObjPtr\fR contains a list object +built up by the caller. \fBerrorCode\fR is set to this +value. \fBTcl_SetObjErrorCode\fR is typically invoked just +before returning an error in an object command. If an error is +returned without calling \fBTcl_SetObjErrorCode\fR or +\fBTcl_SetErrorCode\fR the Tcl interpreter automatically sets +\fBerrorCode\fR to \fBNONE\fR. +.PP +The procedure \fBTcl_SetErrorCode\fR is also used to set the +\fBerrorCode\fR variable. However, it takes one or more strings to +record instead of an object. Otherwise, it is similar to +\fBTcl_SetObjErrorCode\fR in behavior. +.PP +\fBTcl_SetErrorCodeVA\fR is the same as \fBTcl_SetErrorCode\fR except that +instead of taking a variable number of arguments it takes an argument list. +.PP +\fBTcl_PosixError\fR +sets the \fBerrorCode\fR variable after an error in a POSIX kernel call. +It reads the value of the \fBerrno\fR C variable and calls +\fBTcl_SetErrorCode\fR to set \fBerrorCode\fR in the \fBPOSIX\fR format. +The caller must previously have called \fBTcl_SetErrno\fR to set +\fBerrno\fR; this is necessary on some platforms (e.g. Windows) where Tcl +is linked into an application as a shared library, or when the error +occurs in a dynamically loaded extension. See the manual entry for +\fBTcl_SetErrno\fR for more information. +.PP +\fBTcl_PosixError\fR returns a human-readable diagnostic message +for the error +(this is the same value that will appear as the third element +in \fBerrorCode\fR). +It may be convenient to include this string as part of the +error message returned to the application in +the interpreter's result. +.PP +\fBTcl_LogCommandInfo\fR is invoked after an error occurs in an +interpreter. It adds information about the command that was being +executed when the error occured to the \fBerrorInfo\fR variable, and +the line number stored internally in the interpreter is set. On the +first call to \fBTcl_LogCommandInfo\fR or \fBTcl_AddObjErrorInfo\fR +since an error occurred, the old information in \fBerrorInfo\fR is +deleted. +.PP +It is important to call the procedures described here rather than +setting \fBerrorInfo\fR or \fBerrorCode\fR directly with +\fBTcl_ObjSetVar2\fR. +The reason for this is that the Tcl interpreter keeps information +about whether these procedures have been called. +For example, the first time \fBTcl_AddObjErrorInfo\fR is called +for an error, it clears the existing value of \fBerrorInfo\fR +and adds the error message in the interpreter's result to the variable +before appending \fImessage\fR; +in subsequent calls, it just appends the new \fImessage\fR. +When \fBTcl_SetErrorCode\fR is called, it sets a flag indicating +that \fBerrorCode\fR has been set; +this allows the Tcl interpreter to set \fBerrorCode\fR to \fBNONE\fR +if it receives an error return +when \fBTcl_SetErrorCode\fR hasn't been called. +.PP +If the procedure \fBTcl_ResetResult\fR is called, +it clears all of the state associated with +\fBerrorInfo\fR and \fBerrorCode\fR +(but it doesn't actually modify the variables). +If an error had occurred, this will clear the error state to +make it appear as if no error had occurred after all. + +.SH "SEE ALSO" +Tcl_DecrRefCount, Tcl_IncrRefCount, Tcl_Interp, Tcl_ResetResult, Tcl_SetErrno + +.SH KEYWORDS +error, object, object result, stack, trace, variable diff --git a/mk4/modtcl/tcl8.3.4/doc/Alloc.3 b/mk4/modtcl/tcl8.3.4/doc/Alloc.3 new file mode 100644 index 0000000..df36366 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/Alloc.3 @@ -0,0 +1,52 @@ +'\" +'\" Copyright (c) 1995-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: Alloc.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_Alloc 3 7.5 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_Alloc, Tcl_Free, Tcl_Realloc \- allocate or free heap memory +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +char * +\fBTcl_Alloc\fR(\fIsize\fR) +.sp +\fBTcl_Free\fR(\fIptr\fR) +.sp +char * +\fBTcl_Realloc\fR(\fIptr, size\fR) +.SH ARGUMENTS +.AS char *size +.AP int size in +Size in bytes of the memory block to allocate. +.AP char *ptr in +Pointer to memory block to free or realloc. +.BE + +.SH DESCRIPTION +.PP +These procedures provide a platform and compiler independent interface +for memory allocation. Programs that need to transfer ownership of +memory blocks between Tcl and other modules should use these routines +rather than the native \fBmalloc()\fR and \fBfree()\fR routines +provided by the C run-time library. +.PP +\fBTcl_Alloc\fR returns a pointer to a block of at least \fIsize\fR +bytes suitably aligned for any use. +.PP +\fBTcl_Free\fR makes the space referred to by \fIptr\fR available for +further allocation. +.PP +\fBTcl_Realloc\fR changes the size of the block pointed to by +\fIptr\fR to \fIsize\fR bytes and returns a pointer to the new block. +The contents will be unchanged up to the lesser of the new and old +sizes. The returned location may be different from \fIptr\fR. +.SH KEYWORDS +alloc, allocation, free, malloc, memory, realloc diff --git a/mk4/modtcl/tcl8.3.4/doc/AllowExc.3 b/mk4/modtcl/tcl8.3.4/doc/AllowExc.3 new file mode 100644 index 0000000..a2b55d7 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/AllowExc.3 @@ -0,0 +1,42 @@ +'\" +'\" Copyright (c) 1989-1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: AllowExc.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_AllowExceptions 3 7.4 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_AllowExceptions \- allow all exceptions in next script evaluation +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +\fBTcl_AllowExceptions\fR(\fIinterp\fR) +.SH ARGUMENTS +.AS Tcl_Interp *doublePtr +.AP Tcl_Interp *interp in +Interpreter in which script will be evaluated. +.BE + +.SH DESCRIPTION +.PP +If a script is evaluated at top-level (i.e. no other scripts are +pending evaluation when the script is invoked), and if the script +terminates with a completion code other than TCL_OK, TCL_CONTINUE +or TCL_RETURN, then Tcl normally converts this into a TCL_ERROR +return with an appropriate message. +.PP +However, if \fBTcl_AllowExceptions\fR is invoked immediately before +calling a procedure such as \fBTcl_Eval\fR, then arbitrary completion +codes are permitted from the script, and they are returned without +modification. +This is useful in cases where the caller can deal with exceptions +such as TCL_BREAK or TCL_CONTINUE in a meaningful way. + +.SH KEYWORDS +continue, break, exception, interpreter diff --git a/mk4/modtcl/tcl8.3.4/doc/AppInit.3 b/mk4/modtcl/tcl8.3.4/doc/AppInit.3 new file mode 100644 index 0000000..a3c3a5a --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/AppInit.3 @@ -0,0 +1,73 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: AppInit.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_AppInit 3 7.0 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_AppInit \- perform application-specific initialization +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +int +\fBTcl_AppInit\fR(\fIinterp\fR) +.SH ARGUMENTS +.AS Tcl_Interp *interp +.AP Tcl_Interp *interp in +Interpreter for the application. +.BE + +.SH DESCRIPTION +.PP +\fBTcl_AppInit\fR is a ``hook'' procedure that is invoked by +the main programs for Tcl applications such as \fBtclsh\fR and \fBwish\fR. +Its purpose is to allow new Tcl applications to be created without +modifying the main programs provided as part of Tcl and Tk. +To create a new application you write a new version of +\fBTcl_AppInit\fR to replace the default version provided by Tcl, +then link your new \fBTcl_AppInit\fR with the Tcl library. +.PP +\fBTcl_AppInit\fR is invoked after by \fBTcl_Main\fR and \fBTk_Main\fR +after their own initialization and before entering the main loop +to process commands. +Here are some examples of things that \fBTcl_AppInit\fR might do: +.IP [1] +Call initialization procedures for various packages used by +the application. +Each initialization procedure adds new commands to \fIinterp\fR +for its package and performs other package-specific initialization. +.IP [2] +Process command-line arguments, which can be accessed from the +Tcl variables \fBargv\fR and \fBargv0\fR in \fIinterp\fR. +.IP [3] +Invoke a startup script to initialize the application. +.LP +\fBTcl_AppInit\fR returns TCL_OK or TCL_ERROR. +If it returns TCL_ERROR then it must leave an error message in +for the interpreter's result; otherwise the result is ignored. +.PP +In addition to \fBTcl_AppInit\fR, your application should also contain +a procedure \fBmain\fR that calls \fBTcl_Main\fR as follows: +.CS +Tcl_Main(argc, argv, Tcl_AppInit); +.CE +The third argument to \fBTcl_Main\fR gives the address of the +application-specific initialization procedure to invoke. +This means that you don't have to use the name \fBTcl_AppInit\fR +for the procedure, but in practice the name is nearly always +\fBTcl_AppInit\fR (in versions before Tcl 7.4 the name \fBTcl_AppInit\fR +was implicit; there was no way to specify the procedure explicitly). +The best way to get started is to make a copy of the file +\fBtclAppInit.c\fR from the Tcl library or source directory. +It already contains a \fBmain\fR procedure and a template for +\fBTcl_AppInit\fR that you can modify for your application. + +.SH KEYWORDS +application, argument, command, initialization, interpreter diff --git a/mk4/modtcl/tcl8.3.4/doc/AssocData.3 b/mk4/modtcl/tcl8.3.4/doc/AssocData.3 new file mode 100644 index 0000000..a98c56e --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/AssocData.3 @@ -0,0 +1,89 @@ +'\" +'\" Copyright (c) 1995-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" +'\" RCS: @(#) $Id: AssocData.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +.so man.macros +.TH Tcl_SetAssocData 3 7.5 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_GetAssocData, Tcl_SetAssocData, Tcl_DeleteAssocData \- manage +associations of string keys and user specified data with Tcl +interpreters. +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +ClientData +\fBTcl_GetAssocData\fR(\fIinterp, key, delProcPtr\fR) +.sp +\fBTcl_SetAssocData\fR(\fIinterp, key, delProc, clientData\fR) +.sp +\fBTcl_DeleteAssocData\fR(\fIinterp, key\fR) +.SH ARGUMENTS +.AS Tcl_InterpDeleteProc *delProcPtr +.AP Tcl_Interp *interp in +Interpreter in which to execute the specified command. +.AP char *key in +Key for association with which to store data or from which to delete or +retrieve data. Typically the module prefix for a package. +.AP Tcl_InterpDeleteProc *delProc in +Procedure to call when \fIinterp\fR is deleted. +.AP Tcl_InterpDeleteProc **delProcPtr in +Pointer to location in which to store address of current deletion procedure +for association. Ignored if NULL. +.AP ClientData clientData in +Arbitrary one-word value associated with the given key in this +interpreter. This data is owned by the caller. +.BE + +.SH DESCRIPTION +.PP +These procedures allow extensions to associate their own data with +a Tcl interpreter. +An association consists of a string key, typically the name of +the extension, and a one-word value, which is typically a pointer +to a data structure holding data specific to the extension. +Tcl makes no interpretation of either the key or the value for +an association. +.PP +Storage management is facilitated by storing with each association a +procedure to call when the interpreter is deleted. This +procedure can dispose of the storage occupied by the client's data in any +way it sees fit. +.PP +\fBTcl_SetAssocData\fR creates an association between a string +key and a user specified datum in the given interpreter. +If there is already an association with the given \fIkey\fR, +\fBTcl_SetAssocData\fR overwrites it with the new information. +It is up to callers to organize their use of names to avoid conflicts, +for example, by using package names as the keys. +If the \fIdeleteProc\fR argument is non-NULL it specifies the address of a +procedure to invoke if the interpreter is deleted before the association +is deleted. \fIDeleteProc\fR should have arguments and result that match +the type \fBTcl_InterpDeleteProc\fR: +.CS +typedef void Tcl_InterpDeleteProc( + ClientData \fIclientData\fR, + Tcl_Interp *\fIinterp\fR); +.CE +When \fIdeleteProc\fR is invoked the \fIclientData\fR and \fIinterp\fR +arguments will be the same as the corresponding arguments passed to +\fBTcl_SetAssocData\fR. +The deletion procedure will \fInot\fR be invoked if the association +is deleted before the interpreter is deleted. +.PP +\fBTcl_GetAssocData\fR returns the datum stored in the association with the +specified key in the given interpreter, and if the \fIdelProcPtr\fR field +is non-\fBNULL\fR, the address indicated by it gets the address of the +delete procedure stored with this association. If no association with the +specified key exists in the given interpreter \fBTcl_GetAssocData\fR +returns \fBNULL\fR. +.PP +\fBTcl_DeleteAssocData\fR deletes an association with a specified key in +the given interpreter. Then it calls the deletion procedure. +.SH KEYWORDS +association, data, deletion procedure, interpreter, key diff --git a/mk4/modtcl/tcl8.3.4/doc/Async.3 b/mk4/modtcl/tcl8.3.4/doc/Async.3 new file mode 100644 index 0000000..ee835ec --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/Async.3 @@ -0,0 +1,163 @@ +'\" +'\" Copyright (c) 1989-1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: Async.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_AsyncCreate 3 7.0 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_AsyncCreate, Tcl_AsyncMark, Tcl_AsyncInvoke, Tcl_AsyncDelete, Tcl_AsyncReady \- handle asynchronous events +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +Tcl_AsyncHandler +\fBTcl_AsyncCreate\fR(\fIproc, clientData\fR) +.sp +\fBTcl_AsyncMark\fR(\fIasync\fR) +.sp +int +\fBTcl_AsyncInvoke\fR(\fIinterp, code\fR) +.sp +\fBTcl_AsyncDelete\fR(\fIasync\fR) +.sp +int +\fBTcl_AsyncReady\fR() +.SH ARGUMENTS +.AS Tcl_AsyncHandler clientData +.AP Tcl_AsyncProc *proc in +Procedure to invoke to handle an asynchronous event. +.AP ClientData clientData in +One-word value to pass to \fIproc\fR. +.AP Tcl_AsyncHandler async in +Token for asynchronous event handler. +.AP Tcl_Interp *interp in +Tcl interpreter in which command was being evaluated when handler was +invoked, or NULL if handler was invoked when there was no interpreter +active. +.AP int code in +Completion code from command that just completed in \fIinterp\fR, +or 0 if \fIinterp\fR is NULL. +.BE + +.SH DESCRIPTION +.PP +These procedures provide a safe mechanism for dealing with +asynchronous events such as signals. +If an event such as a signal occurs while a Tcl script is being +evaluated then it isn't safe to take any substantive action to +process the event. +For example, it isn't safe to evaluate a Tcl script since the +interpreter may already be in the middle of evaluating a script; +it may not even be safe to allocate memory, since a memory +allocation could have been in progress when the event occurred. +The only safe approach is to set a flag indicating that the event +occurred, then handle the event later when the world has returned +to a clean state, such as after the current Tcl command completes. +.PP +\fBTcl_AsyncCreate\fR, \fBTcl_AsyncDelete\fR, and \fBTcl_AsyncReady\fR +are thread sensitive. They access and/or set a thread-specific data +structure in the event of an --enable-thread built core. The token +created by Tcl_AsyncCreate contains the needed thread information it +was called from so that calling Tcl_AsyncMark(token) will only yield +the origin thread into the AsyncProc. +.PP +\fBTcl_AsyncCreate\fR creates an asynchronous handler and returns +a token for it. +The asynchronous handler must be created before +any occurrences of the asynchronous event that it is intended +to handle (it is not safe to create a handler at the time of +an event). +When an asynchronous event occurs the code that detects the event +(such as a signal handler) should call \fBTcl_AsyncMark\fR with the +token for the handler. +\fBTcl_AsyncMark\fR will mark the handler as ready to execute, but it +will not invoke the handler immediately. +Tcl will call the \fIproc\fR associated with the handler later, when +the world is in a safe state, and \fIproc\fR can then carry out +the actions associated with the asynchronous event. +\fIProc\fR should have arguments and result that match the +type \fBTcl_AsyncProc\fR: +.CS +typedef int Tcl_AsyncProc( + ClientData \fIclientData\fR, + Tcl_Interp *\fIinterp\fR, + int \fIcode\fR); +.CE +The \fIclientData\fR will be the same as the \fIclientData\fR +argument passed to \fBTcl_AsyncCreate\fR when the handler was +created. +If \fIproc\fR is invoked just after a command has completed +execution in an interpreter, then \fIinterp\fR will identify +the interpreter in which the command was evaluated and +\fIcode\fR will be the completion code returned by that +command. +The command's result will be present in the interpreter's result. +When \fIproc\fR returns, whatever it leaves in the interpreter's result +will be returned as the result of the command and the integer +value returned by \fIproc\fR will be used as the new completion +code for the command. +.PP +It is also possible for \fIproc\fR to be invoked when no interpreter +is active. +This can happen, for example, if an asynchronous event occurs while +the application is waiting for interactive input or an X event. +In this case \fIinterp\fR will be NULL and \fIcode\fR will be +0, and the return value from \fIproc\fR will be ignored. +.PP +The procedure \fBTcl_AsyncInvoke\fR is called to invoke all of the +handlers that are ready. +The procedure \fBTcl_AsyncReady\fR will return non-zero whenever any +asynchronous handlers are ready; it can be checked to avoid calls +to \fBTcl_AsyncInvoke\fR when there are no ready handlers. +Tcl calls \fBTcl_AsyncReady\fR after each command is evaluated +and calls \fBTcl_AsyncInvoke\fR if needed. +Applications may also call \fBTcl_AsyncInvoke\fR at interesting +times for that application. +For example, Tcl's event handler calls \fBTcl_AsyncReady\fR +after each event and calls \fBTcl_AsyncInvoke\fR if needed. +The \fIinterp\fR and \fIcode\fR arguments to \fBTcl_AsyncInvoke\fR +have the same meaning as for \fIproc\fR: they identify the active +interpreter, if any, and the completion code from the command +that just completed. +.PP +\fBTcl_AsyncDelete\fR removes an asynchronous handler so that +its \fIproc\fR will never be invoked again. +A handler can be deleted even when ready, and it will still +not be invoked. +.PP +If multiple handlers become active at the same time, the +handlers are invoked in the order they were created (oldest +handler first). +The \fIcode\fR and the interpreter's result for later handlers +reflect the values returned by earlier handlers, so that +the most recently created handler has last say about +the interpreter's result and completion code. +If new handlers become ready while handlers are executing, +\fBTcl_AsyncInvoke\fR will invoke them all; at each point it +invokes the highest-priority (oldest) ready handler, repeating +this over and over until there are no longer any ready handlers. + +.SH WARNING +.PP +It is almost always a bad idea for an asynchronous event +handler to modify the interpreter's result or return a code different +from its \fIcode\fR argument. +This sort of behavior can disrupt the execution of scripts in +subtle ways and result in bugs that are extremely difficult +to track down. +If an asynchronous event handler needs to evaluate Tcl scripts +then it should first save the interpreter's result plus the values +of the variables \fBerrorInfo\fR and \fBerrorCode\fR (this can +be done, for example, by storing them in dynamic strings). +When the asynchronous handler is finished it should restore +the interpreter's result, \fBerrorInfo\fR, and \fBerrorCode\fR, +and return the \fIcode\fR argument. + +.SH KEYWORDS +asynchronous event, handler, signal diff --git a/mk4/modtcl/tcl8.3.4/doc/BackgdErr.3 b/mk4/modtcl/tcl8.3.4/doc/BackgdErr.3 new file mode 100644 index 0000000..d80d6ee --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/BackgdErr.3 @@ -0,0 +1,58 @@ +'\" +'\" Copyright (c) 1992-1994 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: BackgdErr.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_BackgroundError 3 7.5 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_BackgroundError \- report Tcl error that occurred in background processing +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +\fBTcl_BackgroundError\fR(\fIinterp\fR) +.SH ARGUMENTS +.AS Tcl_Interp *interp +.AP Tcl_Interp *interp in +Interpreter in which the error occurred. +.BE + +.SH DESCRIPTION +.PP +This procedure is typically invoked when a Tcl error occurs during +``background processing'' such as executing an event handler. +When such an error occurs, the error condition is reported to Tcl +or to a widget or some other C code, and there is not usually any +obvious way for that code to report the error to the user. +In these cases the code calls \fBTcl_BackgroundError\fR with an +\fIinterp\fR argument identifying the interpreter in which the +error occurred. At the time \fBTcl_BackgroundError\fR is invoked, +the interpreter's result is expected to contain an error message. +\fBTcl_BackgroundError\fR will invoke the \fBbgerror\fR +Tcl command to report the error in an application-specific fashion. +If no \fBbgerror\fR command exists, or if it returns with an error condition, +then \fBTcl_BackgroundError\fR reports the error itself by printing +a message on the standard error file. +.PP +\fBTcl_BackgroundError\fR does not invoke \fBbgerror\fR immediately +because this could potentially interfere with scripts that are in process +at the time the error occurred. +Instead, it invokes \fBbgerror\fR later as an idle callback. +\fBTcl_BackgroundError\fR saves the values of the \fBerrorInfo\fR and +\fBerrorCode\fR variables and restores these values just before +invoking \fBbgerror\fR. +.PP +It is possible for many background errors to accumulate before +\fBbgerror\fR is invoked. When this happens, each of the errors +is processed in order. However, if \fBbgerror\fR returns a +break exception, then all remaining error reports for the +interpreter are skipped. + +.SH KEYWORDS +background, bgerror, error diff --git a/mk4/modtcl/tcl8.3.4/doc/Backslash.3 b/mk4/modtcl/tcl8.3.4/doc/Backslash.3 new file mode 100644 index 0000000..48128ab --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/Backslash.3 @@ -0,0 +1,53 @@ +'\" +'\" Copyright (c) 1989-1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: Backslash.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_Backslash 3 "8.1" Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_Backslash \- parse a backslash sequence +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +char +\fBTcl_Backslash\fR(\fIsrc, countPtr\fR) +.SH ARGUMENTS +.AS char *countPtr +.AP char *src in +Pointer to a string starting with a backslash. +.AP int *countPtr out +If \fIcountPtr\fR isn't NULL, \fI*countPtr\fR gets filled +in with number of characters in the backslash sequence, including +the backslash character. +.BE + +.SH DESCRIPTION +.PP +.VS 8.1 +The use of \fBTcl_Backslash\fR is deprecated in favor of +\fBTcl_UtfBackslash\fR. +.PP +This is a utility procedure provided for backwards compatibilty with +non-internationalized Tcl extensions. It parses a backslash sequence and +returns the low byte of the Unicode character corresponding to the sequence. +.VE +\fBTcl_Backslash\fR modifies \fI*countPtr\fR to contain the number of +characters in the backslash sequence. +.PP +See the Tcl manual entry for information on the valid backslash sequences. +All of the sequences described in the Tcl manual entry are supported by +\fBTcl_Backslash\fR. +.VS 8.1 br +.SH "SEE ALSO" +Tcl(n), Tcl_UtfBackslash(3) +.VE + +.SH KEYWORDS +backslash, parse diff --git a/mk4/modtcl/tcl8.3.4/doc/BoolObj.3 b/mk4/modtcl/tcl8.3.4/doc/BoolObj.3 new file mode 100644 index 0000000..b8524aa --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/BoolObj.3 @@ -0,0 +1,83 @@ +'\" +'\" Copyright (c) 1996-1997 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: BoolObj.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_BooleanObj 3 8.0 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_NewBooleanObj, Tcl_SetBooleanObj, Tcl_GetBooleanFromObj \- manipulate Tcl objects as boolean values +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +Tcl_Obj * +\fBTcl_NewBooleanObj\fR(\fIboolValue\fR) +.sp +\fBTcl_SetBooleanObj\fR(\fIobjPtr, boolValue\fR) +.sp +int +\fBTcl_GetBooleanFromObj\fR(\fIinterp, objPtr, boolPtr\fR) +.SH ARGUMENTS +.AS Tcl_Interp *interp +.AP int boolValue in +Integer value used to initialize or set a boolean object. +If the integer is nonzero, the boolean object is set to 1; +otherwise the boolean object is set to 0. +.AP Tcl_Obj *objPtr in/out +For \fBTcl_SetBooleanObj\fR, this points to the object to be converted +to boolean type. +For \fBTcl_GetBooleanFromObj\fR, this refers to the object +from which to get a boolean value; +if \fIobjPtr\fR does not already point to a boolean object, +an attempt will be made to convert it to one. +.AP Tcl_Interp *interp in/out +If an error occurs during conversion, +an error message is left in the interpreter's result object +unless \fIinterp\fR is NULL. +.AP int *boolPtr out +Points to place where \fBTcl_GetBooleanFromObj\fR +stores the boolean value (0 or 1) obtained from \fIobjPtr\fR. +.BE + +.SH DESCRIPTION +.PP +These procedures are used to create, modify, and read +boolean Tcl objects from C code. +\fBTcl_NewBooleanObj\fR and \fBTcl_SetBooleanObj\fR +will create a new object of boolean type +or modify an existing object to have boolean type. +Both of these procedures set the object to have the +boolean value (0 or 1) specified by \fIboolValue\fR; +if \fIboolValue\fR is nonzero, the object is set to 1, +otherwise to 0. +\fBTcl_NewBooleanObj\fR returns a pointer to a newly created object +with reference count zero. +Both procedures set the object's type to be boolean +and assign the boolean value to the object's internal representation +\fIlongValue\fR member. +\fBTcl_SetBooleanObj\fR invalidates any old string representation +and, if the object is not already a boolean object, +frees any old internal representation. +.PP +\fBTcl_GetBooleanFromObj\fR attempts to return a boolean value +from the Tcl object \fIobjPtr\fR. +If the object is not already a boolean object, +it will attempt to convert it to one. +If an error occurs during conversion, it returns \fBTCL_ERROR\fR +and leaves an error message in the interpreter's result object +unless \fIinterp\fR is NULL. +Otherwise, \fBTcl_GetBooleanFromObj\fR returns \fBTCL_OK\fR +and stores the boolean value in the address given by \fIboolPtr\fR. +If the object is not already a boolean object, +the conversion will free any old internal representation. + +.SH "SEE ALSO" +Tcl_NewObj, Tcl_DecrRefCount, Tcl_IncrRefCount, Tcl_GetObjResult + +.SH KEYWORDS +boolean, boolean object, boolean type, internal representation, object, object type, string representation diff --git a/mk4/modtcl/tcl8.3.4/doc/ByteArrObj.3 b/mk4/modtcl/tcl8.3.4/doc/ByteArrObj.3 new file mode 100644 index 0000000..5a366ad --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/ByteArrObj.3 @@ -0,0 +1,91 @@ +'\" +'\" Copyright (c) 1997 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: ByteArrObj.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_ByteArrayObj 3 8.1 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_NewByteArrayObj, Tcl_SetByteArrayObj, Tcl_GetByteArrayFromObj, Tcl_SetByteArrayLength \- manipulate Tcl objects as a arrays of bytes +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +Tcl_Obj * +\fBTcl_NewByteArrayObj\fR(\fIbytes, length\fR) +.sp +void +\fBTcl_SetByteArrayObj\fR(\fIobjPtr, bytes, length\fR) +.sp +unsigned char * +\fBTcl_GetByteArrayFromObj\fR(\fIobjPtr, lengthPtr\fR) +.sp +unsigned char * +\fBTcl_SetByteArrayLength\fR(\fIobjPtr, length\fR) +.SH ARGUMENTS +.AS "unsigned char" *lengthPtr in/out +.AP "unsigned char" *bytes in +The array of bytes used to initialize or set a byte-array object. +.AP int length in +The length of the array of bytes. It must be >= 0. +.AP Tcl_Obj *objPtr in/out +For \fBTcl_SetByteArrayObj\fR, this points to the object to be converted to +byte-array type. For \fBTcl_GetByteArrayFromObj\fR and +\fBTcl_SetByteArrayLength\fR, this points to the object from which to get +the byte-array value; if \fIobjPtr\fR does not already point to a byte-array +object, it will be converted to one. +.AP int *lengthPtr out +If non-NULL, filled with the length of the array of bytes in the object. +.BE + +.SH DESCRIPTION +.PP +These procedures are used to create, modify, and read Tcl byte-array objects +from C code. Byte-array objects are typically used to hold the +results of binary IO operations or data structures created with the +\fBbinary\fR command. In Tcl, an array of bytes is not equivalent to a +string. Conceptually, a string is an array of Unicode characters, while a +byte-array is an array of 8-bit quantities with no implicit meaning. +Accesser functions are provided to get the string representation of a +byte-array or to convert an arbitrary object to a byte-array. Obtaining the +string representation of a byte-array object (by calling +\fBTcl_GetStringFromObj\fR) produces a properly formed UTF-8 sequence with a +one-to-one mapping between the bytes in the internal representation and the +UTF-8 characters in the string representation. +.PP +\fBTcl_NewByteArrayObj\fR and \fBTcl_SetByteArrayObj\fR will +create a new object of byte-array type or modify an existing object to have a +byte-array type. Both of these procedures set the object's type to be +byte-array and set the object's internal representation to a copy of the +array of bytes given by \fIbytes\fR. \fBTcl_NewByteArrayObj\fR returns a +pointer to a newly allocated object with a reference count of zero. +\fBTcl_SetByteArrayObj\fR invalidates any old string representation and, if +the object is not already a byte-array object, frees any old internal +representation. +.PP +\fBTcl_GetByteArrayFromObj\fR converts a Tcl object to byte-array type and +returns a pointer to the object's new internal representation as an array of +bytes. The length of this array is stored in \fIlengthPtr\fR if +\fIlengthPtr\fR is non-NULL. The storage for the array of bytes is owned by +the object and should not be freed. The contents of the array may be +modified by the caller only if the object is not shared and the caller +invalidates the string representation. +.PP +\fBTcl_SetByteArrayLength\fR converts the Tcl object to byte-array type +and changes the length of the object's internal representation as an +array of bytes. If \fIlength\fR is greater than the space currently +allocated for the array, the array is reallocated to the new length; the +newly allocated bytes at the end of the array have arbitrary values. If +\fIlength\fR is less than the space currently allocated for the array, +the length of array is reduced to the new length. The return value is a +pointer to the object's new array of bytes. + +.SH "SEE ALSO" +Tcl_GetStringFromObj, Tcl_NewObj, Tcl_IncrRefCount, Tcl_DecrRefCount + +.SH KEYWORDS +object, byte array, utf, unicode, internationalization diff --git a/mk4/modtcl/tcl8.3.4/doc/CVS/Entries b/mk4/modtcl/tcl8.3.4/doc/CVS/Entries new file mode 100644 index 0000000..5226806 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/CVS/Entries @@ -0,0 +1,184 @@ +/Access.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/AddErrInfo.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/Alloc.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/AllowExc.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/AppInit.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/AssocData.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/Async.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/BackgdErr.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/Backslash.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/BoolObj.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/ByteArrObj.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/CallDel.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/ChnlStack.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/CmdCmplt.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/Concat.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/CrtChannel.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/CrtChnlHdlr.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/CrtCloseHdlr.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/CrtCommand.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/CrtFileHdlr.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/CrtInterp.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/CrtMathFnc.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/CrtObjCmd.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/CrtSlave.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/CrtTimerHdlr.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/CrtTrace.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/DString.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/DetachPids.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/DoOneEvent.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/DoWhenIdle.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/DoubleObj.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/DumpActiveMemory.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/Encoding.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/Eval.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/Exit.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/ExprLong.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/ExprLongObj.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/FindExec.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/GetCwd.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/GetHostName.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/GetIndex.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/GetInt.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/GetOpnFl.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/GetStdChan.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/GetVersion.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/Hash.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/Init.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/InitStubs.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/IntObj.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/Interp.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/LinkVar.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/ListObj.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/Notifier.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/Object.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/ObjectType.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/OpenFileChnl.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/OpenTcp.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/ParseCmd.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/PkgRequire.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/Preserve.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/PrintDbl.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/RecEvalObj.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/RecordEval.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/RegExp.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/SaveResult.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/SetErrno.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/SetRecLmt.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/SetResult.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/SetVar.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/Sleep.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/SourceRCFile.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/SplitList.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/SplitPath.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/StaticPkg.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/StrMatch.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/StringObj.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/TCL_MEM_DEBUG.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/Tcl.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/Tcl_Main.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/Thread.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/ToUpper.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/TraceVar.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/Translate.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/UpVar.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/Utf.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/WrongNumArgs.3/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/after.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/append.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/array.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/bgerror.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/binary.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/break.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/case.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/catch.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/cd.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/clock.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/close.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/concat.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/continue.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/dde.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/encoding.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/eof.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/error.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/eval.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/exec.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/exit.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/expr.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/fblocked.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/fconfigure.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/fcopy.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/file.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/fileevent.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/filename.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/flush.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/for.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/foreach.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/format.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/gets.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/glob.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/global.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/history.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/http.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/if.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/incr.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/info.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/interp.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/join.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/lappend.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/library.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/license.terms/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/lindex.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/linsert.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/list.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/llength.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/load.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/lrange.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/lreplace.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/lsearch.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/lsort.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/man.macros/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/memory.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/msgcat.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/namespace.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/open.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/package.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/packagens.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/pid.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/pkgMkIndex.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/proc.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/puts.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/pwd.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/re_syntax.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/read.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/regexp.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/registry.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/regsub.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/rename.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/resource.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/return.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/safe.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/scan.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/seek.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/set.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/socket.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/source.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/split.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/string.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/subst.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/switch.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/tclsh.1/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/tcltest.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/tclvars.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/tell.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/time.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/trace.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/unknown.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/unset.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/update.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/uplevel.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/upvar.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/variable.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/vwait.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +/while.n/1.1.1.1/Wed Oct 29 20:29:11 2003//Tmk4_mod6_rc2 +D diff --git a/mk4/modtcl/tcl8.3.4/doc/CVS/Repository b/mk4/modtcl/tcl8.3.4/doc/CVS/Repository new file mode 100644 index 0000000..c4c67d7 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/CVS/Repository @@ -0,0 +1 @@ +/san01/cvs/ashpool/csrc/modtcl/tcl8.3.4/doc diff --git a/mk4/modtcl/tcl8.3.4/doc/CVS/Root b/mk4/modtcl/tcl8.3.4/doc/CVS/Root new file mode 100644 index 0000000..8f34465 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/CVS/Root @@ -0,0 +1 @@ +/san01/cvs/ashpool diff --git a/mk4/modtcl/tcl8.3.4/doc/CVS/Tag b/mk4/modtcl/tcl8.3.4/doc/CVS/Tag new file mode 100644 index 0000000..5a4cb45 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/CVS/Tag @@ -0,0 +1 @@ +Nmk4_mod6_rc2 diff --git a/mk4/modtcl/tcl8.3.4/doc/CallDel.3 b/mk4/modtcl/tcl8.3.4/doc/CallDel.3 new file mode 100644 index 0000000..ce93ef7 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/CallDel.3 @@ -0,0 +1,63 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: CallDel.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_CallWhenDeleted 3 7.0 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_CallWhenDeleted, Tcl_DontCallWhenDeleted \- Arrange for callback when interpreter is deleted +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +\fBTcl_CallWhenDeleted\fR(\fIinterp\fR, \fIproc\fR, \fIclientData\fR) +.sp +\fBTcl_DontCallWhenDeleted\fR(\fIinterp\fR, \fIproc\fR, \fIclientData\fR) +.SH ARGUMENTS +.AS Tcl_InterpDeleteProc clientData +.AP Tcl_Interp *interp in +Interpreter with which to associated callback. +.AP Tcl_InterpDeleteProc *proc in +Procedure to call when \fIinterp\fR is deleted. +.AP ClientData clientData in +Arbitrary one-word value to pass to \fIproc\fR. +.BE + +.SH DESCRIPTION +.PP +\fBTcl_CallWhenDeleted\fR arranges for \fIproc\fR to be called by +\fBTcl_DeleteInterp\fR if/when \fIinterp\fR is deleted at some future +time. \fIProc\fR will be invoked just before the interpreter +is deleted, but the interpreter will still be valid at the +time of the call. +\fIProc\fR should have arguments and result that match the +type \fBTcl_InterpDeleteProc\fR: +.CS +typedef void Tcl_InterpDeleteProc( + ClientData \fIclientData\fR, + Tcl_Interp *\fIinterp\fR); +.CE +The \fIclientData\fR and \fIinterp\fR parameters are +copies of the \fIclientData\fR and \fIinterp\fR arguments given +to \fBTcl_CallWhenDeleted\fR. +Typically, \fIclientData\fR points to an application-specific +data structure that \fIproc\fR uses to perform cleanup when an +interpreter is about to go away. +\fIProc\fR does not return a value. +.PP +\fBTcl_DontCallWhenDeleted\fR cancels a previous call to +\fBTcl_CallWhenDeleted\fR with the same arguments, so that +\fIproc\fR won't be called after all when \fIinterp\fR is +deleted. +If there is no deletion callback that matches \fIinterp\fR, +\fIproc\fR, and \fIclientData\fR then the call to +\fBTcl_DontCallWhenDeleted\fR has no effect. + +.SH KEYWORDS +callback, delete, interpreter diff --git a/mk4/modtcl/tcl8.3.4/doc/ChnlStack.3 b/mk4/modtcl/tcl8.3.4/doc/ChnlStack.3 new file mode 100644 index 0000000..5c82dd2 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/ChnlStack.3 @@ -0,0 +1,90 @@ +'\" +'\" Copyright (c) 1999-2000 Ajuba Solutions. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: ChnlStack.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +.so man.macros +.TH Tcl_StackChannel 3 8.3 Tcl "Tcl Library Procedures" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +Tcl_StackChannel, Tcl_UnstackChannel, Tcl_GetStackedChannel \- stack an I/O channel on top of another, and undo it +.SH SYNOPSIS +.nf +.nf +\fB#include \fR +.sp +Tcl_Channel +\fBTcl_StackChannel\fR(\fIinterp, typePtr, clientData, mask, channel\fR) +.sp +int +\fBTcl_UnstackChannel\fR(\fIinterp, channel\fR) +.sp +Tcl_Channel +\fBTcl_GetStackedChannel\fR(\fIchannel\fR) +.sp +.SH ARGUMENTS +.AS Tcl_ChannelType +.AP Tcl_Interp *interp in +Interpreter for error reporting - can be NULL. +.AP Tcl_ChannelType *typePtr in +The new channel I/O procedures to use for \fIchannel\fP. +.AP ClientData clientData in +Arbitrary one-word value to pass to channel I/O procedures. +.AP int mask in +Conditions under which \fIchannel\fR will be used: OR-ed combination of +\fBTCL_READABLE\fR, \fBTCL_WRITABLE\fR and \fBTCL_EXCEPTION\fR. +This can be a subset of the operations currently allowed on \fIchannel\fP. +.AP Tcl_Channel channel in +An existing Tcl channel such as returned by \fBTcl_CreateChannel\fR. +.BE + +.SH DESCRIPTION +.PP +These functions are for use by extensions that add processing layers to Tcl +I/O channels. Examples include compression and encryption modules. These +functions transparently stack and unstack a new channel on top of an +existing one. Any number of channels can be stacked together. +.PP +The implementation of the Tcl channel code was rewritten in 8.3.2 to +correct some problems with the previous implementation with regard to +stacked channels. Anyone using stacked channels or creating stacked +channel drivers should update to the new \fBTCL_CHANNEL_VERSION_2\fR +\fBTcl_ChannelType\fR structure. See \fBTcl_CreateChannel\fR for details. +.PP +\fBTcl_StackChannel\fR stacks a new \fIchannel\fP on an existing channel +with the same name that was registered for \fIchannel\fP by +\fBTcl_RegisterChannel\fP. +.PP +\fBTcl_StackChannel\fR works by creating a new channel structure and +placing itself on top of the channel stack. EOL translation, encoding and +buffering options are shared between all channels in the stack. The hidden +channel does no buffering, newline translations, or character set encoding. +Instead, the buffering, newline translations, and encoding functions all +remain at the top of the channel stack. A pointer to the new top channel +structure is returned. If an error occurs when stacking the channel, NULL +is returned instead. +.PP +The \fImask\fP parameter specifies the operations that are allowed on the +new channel. These can be a subset of the operations allowed on the +original channel. For example, a read-write channel may become read-only +after the \fBTcl_StackChannel\fR call. +.PP +Closing a channel closes the channels stacked below it. The close of +stacked channels is executed in a way that allows buffered data to be +properly flushed. +.PP +\fBTcl_UnstackChannel\fP reverses the process. The old channel is +associated with the channel name, and the processing module added by +\fBTcl_StackChannel\fR is destroyed. If there is no old channel, then +\fBTcl_UnstackChannel\fP is equivalent to \fBTcl_Close\fP. If an error +occurs unstacking the channel, \fBTCL_ERROR\fR is returned, otherwise +\fBTCL_OK\fR is returned. + +.SH "SEE ALSO" +Notifier(3), Tcl_CreateChannel(3), Tcl_OpenFileChannel(3), vwait(n). + +.SH KEYWORDS +channel, compression diff --git a/mk4/modtcl/tcl8.3.4/doc/CmdCmplt.3 b/mk4/modtcl/tcl8.3.4/doc/CmdCmplt.3 new file mode 100644 index 0000000..9483914 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/CmdCmplt.3 @@ -0,0 +1,36 @@ +'\" +'\" Copyright (c) 1989-1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: CmdCmplt.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_CommandComplete 3 "" Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_CommandComplete \- Check for unmatched braces in a Tcl command +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +int +\fBTcl_CommandComplete\fR(\fIcmd\fR) +.SH ARGUMENTS +.AS char *cmd +.AP char *cmd in +Command string to test for completeness. +.BE + +.SH DESCRIPTION +.PP +\fBTcl_CommandComplete\fR takes a Tcl command string +as argument and determines whether it contains one or more +complete commands (i.e. there are no unclosed quotes, braces, +brackets, or variable references). +If the command string is complete then it returns 1; otherwise it returns 0. + +.SH KEYWORDS +complete command, partial command diff --git a/mk4/modtcl/tcl8.3.4/doc/Concat.3 b/mk4/modtcl/tcl8.3.4/doc/Concat.3 new file mode 100644 index 0000000..99a9255 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/Concat.3 @@ -0,0 +1,55 @@ +'\" +'\" Copyright (c) 1989-1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: Concat.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_Concat 3 7.5 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_Concat \- concatenate a collection of strings +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +char * +\fBTcl_Concat\fR(\fIargc, argv\fR) +.SH ARGUMENTS +.AP int argc in +Number of strings. +.AP char *argv[] in +Array of strings to concatenate. Must have \fIargc\fR entries. +.BE + +.SH DESCRIPTION +.PP +\fBTcl_Concat\fR is a utility procedure used by several of the +Tcl commands. Given a collection of strings, it concatenates +them together into a single string, with the original strings +separated by spaces. This procedure behaves differently than +\fBTcl_Merge\fR, in that the arguments are simply concatenated: +no effort is made to ensure proper list structure. +However, in most common usage the arguments will all be proper +lists themselves; if this is true, then the result will also have +proper list structure. +.PP +\fBTcl_Concat\fR eliminates leading and trailing white space as it +copies strings from \fBargv\fR to the result. If an element of +\fBargv\fR consists of nothing but white space, then that string +is ignored entirely. This white-space removal was added to make +the output of the \fBconcat\fR command cleaner-looking. +.PP +.VS +The result string is dynamically allocated +using \fBTcl_Alloc\fR; the caller must eventually release the space +by calling \fBTcl_Free\fR. +.VE +.VS +.SH "SEE ALSO" +Tcl_ConcatObj +.SH KEYWORDS +concatenate, strings diff --git a/mk4/modtcl/tcl8.3.4/doc/CrtChannel.3 b/mk4/modtcl/tcl8.3.4/doc/CrtChannel.3 new file mode 100644 index 0000000..a32ecf9 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/CrtChannel.3 @@ -0,0 +1,760 @@ +'\" +'\" Copyright (c) 1996-1997 Sun Microsystems, Inc. +'\" Copyright (c) 1997-2000 Ajuba Solutions. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: CrtChannel.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +.so man.macros +.TH Tcl_CreateChannel 3 8.3 Tcl "Tcl Library Procedures" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +Tcl_CreateChannel, Tcl_GetChannelInstanceData, Tcl_GetChannelType, Tcl_GetChannelName, Tcl_GetChannelHandle, Tcl_GetChannelMode, Tcl_GetChannelBufferSize, Tcl_SetChannelBufferSize, Tcl_NotifyChannel, Tcl_BadChannelOption, Tcl_ChannelName, Tcl_ChannelVersion, Tcl_ChannelBlockModeProc, Tcl_ChannelCloseProc, Tcl_ChannelClose2Proc, Tcl_ChannelInputProc, Tcl_ChannelOutputProc, Tcl_ChannelSeekProc, Tcl_ChannelSetOptionProc, Tcl_ChannelGetOptionProc, Tcl_ChannelWatchProc, Tcl_ChannelGetHandleProc, Tcl_ChannelFlushProc, Tcl_ChannelHandlerProc, \- procedures for creating and manipulating channels +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +Tcl_Channel +\fBTcl_CreateChannel\fR(\fItypePtr, channelName, instanceData, mask\fR) +.sp +ClientData +\fBTcl_GetChannelInstanceData\fR(\fIchannel\fR) +.sp +Tcl_ChannelType * +\fBTcl_GetChannelType\fR(\fIchannel\fR) +.sp +char * +\fBTcl_GetChannelName\fR(\fIchannel\fR) +.sp +int +\fBTcl_GetChannelHandle\fR(\fIchannel, direction, handlePtr\fR) +.sp +int +\fBTcl_GetChannelBufferSize\fR(\fIchannel\fR) +.sp +\fBTcl_SetChannelBufferSize\fR(\fIchannel, size\fR) +.sp +\fBTcl_NotifyChannel\fR(\fIchannel, mask\fR) +.sp +int +\fBTcl_BadChannelOption\fR(\fIinterp, optionName, optionList\fR) +.VS 8.3.2 +.sp +char * +\fBTcl_ChannelName\fR(\fItypePtr\fR) +.sp +Tcl_ChannelTypeVersion +\fBTcl_ChannelVersion\fR(\fItypePtr\fR) +.sp +Tcl_DriverBlockModeProc * +\fBTcl_ChannelBlockModeProc\fR(\fItypePtr\fR) +.sp +Tcl_DriverCloseProc * +\fBTcl_ChannelCloseProc\fR(\fItypePtr\fR) +.sp +Tcl_DriverClose2Proc * +\fBTcl_ChannelClose2Proc\fR(\fItypePtr\fR) +.sp +Tcl_DriverInputProc * +\fBTcl_ChannelInputProc\fR(\fItypePtr\fR) +.sp +Tcl_DriverOutputProc * +\fBTcl_ChannelOutputProc\fR(\fItypePtr\fR) +.sp +Tcl_DriverSeekProc * +\fBTcl_ChannelSeekProc\fR(\fItypePtr\fR) +.sp +Tcl_DriverSetOptionProc * +\fBTcl_ChannelSetOptionProc\fR(\fItypePtr\fR) +.sp +Tcl_DriverGetOptionProc * +\fBTcl_ChannelGetOptionProc\fR(\fItypePtr\fR) +.sp +Tcl_DriverWatchProc * +\fBTcl_ChannelWatchProc\fR(\fItypePtr\fR) +.sp +Tcl_DriverGetHandleProc * +\fBTcl_ChannelGetHandleProc\fR(\fItypePtr\fR) +.sp +Tcl_DriverFlushProc * +\fBTcl_ChannelFlushProc\fR(\fItypePtr\fR) +.sp +Tcl_DriverHandlerProc * +\fBTcl_ChannelHandlerProc\fR(\fItypePtr\fR) +.VE +.sp +.SH ARGUMENTS +.AS Tcl_EolTranslation *channelName in +.AP Tcl_ChannelType *typePtr in +Points to a structure containing the addresses of procedures that +can be called to perform I/O and other functions on the channel. +.AP char *channelName in +The name of this channel, such as \fBfile3\fR; must not be in use +by any other channel. Can be NULL, in which case the channel is +created without a name. +.AP ClientData instanceData in +Arbitrary one-word value to be associated with this channel. This +value is passed to procedures in \fItypePtr\fR when they are invoked. +.AP int mask in +OR-ed combination of \fBTCL_READABLE\fR and \fBTCL_WRITABLE\fR to indicate +whether a channel is readable and writable. +.AP Tcl_Channel channel in +The channel to operate on. +.AP int direction in +\fBTCL_READABLE\fR means the input handle is wanted; \fBTCL_WRITABLE\fR +means the output handle is wanted. +.AP ClientData *handlePtr out +Points to the location where the desired OS-specific handle should be +stored. +.AP Tcl_EolTranslation transMode in +The translation mode; one of the constants \fBTCL_TRANSLATE_AUTO\fR, +\fBTCL_TRANSLATE_CR\fR, \fBTCL_TRANSLATE_LF\fR and \fBTCL_TRANSLATE_CRLF\fR. +.AP int size in +The size, in bytes, of buffers to allocate in this channel. +.AP int mask in +An OR-ed combination of \fBTCL_READABLE\fR, \fBTCL_WRITABLE\fR +and \fBTCL_EXCEPTION\fR that indicates events that have occurred on +this channel. +.AP Tcl_Interp *interp in +Current interpreter. (can be NULL) +.AP char *optionName in +Name of the invalid option. +.AP char *optionList in +Specific options list (space separated words, without "-") +to append to the standard generic options list. +Can be NULL for generic options error message only. + +.BE + +.SH DESCRIPTION +.PP +Tcl uses a two-layered channel architecture. It provides a generic upper +layer to enable C and Tcl programs to perform input and output using the +same APIs for a variety of files, devices, sockets etc. The generic C APIs +are described in the manual entry for \fBTcl_OpenFileChannel\fR. +.PP +The lower layer provides type-specific channel drivers for each type +of device supported on each platform. This manual entry describes the +C APIs used to communicate between the generic layer and the +type-specific channel drivers. It also explains how new types of +channels can be added by providing new channel drivers. +.PP +Channel drivers consist of a number of components: First, each channel +driver provides a \fBTcl_ChannelType\fR structure containing pointers to +functions implementing the various operations used by the generic layer to +communicate with the channel driver. The \fBTcl_ChannelType\fR structure +and the functions referenced by it are described in the section +TCL_CHANNELTYPE, below. +.PP +Second, channel drivers usually provide a Tcl command to create +instances of that type of channel. For example, the Tcl \fBopen\fR +command creates channels that use the file and command channel +drivers, and the Tcl \fBsocket\fR command creates channels that use +TCP sockets for network communication. +.PP +Third, a channel driver optionally provides a C function to open +channel instances of that type. For example, \fBTcl_OpenFileChannel\fR +opens a channel that uses the file channel driver, and +\fBTcl_OpenTcpClient\fR opens a channel that uses the TCP network +protocol. These creation functions typically use +\fBTcl_CreateChannel\fR internally to open the channel. +.PP +To add a new type of channel you must implement a C API or a Tcl command +that opens a channel by invoking \fBTcl_CreateChannel\fR. +When your driver calls \fBTcl_CreateChannel\fR it passes in +a \fBTcl_ChannelType\fR structure describing the driver's I/O +procedures. +The generic layer will then invoke the functions referenced in that +structure to perform operations on the channel. +.PP +\fBTcl_CreateChannel\fR opens a new channel and associates the supplied +\fItypePtr\fR and \fIinstanceData\fR with it. The channel is opened in the +mode indicated by \fImask\fR. +For a discussion of channel drivers, their operations and the +\fBTcl_ChannelType\fR structure, see the section TCL_CHANNELTYPE, below. +.PP +\fBTcl_GetChannelInstanceData\fR returns the instance data associated with +the channel in \fIchannel\fR. This is the same as the \fIinstanceData\fR +argument in the call to \fBTcl_CreateChannel\fR that created this channel. +.PP +\fBTcl_GetChannelType\fR returns a pointer to the \fBTcl_ChannelType\fR +structure used by the channel in the \fIchannel\fR argument. This is +the same as the \fItypePtr\fR argument in the call to +\fBTcl_CreateChannel\fR that created this channel. +.PP +\fBTcl_GetChannelName\fR returns a string containing the name associated +with the channel, or NULL if the \fIchannelName\fR argument to +\fBTcl_CreateChannel\fR was NULL. +.PP +\fBTcl_GetChannelHandle\fR places the OS-specific device handle +associated with \fIchannel\fR for the given \fIdirection\fR in the +location specified by \fIhandlePtr\fR and returns \fBTCL_OK\fR. If +the channel does not have a device handle for the specified direction, +then \fBTCL_ERROR\fR is returned instead. Different channel drivers +will return different types of handle. Refer to the manual entries +for each driver to determine what type of handle is returned. +.PP +\fBTcl_GetChannelMode\fR returns an OR-ed combination of \fBTCL_READABLE\fR +and \fBTCL_WRITABLE\fR, indicating whether the channel is open for input +and output. +.PP + \fBTcl_GetChannelBufferSize\fR returns the size, in bytes, of buffers +allocated to store input or output in \fIchan\fR. If the value was not set +by a previous call to \fBTcl_SetChannelBufferSize\fR, described below, then +the default value of 4096 is returned. +.PP +\fBTcl_SetChannelBufferSize\fR sets the size, in bytes, of buffers that +will be allocated in subsequent operations on the channel to store input or +output. The \fIsize\fR argument should be between ten and one million, +allowing buffers of ten bytes to one million bytes. If \fIsize\fR is +outside this range, \fBTcl_SetChannelBufferSize\fR sets the buffer size to +4096. +.PP +\fBTcl_NotifyChannel\fR is called by a channel driver to indicate to +the generic layer that the events specified by \fImask\fR have +occurred on the channel. Channel drivers are responsible for invoking +this function whenever the channel handlers need to be called for the +channel. See \fBWATCHPROC\fR below for more details. +.PP +\fBTcl_BadChannelOption\fR is called from driver specific set or get option +procs to generate a complete error message. + +.SH TCL_CHANNELTYPE +.PP +A channel driver provides a \fBTcl_ChannelType\fR structure that contains +pointers to functions that implement the various operations on a channel; +these operations are invoked as needed by the generic layer. The structure +was versioned starting in Tcl 8.3.2/8.4 to correct a problem with stacked +channel drivers. See the \fBOLD_CHANNEL\fR section below for details about +the old structure. +.PP +The \fBTcl_ChannelType\fR structure contains the following fields: +.CS +typedef struct Tcl_ChannelType { + char *\fItypeName\fR; + Tcl_ChannelTypeVersion \fIversion\fR; + Tcl_DriverCloseProc *\fIcloseProc\fR; + Tcl_DriverInputProc *\fIinputProc\fR; + Tcl_DriverOutputProc *\fIoutputProc\fR; + Tcl_DriverSeekProc *\fIseekProc\fR; + Tcl_DriverSetOptionProc *\fIsetOptionProc\fR; + Tcl_DriverGetOptionProc *\fIgetOptionProc\fR; + Tcl_DriverWatchProc *\fIwatchProc\fR; + Tcl_DriverGetHandleProc *\fIgetHandleProc\fR; + Tcl_DriverClose2Proc *\fIclose2Proc\fR; + Tcl_DriverBlockModeProc *\fIblockModeProc\fR; + Tcl_DriverFlushProc *\fIflushProc\fR; + Tcl_DriverHandlerProc *\fIhandlerProc\fR; +} Tcl_ChannelType; +.CE +.PP +The driver must provide implementations for all functions except +\fIblockModeProc\fR, \fIseekProc\fR, \fIsetOptionProc\fR, +\fIgetOptionProc\fR, and \fIclose2Proc\fR, which may be specified as +NULL. Other functions that can not be implemented for this type of +device should return \fBEINVAL\fR when invoked to indicate that they +are not implemented, except in the case of \fIflushProc\fR and +\fIhandlerProc\fR, which should specified as NULL if not otherwise defined. +.PP +.VS 8.3.2 +The user should only use the above structure for \fBTcl_ChannelType\fR +instantiation. When referencing fields in a \fBTcl_ChannelType\fR +structure, the following functions should be used to obtain the values: +\fBTcl_ChannelName\fR, \fBTcl_ChannelVersion\fR, +\fBTcl_ChannelBlockModeProc\fR, \fBTcl_ChannelCloseProc\fR, +\fBTcl_ChannelClose2Proc\fR, \fBTcl_ChannelInputProc\fR, +\fBTcl_ChannelOutputProc\fR, \fBTcl_ChannelSeekProc\fR, +\fBTcl_ChannelSetOptionProc\fR, \fBTcl_ChannelGetOptionProc\fR, +\fBTcl_ChannelWatchProc\fR, \fBTcl_ChannelGetHandleProc\fR, +\fBTcl_ChannelFlushProc\fR, or \fBTcl_ChannelHandlerProc\fR. +.PP +The change to the structures was made in such a way that standard channel +types are binary compatible. However, channel types that use stacked +channels (ie: TLS, Trf) have new versions to correspond to the above change +since the previous code for stacked channels had problems. +.VE + +.SH TYPENAME +.PP +The \fItypeName\fR field contains a null-terminated string that +identifies the type of the device implemented by this driver, e.g. +\fBfile\fR or \fBsocket\fR. +.PP +.VS 8.3.2 +This value can be retrieved with \fBTcl_ChannelName\fR, which returns +a pointer to the string. +.VE + +.VS 8.3.2 +.SH VERSION +.PP +The \fIversion\fR field should be set to \fBTCL_CHANNEL_VERSION_2\fR. +If it is not set to this value \fBTCL_CHANNEL_VERSION_2\fR, then this +\fBTcl_ChannelType\fR is assumed to have the older structure. See +\fBOLD_CHANNEL\fR for more details. While Tcl will recognize and +function with either structure, stacked channels must be of the newer +style to function correctly. +.PP +This value can be retrieved with \fBTcl_ChannelVersion\fR, which returns +either \fBTCL_CHANNEL_VERSION_2\fR or \fBTCL_CHANNEL_VERSION_1\fR. +.VE + +.SH BLOCKMODEPROC +.PP +The \fIblockModeProc\fR field contains the address of a function called by +the generic layer to set blocking and nonblocking mode on the device. +\fIBlockModeProc\fR should match the following prototype: +.PP +.CS +typedef int Tcl_DriverBlockModeProc( + ClientData \fIinstanceData\fR, + int \fImode\fR); +.CE +.PP +The \fIinstanceData\fR is the same as the value passed to +\fBTcl_CreateChannel\fR when this channel was created. The \fImode\fR +argument is either \fBTCL_MODE_BLOCKING\fR or \fBTCL_MODE_NONBLOCKING\fR to +set the device into blocking or nonblocking mode. The function should +return zero if the operation was successful, or a nonzero POSIX error code +if the operation failed. +.PP +If the operation is successful, the function can modify the supplied +\fIinstanceData\fR to record that the channel entered blocking or +nonblocking mode and to implement the blocking or nonblocking behavior. +For some device types, the blocking and nonblocking behavior can be +implemented by the underlying operating system; for other device types, the +behavior must be emulated in the channel driver. +.PP +.VS 8.3.2 +This value can be retrieved with \fBTcl_ChannelBlockModeProc\fR, which returns +a pointer to the function. +.VE + +.SH "CLOSEPROC AND CLOSE2PROC" +.PP +The \fIcloseProc\fR field contains the address of a function called by the +generic layer to clean up driver-related information when the channel is +closed. \fICloseProc\fR must match the following prototype: +.PP +.CS +typedef int Tcl_DriverCloseProc( + ClientData \fIinstanceData\fR, + Tcl_Interp *\fIinterp\fR); +.CE +.PP +The \fIinstanceData\fR argument is the same as the value provided to +\fBTcl_CreateChannel\fR when the channel was created. The function should +release any storage maintained by the channel driver for this channel, and +close the input and output devices encapsulated by this channel. All queued +output will have been flushed to the device before this function is called, +and no further driver operations will be invoked on this instance after +calling the \fIcloseProc\fR. If the close operation is successful, the +procedure should return zero; otherwise it should return a nonzero POSIX +error code. In addition, if an error occurs and \fIinterp\fR is not NULL, +the procedure should store an error message in the interpreter's result. +.PP +Alternatively, channels that support closing the read and write sides +independently may set \fIcloseProc\fR to \fBTCL_CLOSE2PROC\fR and set +\fIclose2Proc\fR to the address of a function that matches the +following prototype: +.PP +.CS +typedef int Tcl_DriverClose2Proc( + ClientData \fIinstanceData\fR, + Tcl_Interp *\fIinterp\fR, + int \fIflags\fR); +.CE +.PP +The \fIclose2Proc\fR will be called with \fIflags\fR set to an OR'ed +combination of \fBTCL_CLOSE_READ\fR or \fBTCL_CLOSE_WRITE\fR to +indicate that the driver should close the read and/or write side of +the channel. The channel driver may be invoked to perform +additional operations on the channel after \fIclose2Proc\fR is +called to close one or both sides of the channel. If \fIflags\fR is +\fB0\fR (zero), the driver should close the channel in the manner +described above for \fIcloseProc\fR. No further operations will be +invoked on this instance after \fIclose2Proc\fR is called with all +flags cleared. In all cases, the \fIclose2Proc\fR function should +return zero if the close operation was successful; otherwise it should +return a nonzero POSIX error code. In addition, if an error occurs and +\fIinterp\fR is not NULL, the procedure should store an error message +in the interpreter's result. +.PP +.VS 8.3.2 +These value can be retrieved with \fBTcl_ChannelCloseProc\fR or +\fBTcl_ChannelClose2Proc\fR, which returns a pointer to the respective +function. +.VE + +.SH INPUTPROC +.PP +The \fIinputProc\fR field contains the address of a function called by the +generic layer to read data from the file or device and store it in an +internal buffer. \fIInputProc\fR must match the following prototype: +.PP +.CS +typedef int Tcl_DriverInputProc( + ClientData \fIinstanceData\fR, + char *\fIbuf\fR, + int \fIbufSize\fR, + int *\fIerrorCodePtr\fR); +.CE +.PP +\fIInstanceData\fR is the same as the value passed to +\fBTcl_CreateChannel\fR when the channel was created. The \fIbuf\fR +argument points to an array of bytes in which to store input from the +device, and the \fIbufSize\fR argument indicates how many bytes are +available at \fIbuf\fR. +.PP +The \fIerrorCodePtr\fR argument points to an integer variable provided by +the generic layer. If an error occurs, the function should set the variable +to a POSIX error code that identifies the error that occurred. +.PP +The function should read data from the input device encapsulated by the +channel and store it at \fIbuf\fR. On success, the function should return +a nonnegative integer indicating how many bytes were read from the input +device and stored at \fIbuf\fR. On error, the function should return -1. If +an error occurs after some data has been read from the device, that data is +lost. +.PP +If \fIinputProc\fR can determine that the input device has some data +available but less than requested by the \fIbufSize\fR argument, the +function should only attempt to read as much data as is available and +return without blocking. If the input device has no data available +whatsoever and the channel is in nonblocking mode, the function should +return an \fBEAGAIN\fR error. If the input device has no data available +whatsoever and the channel is in blocking mode, the function should block +for the shortest possible time until at least one byte of data can be read +from the device; then, it should return as much data as it can read without +blocking. +.PP +.VS 8.3.2 +This value can be retrieved with \fBTcl_ChannelInputProc\fR, which returns +a pointer to the function. +.VE + +.SH OUTPUTPROC +.PP +The \fIoutputProc\fR field contains the address of a function called by the +generic layer to transfer data from an internal buffer to the output device. +\fIOutputProc\fR must match the following prototype: +.PP +.CS +typedef int Tcl_DriverOutputProc( + ClientData \fIinstanceData\fR, + char *\fIbuf\fR, + int \fItoWrite\fR, + int *\fIerrorCodePtr\fR); +.CE +.PP +\fIInstanceData\fR is the same as the value passed to +\fBTcl_CreateChannel\fR when the channel was created. The \fIbuf\fR +argument contains an array of bytes to be written to the device, and the +\fItoWrite\fR argument indicates how many bytes are to be written from the +\fIbuf\fR argument. +.PP +The \fIerrorCodePtr\fR argument points to an integer variable provided by +the generic layer. If an error occurs, the function should set this +variable to a POSIX error code that identifies the error. +.PP +The function should write the data at \fIbuf\fR to the output device +encapsulated by the channel. On success, the function should return a +nonnegative integer indicating how many bytes were written to the output +device. The return value is normally the same as \fItoWrite\fR, but may be +less in some cases such as if the output operation is interrupted by a +signal. If an error occurs the function should return -1. In case of +error, some data may have been written to the device. +.PP +If the channel is nonblocking and the output device is unable to absorb any +data whatsoever, the function should return -1 with an \fBEAGAIN\fR error +without writing any data. +.PP +.VS 8.3.2 +This value can be retrieved with \fBTcl_ChannelOutputProc\fR, which returns +a pointer to the function. +.VE + +.SH SEEKPROC +.PP +The \fIseekProc\fR field contains the address of a function called by the +generic layer to move the access point at which subsequent input or output +operations will be applied. \fISeekProc\fR must match the following +prototype: +.PP +.CS +typedef int Tcl_DriverSeekProc( + ClientData \fIinstanceData\fR, + long \fIoffset\fR, + int \fIseekMode\fR, + int *\fIerrorCodePtr\fR); +.CE +.PP +The \fIinstanceData\fR argument is the same as the value given to +\fBTcl_CreateChannel\fR when this channel was created. \fIOffset\fR and +\fIseekMode\fR have the same meaning as for the \fBTcl_Seek\fR +procedure (described in the manual entry for \fBTcl_OpenFileChannel\fR). +.PP +The \fIerrorCodePtr\fR argument points to an integer variable provided by +the generic layer for returning \fBerrno\fR values from the function. The +function should set this variable to a POSIX error code if an error occurs. +The function should store an \fBEINVAL\fR error code if the channel type +does not implement seeking. +.PP +The return value is the new access point or -1 in case of error. If an +error occurred, the function should not move the access point. +.PP +.VS 8.3.2 +This value can be retrieved with \fBTcl_ChannelSeekProc\fR, which returns +a pointer to the function. +.VE + +.SH SETOPTIONPROC +.PP +The \fIsetOptionProc\fR field contains the address of a function called by +the generic layer to set a channel type specific option on a channel. +\fIsetOptionProc\fR must match the following prototype: +.PP +.CS +typedef int Tcl_DriverSetOptionProc( + ClientData \fIinstanceData\fR, + Tcl_Interp *\fIinterp\fR, + char *\fIoptionName\fR, + char *\fIoptionValue\fR); +.CE +.PP +\fIoptionName\fR is the name of an option to set, and \fIoptionValue\fR is +the new value for that option, as a string. The \fIinstanceData\fR is the +same as the value given to \fBTcl_CreateChannel\fR when this channel was +created. The function should do whatever channel type specific action is +required to implement the new value of the option. +.PP +Some options are handled by the generic code and this function is never +called to set them, e.g. \fB-blockmode\fR. Other options are specific to +each channel type and the \fIsetOptionProc\fR procedure of the channel +driver will get called to implement them. The \fIsetOptionProc\fR field can +be NULL, which indicates that this channel type supports no type specific +options. +.PP +If the option value is successfully modified to the new value, the function +returns \fBTCL_OK\fR. +It should call \fBTcl_BadChannelOption\fR which itself returns +\fBTCL_ERROR\fR if the \fIoptionName\fR is +unrecognized. +If \fIoptionValue\fR specifies a value for the option that +is not supported or if a system call error occurs, +the function should leave an error message in the +\fIresult\fR field of \fIinterp\fR if \fIinterp\fR is not NULL. The +function should also call \fBTcl_SetErrno\fR to store an appropriate POSIX +error code. +.PP +.VS 8.3.2 +This value can be retrieved with \fBTcl_ChannelSetOptionProc\fR, which returns +a pointer to the function. +.VE + +.SH GETOPTIONPROC +.PP +The \fIgetOptionProc\fR field contains the address of a function called by +the generic layer to get the value of a channel type specific option on a +channel. \fIgetOptionProc\fR must match the following prototype: +.PP +.CS +typedef int Tcl_DriverGetOptionProc( + ClientData \fIinstanceData\fR, + Tcl_Interp *\fIinterp\fR, + char *\fIoptionName\fR, + Tcl_DString *\fIdsPtr\fR); +.CE +.PP +\fIOptionName\fR is the name of an option supported by this type of +channel. If the option name is not NULL, the function stores its current +value, as a string, in the Tcl dynamic string \fIdsPtr\fR. +If \fIoptionName\fR is NULL, the function stores in \fIdsPtr\fR an +alternating list of all supported options and their current values. +On success, the function returns \fBTCL_OK\fR. +It should call \fBTcl_BadChannelOption\fR which itself returns +\fBTCL_ERROR\fR if the \fIoptionName\fR is +unrecognized. If a system call error occurs, +the function should leave an error message in the +\fIresult\fR field of \fIinterp\fR if \fIinterp\fR is not NULL. The +function should also call \fBTcl_SetErrno\fR to store an appropriate POSIX +error code. +.PP +Some options are handled by the generic code and this function is never +called to retrieve their value, e.g. \fB-blockmode\fR. Other options are +specific to each channel type and the \fIgetOptionProc\fR procedure of the +channel driver will get called to implement them. The \fIgetOptionProc\fR +field can be NULL, which indicates that this channel type supports no type +specific options. +.PP +.VS 8.3.2 +This value can be retrieved with \fBTcl_ChannelGetOptionProc\fR, which returns +a pointer to the function. +.VE + +.SH WATCHPROC +.PP +The \fIwatchProc\fR field contains the address of a function called +by the generic layer to initialize the event notification mechanism to +notice events of interest on this channel. +\fIWatchProc\fR should match the following prototype: +.PP +.CS +typedef void Tcl_DriverWatchProc( + ClientData \fIinstanceData\fR, + int \fImask\fR); +.CE +.PP +The \fIinstanceData\fR is the same as the value passed to +\fBTcl_CreateChannel\fR when this channel was created. The \fImask\fR +argument is an OR-ed combination of \fBTCL_READABLE\fR, \fBTCL_WRITABLE\fR +and \fBTCL_EXCEPTION\fR; it indicates events the caller is interested in +noticing on this channel. +.PP +The function should initialize device type specific mechanisms to +notice when an event of interest is present on the channel. When one +or more of the designated events occurs on the channel, the channel +driver is responsible for calling \fBTcl_NotifyChannel\fR to inform +the generic channel module. The driver should take care not to starve +other channel drivers or sources of callbacks by invoking +Tcl_NotifyChannel too frequently. Fairness can be insured by using +the Tcl event queue to allow the channel event to be scheduled in sequence +with other events. See the description of \fBTcl_QueueEvent\fR for +details on how to queue an event. +.PP +.VS 8.3.2 +This value can be retrieved with \fBTcl_ChannelWatchProc\fR, which returns +a pointer to the function. +.VE + +.SH GETHANDLEPROC +.PP +The \fIgetHandleProc\fR field contains the address of a function called by +the generic layer to retrieve a device-specific handle from the channel. +\fIGetHandleProc\fR should match the following prototype: +.PP +.CS +typedef int Tcl_DriverGetHandleProc( + ClientData \fIinstanceData\fR, + int \fIdirection\fR, + ClientData *\fIhandlePtr\fR); +.CE +.PP +\fIInstanceData\fR is the same as the value passed to +\fBTcl_CreateChannel\fR when this channel was created. The \fIdirection\fR +argument is either \fBTCL_READABLE\fR to retrieve the handle used +for input, or \fBTCL_WRITABLE\fR to retrieve the handle used for +output. +.PP +If the channel implementation has device-specific handles, the +function should retrieve the appropriate handle associated with the +channel, according the \fIdirection\fR argument. The handle should be +stored in the location referred to by \fIhandlePtr\fR, and +\fBTCL_OK\fR should be returned. If the channel is not open for the +specified direction, or if the channel implementation does not use +device handles, the function should return \fBTCL_ERROR\fR. +.PP +.VS 8.3.2 +This value can be retrieved with \fBTcl_ChannelGetHandleProc\fR, which returns +a pointer to the function. +.VE + +.VS 8.3.2 +.SH FLUSHPROC +.PP +The \fIflushProc\fR field is currently reserved for future use. +It should be set to NULL. +\fIFlushProc\fR should match the following prototype: +.PP +.CS +typedef int Tcl_DriverFlushProc( + ClientData \fIinstanceData\fR); +.CE +.PP +This value can be retrieved with \fBTcl_ChannelFlushProc\fR, which returns +a pointer to the function. + +.SH HANDLERPROC +.PP +The \fIhandlerProc\fR field contains the address of a function called by +the generic layer to notify the channel that an event occured. It should +be defined for stacked channel drivers that wish to be notified of events +that occur on the underlying (stacked) channel. +\fIHandlerProc\fR should match the following prototype: +.PP +.CS +typedef int Tcl_DriverHandlerProc( + ClientData \fIinstanceData\fR, + int \fIinterestMask\fR); +.CE +.PP +\fIInstanceData\fR is the same as the value passed to \fBTcl_CreateChannel\fR +when this channel was created. The \fIinterestMask\fR is an OR-ed +combination of \fBTCL_READABLE\fR or \fBTCL_WRITABLE\fR; it indicates what +type of event occured on this channel. +.PP +This value can be retrieved with \fBTcl_ChannelHandlerProc\fR, which returns +a pointer to the function. +.VE + +.SH TCL_BADCHANNELOPTION +.PP +This procedure generates a "bad option" error message in an +(optional) interpreter. It is used by channel drivers when +a invalid Set/Get option is requested. Its purpose is to concatenate +the generic options list to the specific ones and factorize +the generic options error message string. +.PP +It always return \fBTCL_ERROR\fR +.PP +An error message is generated in interp's result object to +indicate that a command was invoked with the a bad option +The message has the form +.CS + bad option "blah": should be one of + <...generic options...>+<...specific options...> +so you get for instance: + bad option "-blah": should be one of -blocking, + -buffering, -buffersize, -eofchar, -translation, + -peername, or -sockname +when called with optionList="peername sockname" +.CE +``blah'' is the optionName argument and ``'' +is a space separated list of specific option words. +The function takes good care of inserting minus signs before +each option, commas after, and an ``or'' before the last option. + +.SH OLD_CHANNEL + +The original (8.3.1 and below) \fBTcl_ChannelType\fR structure contains +the following fields: +.PP +.CS +typedef struct Tcl_ChannelType { + char *\fItypeName\fR; + Tcl_DriverBlockModeProc *\fIblockModeProc\fR; + Tcl_DriverCloseProc *\fIcloseProc\fR; + Tcl_DriverInputProc *\fIinputProc\fR; + Tcl_DriverOutputProc *\fIoutputProc\fR; + Tcl_DriverSeekProc *\fIseekProc\fR; + Tcl_DriverSetOptionProc *\fIsetOptionProc\fR; + Tcl_DriverGetOptionProc *\fIgetOptionProc\fR; + Tcl_DriverWatchProc *\fIwatchProc\fR; + Tcl_DriverGetHandleProc *\fIgetHandleProc\fR; + Tcl_DriverClose2Proc *\fIclose2Proc\fR; +} Tcl_ChannelType; +.CE +.PP +It is still possible to create channel with the above structure. The +internal channel code will determine the version. It is imperative to use +the new \fBTcl_ChannelType\fR structure if you are creating a stacked +channel driver, due to problems with the earlier stacked channel +implementation (in 8.2.0 to 8.3.1). + +.SH "SEE ALSO" +Tcl_Close(3), Tcl_OpenFileChannel(3), Tcl_SetErrno(3), Tcl_QueueEvent(3), Tcl_StackChannel(3) + +.SH KEYWORDS +blocking, channel driver, channel registration, channel type, nonblocking diff --git a/mk4/modtcl/tcl8.3.4/doc/CrtChnlHdlr.3 b/mk4/modtcl/tcl8.3.4/doc/CrtChnlHdlr.3 new file mode 100644 index 0000000..4a3ed63 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/CrtChnlHdlr.3 @@ -0,0 +1,92 @@ +'\" +'\" Copyright (c) 1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: CrtChnlHdlr.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +.so man.macros +.TH Tcl_CreateChannelHandler 3 7.5 Tcl "Tcl Library Procedures" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +Tcl_CreateChannelHandler, Tcl_DeleteChannelHandler \- call a procedure when a channel becomes readable or writable +.SH SYNOPSIS +.nf +.nf +\fB#include \fR +.sp +void +\fBTcl_CreateChannelHandler\fR(\fIchannel, mask, proc, clientData\fR) +.sp +void +\fBTcl_DeleteChannelHandler\fR(\fIchannel, proc, clientData\fR) +.sp +.SH ARGUMENTS +.AS Tcl_ChannelProc clientData +.AP Tcl_Channel channel in +Tcl channel such as returned by \fBTcl_CreateChannel\fR. +.AP int mask in +Conditions under which \fIproc\fR should be called: OR-ed combination of +\fBTCL_READABLE\fR, \fBTCL_WRITABLE\fR and \fBTCL_EXCEPTION\fR. Specify +a zero value to temporarily disable an existing handler. +.AP Tcl_FileProc *proc in +Procedure to invoke whenever the channel indicated by \fIchannel\fR meets +the conditions specified by \fImask\fR. +.AP ClientData clientData in +Arbitrary one-word value to pass to \fIproc\fR. +.BE + +.SH DESCRIPTION +.PP +\fBTcl_CreateChannelHandler\fR arranges for \fIproc\fR to be called in the +future whenever input or output becomes possible on the channel identified +by \fIchannel\fR, or whenever an exceptional condition exists for +\fIchannel\fR. The conditions of interest under which \fIproc\fR will be +invoked are specified by the \fImask\fR argument. +See the manual entry for \fBfileevent\fR for a precise description of +what it means for a channel to be readable or writable. +\fIProc\fR must conform to the following prototype: +.CS +typedef void Tcl_ChannelProc( + ClientData \fIclientData\fR, + int \fImask\fR); +.CE +.PP +The \fIclientData\fR argument is the same as the value passed to +\fBTcl_CreateChannelHandler\fR when the handler was created. Typically, +\fIclientData\fR points to a data structure containing application-specific +information about the channel. \fIMask\fR is an integer mask indicating +which of the requested conditions actually exists for the channel; it will +contain a subset of the bits from the \fImask\fR argument to +\fBTcl_CreateChannelHandler\fR when the handler was created. +.PP +Each channel handler is identified by a unique combination of \fIchannel\fR, +\fIproc\fR and \fIclientData\fR. +There may be many handlers for a given channel as long as they don't +have the same \fIchannel\fR, \fIproc\fR, and \fIclientData\fR. +If \fBTcl_CreateChannelHandler\fR is invoked when there is already a handler +for \fIchannel\fR, \fIproc\fR, and \fIclientData\fR, then no new +handler is created; instead, the \fImask\fR is changed for the +existing handler. +.PP +\fBTcl_DeleteChannelHandler\fR deletes a channel handler identified by +\fIchannel\fR, \fIproc\fR and \fIclientData\fR; if no such handler exists, +the call has no effect. +.PP +Channel handlers are invoked via the Tcl event mechanism, so they +are only useful in applications that are event-driven. +Note also that the conditions specified in the \fImask\fR argument +to \fIproc\fR may no longer exist when \fIproc\fR is invoked: for +example, if there are two handlers for \fBTCL_READABLE\fR on the same +channel, the first handler could consume all of the available input +so that the channel is no longer readable when the second handler +is invoked. +For this reason it may be useful to use nonblocking I/O on channels +for which there are event handlers. + +.SH "SEE ALSO" +Notifier(3), Tcl_CreateChannel(3), Tcl_OpenFileChannel(3), vwait(n). + +.SH KEYWORDS +blocking, callback, channel, events, handler, nonblocking. diff --git a/mk4/modtcl/tcl8.3.4/doc/CrtCloseHdlr.3 b/mk4/modtcl/tcl8.3.4/doc/CrtCloseHdlr.3 new file mode 100644 index 0000000..a67a718 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/CrtCloseHdlr.3 @@ -0,0 +1,59 @@ +'\" +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: CrtCloseHdlr.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +.so man.macros +.TH Tcl_CreateCloseHandler 3 7.5 Tcl "Tcl Library Procedures" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +Tcl_CreateCloseHandler, Tcl_DeleteCloseHandler \- arrange for callbacks when channels are closed +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +void +\fBTcl_CreateCloseHandler\fR(\fIchannel, proc, clientData\fR) +.sp +void +\fBTcl_DeleteCloseHandler\fR(\fIchannel, proc, clientData\fR) +.sp +.SH ARGUMENTS +.AS Tcl_CloseProc callbackData in +.AP Tcl_Channel channel in +The channel for which to create or delete a close callback. +.AP Tcl_CloseProc *proc in +The procedure to call as the callback. +.AP ClientData clientData in +Arbitrary one-word value to pass to \fIproc\fR. +.BE + +.SH DESCRIPTION +.PP +\fBTcl_CreateCloseHandler\fR arranges for \fIproc\fR to be called when +\fIchannel\fR is closed with \fBTcl_Close\fR or +\fBTcl_UnregisterChannel\fR, or using the Tcl \fBclose\fR command. +\fIProc\fR should match the following prototype: +.PP +.CS +typedef void Tcl_CloseProc( + ClientData \fIclientData\fR); +.CE +.PP +The \fIclientData\fR is the same as the value provided in the call to +\fBTcl_CreateCloseHandler\fR. +.PP +\fBTcl_DeleteCloseHandler\fR removes a close callback for \fIchannel\fR. +The \fIproc\fR and \fIclientData\fR identify which close callback to +remove; \fBTcl_DeleteCloseHandler\fR does nothing if its \fIproc\fR and +\fIclientData\fR arguments do not match the \fIproc\fR and \fIclientData\fR +for a close handler for \fIchannel\fR. + +.SH "SEE ALSO" +close(n), Tcl_Close(3), Tcl_UnregisterChannel(3) + +.SH KEYWORDS +callback, channel closing diff --git a/mk4/modtcl/tcl8.3.4/doc/CrtCommand.3 b/mk4/modtcl/tcl8.3.4/doc/CrtCommand.3 new file mode 100644 index 0000000..ed8525a --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/CrtCommand.3 @@ -0,0 +1,143 @@ +'\" +'\" Copyright (c) 1989-1993 The Regents of the University of California. +'\" Copyright (c) 1994-1997 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: CrtCommand.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_CreateCommand 3 "" Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_CreateCommand \- implement new commands in C +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +Tcl_Command +\fBTcl_CreateCommand\fR(\fIinterp, cmdName, proc, clientData, deleteProc\fR) +.SH ARGUMENTS +.AS Tcl_CmdDeleteProc **deleteProcPtr +.AP Tcl_Interp *interp in +Interpreter in which to create new command. +.AP char *cmdName in +Name of command. +.AP Tcl_CmdProc *proc in +Implementation of new command: \fIproc\fR will be called whenever +\fIcmdName\fR is invoked as a command. +.AP ClientData clientData in +Arbitrary one-word value to pass to \fIproc\fR and \fIdeleteProc\fR. +.AP Tcl_CmdDeleteProc *deleteProc in +Procedure to call before \fIcmdName\fR is deleted from the interpreter; +allows for command-specific cleanup. If NULL, then no procedure is +called before the command is deleted. +.BE + +.SH DESCRIPTION +.PP +\fBTcl_CreateCommand\fR defines a new command in \fIinterp\fR and associates +it with procedure \fIproc\fR such that whenever \fIcmdName\fR is +invoked as a Tcl command (via a call to \fBTcl_Eval\fR) the Tcl interpreter +will call \fIproc\fR to process the command. +It differs from \fBTcl_CreateObjCommand\fR in that a new string-based +command is defined; +that is, a command procedure is defined that takes an array of +argument strings instead of objects. +The object-based command procedures registered by \fBTcl_CreateObjCommand\fR +can execute significantly faster than the string-based command procedures +defined by \fBTcl_CreateCommand\fR. +This is because they take Tcl objects as arguments +and those objects can retain an internal representation that +can be manipulated more efficiently. +Also, Tcl's interpreter now uses objects internally. +In order to invoke a string-based command procedure +registered by \fBTcl_CreateCommand\fR, +it must generate and fetch a string representation +from each argument object before the call +and create a new Tcl object to hold the string result returned by the +string-based command procedure. +New commands should be defined using \fBTcl_CreateObjCommand\fR. +We support \fBTcl_CreateCommand\fR for backwards compatibility. +.PP +The procedures \fBTcl_DeleteCommand\fR, \fBTcl_GetCommandInfo\fR, +and \fBTcl_SetCommandInfo\fR are used in conjunction with +\fBTcl_CreateCommand\fR. +.PP +\fBTcl_CreateCommand\fR will delete an existing command \fIcmdName\fR, +if one is already associated with the interpreter. +It returns a token that may be used to refer +to the command in subsequent calls to \fBTcl_GetCommandName\fR. +If \fIcmdName\fR contains any \fB::\fR namespace qualifiers, +then the command is added to the specified namespace; +otherwise the command is added to the global namespace. +If \fBTcl_CreateCommand\fR is called for an interpreter that is in +the process of being deleted, then it does not create a new command +and it returns NULL. +\fIProc\fR should have arguments and result that match the type +\fBTcl_CmdProc\fR: +.CS +typedef int Tcl_CmdProc( + ClientData \fIclientData\fR, + Tcl_Interp *\fIinterp\fR, + int \fIargc\fR, + char *\fIargv\fR[]); +.CE +When \fIproc\fR is invoked the \fIclientData\fR and \fIinterp\fR +parameters will be copies of the \fIclientData\fR and \fIinterp\fR +arguments given to \fBTcl_CreateCommand\fR. +Typically, \fIclientData\fR points to an application-specific +data structure that describes what to do when the command procedure +is invoked. \fIArgc\fR and \fIargv\fR describe the arguments to +the command, \fIargc\fR giving the number of arguments (including +the command name) and \fIargv\fR giving the values of the arguments +as strings. The \fIargv\fR array will contain \fIargc\fR+1 values; +the first \fIargc\fR values point to the argument strings, and the +last value is NULL. +.VS +Note that the argument strings should not be modified as they may +point to constant strings or may be shared with other parts of the +interpreter. +.VE +.PP +\fIProc\fR must return an integer code that is either \fBTCL_OK\fR, \fBTCL_ERROR\fR, +\fBTCL_RETURN\fR, \fBTCL_BREAK\fR, or \fBTCL_CONTINUE\fR. See the Tcl overview man page +for details on what these codes mean. Most normal commands will only +return \fBTCL_OK\fR or \fBTCL_ERROR\fR. In addition, \fIproc\fR must set +the interpreter result to point to a string value; +in the case of a \fBTCL_OK\fR return code this gives the result +of the command, and in the case of \fBTCL_ERROR\fR it gives an error message. +The \fBTcl_SetResult\fR procedure provides an easy interface for setting +the return value; for complete details on how the the interpreter result +field is managed, see the \fBTcl_Interp\fR man page. +Before invoking a command procedure, +\fBTcl_Eval\fR sets the interpreter result to point to an empty string, +so simple commands can return an empty result by doing nothing at all. +.PP +The contents of the \fIargv\fR array belong to Tcl and are not +guaranteed to persist once \fIproc\fR returns: \fIproc\fR should +not modify them, nor should it set the interpreter result to point +anywhere within the \fIargv\fR values. +Call \fBTcl_SetResult\fR with status \fBTCL_VOLATILE\fR if you want +to return something from the \fIargv\fR array. +.PP +\fIDeleteProc\fR will be invoked when (if) \fIcmdName\fR is deleted. +This can occur through a call to \fBTcl_DeleteCommand\fR or \fBTcl_DeleteInterp\fR, +or by replacing \fIcmdName\fR in another call to \fBTcl_CreateCommand\fR. +\fIDeleteProc\fR is invoked before the command is deleted, and gives the +application an opportunity to release any structures associated +with the command. \fIDeleteProc\fR should have arguments and +result that match the type \fBTcl_CmdDeleteProc\fR: +.CS +typedef void Tcl_CmdDeleteProc(ClientData \fIclientData\fR); +.CE +The \fIclientData\fR argument will be the same as the \fIclientData\fR +argument passed to \fBTcl_CreateCommand\fR. +.PP + +.SH "SEE ALSO" +Tcl_CreateObjCommand, Tcl_DeleteCommand, Tcl_GetCommandInfo, Tcl_SetCommandInfo, Tcl_GetCommandName, Tcl_SetObjResult + +.SH KEYWORDS +bind, command, create, delete, interpreter, namespace diff --git a/mk4/modtcl/tcl8.3.4/doc/CrtFileHdlr.3 b/mk4/modtcl/tcl8.3.4/doc/CrtFileHdlr.3 new file mode 100644 index 0000000..033bb4a --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/CrtFileHdlr.3 @@ -0,0 +1,100 @@ +'\" +'\" Copyright (c) 1990-1994 The Regents of the University of California. +'\" Copyright (c) 1994-1997 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: CrtFileHdlr.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_CreateFileHandler 3 8.0 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_CreateFileHandler, Tcl_DeleteFileHandler \- associate procedure callbacks with files or devices (Unix only) +.SH SYNOPSIS +.nf +\fB#include \fR +.VS +.sp +\fBTcl_CreateFileHandler\fR(\fIfd, mask, proc, clientData\fR) +.sp +\fBTcl_DeleteFileHandler\fR(\fIfd\fR) +.VE +.SH ARGUMENTS +.AS Tcl_FileProc clientData +.VS +.AP int fd in +Unix file descriptor for an open file or device. +.VE +.AP int mask in +Conditions under which \fIproc\fR should be called: +OR-ed combination of \fBTCL_READABLE\fR, \fBTCL_WRITABLE\fR, +and \fBTCL_EXCEPTION\fR. May be set to 0 to temporarily disable +a handler. +.AP Tcl_FileProc *proc in +Procedure to invoke whenever the file or device indicated +by \fIfile\fR meets the conditions specified by \fImask\fR. +.AP ClientData clientData in +Arbitrary one-word value to pass to \fIproc\fR. +.BE + +.SH DESCRIPTION +.PP +.VS +\fBTcl_CreateFileHandler\fR arranges for \fIproc\fR to be +invoked in the future whenever I/O becomes possible on a file +or an exceptional condition exists for the file. The file +is indicated by \fIfd\fR, and the conditions of interest +.VE +are indicated by \fImask\fR. For example, if \fImask\fR +is \fBTCL_READABLE\fR, \fIproc\fR will be called when +the file is readable. +The callback to \fIproc\fR is made by \fBTcl_DoOneEvent\fR, so +\fBTcl_CreateFileHandler\fR is only useful in programs that dispatch +events through \fBTcl_DoOneEvent\fR or through Tcl commands such +as \fBvwait\fR. +.PP +\fIProc\fR should have arguments and result that match the +type \fBTcl_FileProc\fR: +.CS +typedef void Tcl_FileProc( + ClientData \fIclientData\fR, + int \fImask\fR); +.CE +The \fIclientData\fR parameter to \fIproc\fR is a copy +of the \fIclientData\fR +argument given to \fBTcl_CreateFileHandler\fR when the callback +was created. Typically, \fIclientData\fR points to a data +structure containing application-specific information about +the file. \fIMask\fR is an integer mask indicating which +of the requested conditions actually exists for the file; it +will contain a subset of the bits in the \fImask\fR argument +to \fBTcl_CreateFileHandler\fR. +.PP +.PP +There may exist only one handler for a given file at a given time. +If \fBTcl_CreateFileHandler\fR is called when a handler already +exists for \fIfd\fR, then the new callback replaces the information +that was previously recorded. +.PP +\fBTcl_DeleteFileHandler\fR may be called to delete the +file handler for \fIfd\fR; if no handler exists for the +file given by \fIfd\fR then the procedure has no effect. +.PP +The purpose of file handlers is to enable an application to respond to +events while waiting for files to become ready for I/O. For this to work +correctly, the application may need to use non-blocking I/O operations on +the files for which handlers are declared. Otherwise the application may +block if it reads or writes too much data; while waiting for the I/O to +complete the application won't be able to service other events. Use +\fBTcl_SetChannelOption\fR with \fB\-blocking\fR to set the channel into +blocking or nonblocking mode as required. +.PP +.VS +Note that these interfaces are only supported by the Unix +implementation of the Tcl notifier. +.VE + +.SH KEYWORDS +callback, file, handler diff --git a/mk4/modtcl/tcl8.3.4/doc/CrtInterp.3 b/mk4/modtcl/tcl8.3.4/doc/CrtInterp.3 new file mode 100644 index 0000000..f475a1d --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/CrtInterp.3 @@ -0,0 +1,131 @@ +'\" +'\" Copyright (c) 1989-1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: CrtInterp.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_CreateInterp 3 7.5 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_CreateInterp, Tcl_DeleteInterp, Tcl_InterpDeleted \- create and delete Tcl command interpreters +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +Tcl_Interp * +\fBTcl_CreateInterp\fR() +.sp +\fBTcl_DeleteInterp\fR(\fIinterp\fR) +.sp +int +\fBTcl_InterpDeleted\fR(\fIinterp\fR) +.SH ARGUMENTS +.AS Tcl_Interp *interp +.AP Tcl_Interp *interp in +Token for interpreter to be destroyed. +.BE + +.SH DESCRIPTION +.PP +\fBTcl_CreateInterp\fR creates a new interpreter structure and returns +a token for it. The token is required in calls to most other Tcl +procedures, such as \fBTcl_CreateCommand\fR, \fBTcl_Eval\fR, and +\fBTcl_DeleteInterp\fR. +Clients are only allowed to access a few of the fields of +Tcl_Interp structures; see the \fBTcl_Interp\fR +and \fBTcl_CreateCommand\fR man pages for details. +The new interpreter is initialized with no defined variables and only +the built-in Tcl commands. To bind in additional commands, call +\fBTcl_CreateCommand\fR. +.PP +\fBTcl_DeleteInterp\fR marks an interpreter as deleted; the interpreter +will eventually be deleted when all calls to \fBTcl_Preserve\fR for it have +been matched by calls to \fBTcl_Release\fR. At that time, all of the +resources associated with it, including variables, procedures, and +application-specific command bindings, will be deleted. After +\fBTcl_DeleteInterp\fR returns any attempt to use \fBTcl_Eval\fR on the +interpreter will fail and return \fBTCL_ERROR\fR. After the call to +\fBTcl_DeleteInterp\fR it is safe to examine the interpreter's result, +query or set the values of variables, define, undefine or retrieve +procedures, and examine the runtime evaluation stack. See below, in the +section \fBINTERPRETERS AND MEMORY MANAGEMENT\fR for details. +.PP +\fBTcl_InterpDeleted\fR returns nonzero if \fBTcl_DeleteInterp\fR was +called with \fIinterp\fR as its argument; this indicates that the +interpreter will eventually be deleted, when the last call to +\fBTcl_Preserve\fR for it is matched by a call to \fBTcl_Release\fR. If +nonzero is returned, further calls to \fBTcl_Eval\fR in this interpreter +will return \fBTCL_ERROR\fR. +.PP +\fBTcl_InterpDeleted\fR is useful in deletion callbacks to distinguish +between when only the memory the callback is responsible for is being +deleted and when the whole interpreter is being deleted. In the former case +the callback may recreate the data being deleted, but this would lead to an +infinite loop if the interpreter were being deleted. + +.SH "INTERPRETERS AND MEMORY MANAGEMENT" +.PP +\fBTcl_DeleteInterp\fR can be called at any time on an interpreter that may +be used by nested evaluations and C code in various extensions. Tcl +implements a simple mechanism that allows callers to use interpreters +without worrying about the interpreter being deleted in a nested call, and +without requiring special code to protect the interpreter, in most cases. +This mechanism ensures that nested uses of an interpreter can safely +continue using it even after \fBTcl_DeleteInterp\fR is called. +.PP +The mechanism relies on matching up calls to \fBTcl_Preserve\fR with calls +to \fBTcl_Release\fR. If \fBTcl_DeleteInterp\fR has been called, only when +the last call to \fBTcl_Preserve\fR is matched by a call to +\fBTcl_Release\fR, will the interpreter be freed. See the manual entry for +\fBTcl_Preserve\fR for a description of these functions. +.PP +The rules for when the user of an interpreter must call \fBTcl_Preserve\fR +and \fBTcl_Release\fR are simple: +.TP +Interpreters Passed As Arguments +Functions that are passed an interpreter as an argument can safely use the +interpreter without any special protection. Thus, when you write an +extension consisting of new Tcl commands, no special code is needed to +protect interpreters received as arguments. This covers the majority of all +uses. +.TP +Interpreter Creation And Deletion +When a new interpreter is created and used in a call to \fBTcl_Eval\fR, +\fBTcl_VarEval\fR, \fBTcl_GlobalEval\fR, \fBTcl_SetVar\fR, or +\fBTcl_GetVar\fR, a pair of calls to \fBTcl_Preserve\fR and +\fBTcl_Release\fR should be wrapped around all uses of the interpreter. +Remember that it is unsafe to use the interpreter once \fBTcl_Release\fR +has been called. To ensure that the interpreter is properly deleted when +it is no longer needed, call \fBTcl_InterpDeleted\fR to test if some other +code already called \fBTcl_DeleteInterp\fR; if not, call +\fBTcl_DeleteInterp\fR before calling \fBTcl_Release\fR in your own code. +Do not call \fBTcl_DeleteInterp\fR on an interpreter for which +\fBTcl_InterpDeleted\fR returns nonzero. +.TP +Retrieving An Interpreter From A Data Structure +When an interpreter is retrieved from a data structure (e.g. the client +data of a callback) for use in \fBTcl_Eval\fR, \fBTcl_VarEval\fR, +\fBTcl_GlobalEval\fR, \fBTcl_SetVar\fR, or \fBTcl_GetVar\fR, a pair of +calls to \fBTcl_Preserve\fR and \fBTcl_Release\fR should be wrapped around +all uses of the interpreter; it is unsafe to reuse the interpreter once +\fBTcl_Release\fR has been called. If an interpreter is stored inside a +callback data structure, an appropriate deletion cleanup mechanism should +be set up by the code that creates the data structure so that the +interpreter is removed from the data structure (e.g. by setting the field +to NULL) when the interpreter is deleted. Otherwise, you may be using an +interpreter that has been freed and whose memory may already have been +reused. +.PP +All uses of interpreters in Tcl and Tk have already been protected. +Extension writers should ensure that their code also properly protects any +additional interpreters used, as described above. + +.SH "SEE ALSO" +Tcl_Preserve(3), Tcl_Release(3) + +.SH KEYWORDS +command, create, delete, interpreter diff --git a/mk4/modtcl/tcl8.3.4/doc/CrtMathFnc.3 b/mk4/modtcl/tcl8.3.4/doc/CrtMathFnc.3 new file mode 100644 index 0000000..5e62333 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/CrtMathFnc.3 @@ -0,0 +1,93 @@ +'\" +'\" Copyright (c) 1989-1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: CrtMathFnc.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_CreateMathFunc 3 7.0 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_CreateMathFunc \- Define a new math function for expressions +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +\fBTcl_CreateMathFunc\fR(\fIinterp, name, numArgs, argTypes, proc, clientData\fR) +.SH ARGUMENTS +.AS Tcl_ValueType clientData +.AP Tcl_Interp *interp in +Interpreter in which new function will be defined. +.AP char *name in +Name for new function. +.AP int numArgs in +Number of arguments to new function; also gives size of \fIargTypes\fR array. +.AP Tcl_ValueType *argTypes in +Points to an array giving the permissible types for each argument to +function. +.AP Tcl_MathProc *proc in +Procedure that implements the function. +.AP ClientData clientData in +Arbitrary one-word value to pass to \fIproc\fR when it is invoked. +.BE + +.SH DESCRIPTION +.PP +Tcl allows a number of mathematical functions to be used in +expressions, such as \fBsin\fR, \fBcos\fR, and \fBhypot\fR. +\fBTcl_CreateMathFunc\fR allows applications to add additional functions +to those already provided by Tcl or to replace existing functions. +\fIName\fR is the name of the function as it will appear in expressions. +If \fIname\fR doesn't already exist as a function then a new function +is created. If it does exist, then the existing function is replaced. +\fINumArgs\fR and \fIargTypes\fR describe the arguments to the function. +Each entry in the \fIargTypes\fR array must be either TCL_INT, TCL_DOUBLE, +or TCL_EITHER to indicate whether the corresponding argument must be an +integer, a double-precision floating value, or either, respectively. +.PP +Whenever the function is invoked in an expression Tcl will invoke +\fIproc\fR. \fIProc\fR should have arguments and result that match +the type \fBTcl_MathProc\fR: +.CS +typedef int Tcl_MathProc( + ClientData \fIclientData\fR, + Tcl_Interp *\fIinterp\fR, + Tcl_Value *\fIargs\fR, + Tcl_Value *\fIresultPtr\fR); +.CE +.PP +When \fIproc\fR is invoked the \fIclientData\fR and \fIinterp\fR +arguments will be the same as those passed to \fBTcl_CreateMathFunc\fR. +\fIArgs\fR will point to an array of \fInumArgs\fR Tcl_Value structures, +which describe the actual arguments to the function: +.CS +typedef struct Tcl_Value { + Tcl_ValueType \fItype\fR; + long \fIintValue\fR; + double \fIdoubleValue\fR; +} Tcl_Value; +.CE +.PP +The \fItype\fR field indicates the type of the argument and is +either TCL_INT or TCL_DOUBLE. +It will match the \fIargTypes\fR value specified for the function unless +the \fIargTypes\fR value was TCL_EITHER. Tcl converts +the argument supplied in the expression to the type requested in +\fIargTypes\fR, if that is necessary. +Depending on the value of the \fItype\fR field, the \fIintValue\fR +or \fIdoubleValue\fR field will contain the actual value of the argument. +.PP +\fIProc\fR should compute its result and store it either as an integer +in \fIresultPtr->intValue\fR or as a floating value in +\fIresultPtr->doubleValue\fR. +It should set also \fIresultPtr->type\fR to either TCL_INT or TCL_DOUBLE +to indicate which value was set. +Under normal circumstances \fIproc\fR should return TCL_OK. +If an error occurs while executing the function, \fIproc\fR should +return TCL_ERROR and leave an error message in the interpreter's result. + +.SH KEYWORDS +expression, mathematical function diff --git a/mk4/modtcl/tcl8.3.4/doc/CrtObjCmd.3 b/mk4/modtcl/tcl8.3.4/doc/CrtObjCmd.3 new file mode 100644 index 0000000..5bb67d0 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/CrtObjCmd.3 @@ -0,0 +1,260 @@ +'\" +'\" Copyright (c) 1996-1997 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: CrtObjCmd.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_CreateObjCommand 3 8.0 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_CreateObjCommand, Tcl_DeleteCommand, Tcl_DeleteCommandFromToken, Tcl_GetCommandInfo, Tcl_SetCommandInfo, Tcl_GetCommandName \- implement new commands in C +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +Tcl_Command +\fBTcl_CreateObjCommand\fR(\fIinterp, cmdName, proc, clientData, deleteProc\fR) +.sp +int +\fBTcl_DeleteCommand\fR(\fIinterp, cmdName\fR) +.sp +int +\fBTcl_DeleteCommandFromToken\fR(\fIinterp, token\fR) +.sp +int +\fBTcl_GetCommandInfo\fR(\fIinterp, cmdName, infoPtr\fR) +.sp +int +\fBTcl_SetCommandInfo\fR(\fIinterp, cmdName, infoPtr\fR) +.sp +char * +\fBTcl_GetCommandName\fR(\fIinterp, token\fR) +.SH ARGUMENTS +.AS Tcl_ObjCmdProc *deleteProc in/out +.AP Tcl_Interp *interp in +Interpreter in which to create a new command or that contains a command. +.AP char *cmdName in +Name of command. +.AP Tcl_ObjCmdProc *proc in +Implementation of the new command: \fIproc\fR will be called whenever +\fIcmdName\fR is invoked as a command. +.AP ClientData clientData in +Arbitrary one-word value to pass to \fIproc\fR and \fIdeleteProc\fR. +.AP Tcl_CmdDeleteProc *deleteProc in +Procedure to call before \fIcmdName\fR is deleted from the interpreter; +allows for command-specific cleanup. If NULL, then no procedure is +called before the command is deleted. +.AP Tcl_Command token in +Token for command, returned by previous call to \fBTcl_CreateObjCommand\fR. +The command must not have been deleted. +.AP Tcl_CmdInfo *infoPtr in/out +Pointer to structure containing various information about a +Tcl command. +.BE +.SH DESCRIPTION +.PP +\fBTcl_CreateObjCommand\fR defines a new command in \fIinterp\fR +and associates it with procedure \fIproc\fR +such that whenever \fIname\fR is +invoked as a Tcl command (e.g., via a call to \fBTcl_EvalObjEx\fR) +the Tcl interpreter will call \fIproc\fR to process the command. +.PP +\fBTcl_CreateObjCommand\fR deletes any existing command +\fIname\fR already associated with the interpreter +(however see below for an exception where the existing command +is not deleted). +It returns a token that may be used to refer +to the command in subsequent calls to \fBTcl_GetCommandName\fR. +If \fIname\fR contains any \fB::\fR namespace qualifiers, +then the command is added to the specified namespace; +otherwise the command is added to the global namespace. +If \fBTcl_CreateObjCommand\fR is called for an interpreter that is in +the process of being deleted, then it does not create a new command +and it returns NULL. +\fIproc\fR should have arguments and result that match the type +\fBTcl_ObjCmdProc\fR: +.CS +typedef int Tcl_ObjCmdProc( + ClientData \fIclientData\fR, + Tcl_Interp *\fIinterp\fR, + int \fIobjc\fR, +.VS + Tcl_Obj *CONST \fIobjv\fR[]); +.CE +When \fIproc\fR is invoked, the \fIclientData\fR and \fIinterp\fR parameters +will be copies of the \fIclientData\fR and \fIinterp\fR arguments given to +\fBTcl_CreateObjCommand\fR. Typically, \fIclientData\fR points to an +application-specific data structure that describes what to do when the +command procedure is invoked. \fIObjc\fR and \fIobjv\fR describe the +arguments to the command, \fIobjc\fR giving the number of argument objects +(including the command name) and \fIobjv\fR giving the values of the +arguments. The \fIobjv\fR array will contain \fIobjc\fR values, pointing to +the argument objects. Unlike \fIargv\fR[\fIargv\fR] used in a +string-based command procedure, \fIobjv\fR[\fIobjc\fR] will not contain NULL. +.PP +Additionally, when \fIproc\fR is invoked, it must not modify the contents +of the \fIobjv\fR array by assigning new pointer values to any element of the +array (for example, \fIobjv\fR[\fB2\fR] = \fBNULL\fR) because this will +cause memory to be lost and the runtime stack to be corrupted. The +\fBCONST\fR in the declaration of \fIobjv\fR will cause ANSI-compliant +compilers to report any such attempted assignment as an error. However, +it is acceptable to modify the internal representation of any individual +object argument. For instance, the user may call +\fBTcl_GetIntFromObj\fR on \fIobjv\fR[\fB2\fR] to obtain the integer +representation of that object; that call may change the type of the object +that \fIobjv\fR[\fB2\fR] points at, but will not change where +\fIobjv\fR[\fB2\fR] points. +.VE +.PP +\fIproc\fR must return an integer code that is either \fBTCL_OK\fR, +\fBTCL_ERROR\fR, \fBTCL_RETURN\fR, \fBTCL_BREAK\fR, or \fBTCL_CONTINUE\fR. +See the Tcl overview man page +for details on what these codes mean. Most normal commands will only +return \fBTCL_OK\fR or \fBTCL_ERROR\fR. +In addition, if \fIproc\fR needs to return a non-empty result, +it can call \fBTcl_SetObjResult\fR to set the interpreter's result. +In the case of a \fBTCL_OK\fR return code this gives the result +of the command, +and in the case of \fBTCL_ERROR\fR this gives an error message. +Before invoking a command procedure, +\fBTcl_EvalObjEx\fR sets interpreter's result to +point to an object representing an empty string, so simple +commands can return an empty result by doing nothing at all. +.PP +The contents of the \fIobjv\fR array belong to Tcl and are not +guaranteed to persist once \fIproc\fR returns: \fIproc\fR should +not modify them. +Call \fBTcl_SetObjResult\fR if you want +to return something from the \fIobjv\fR array. +.PP +Ordinarily, \fBTcl_CreateObjCommand\fR deletes any existing command +\fIname\fR already associated with the interpreter. +However, if the existing command was created by a previous call to +\fBTcl_CreateCommand\fR, +\fBTcl_CreateObjCommand\fR does not delete the command +but instead arranges for the Tcl interpreter to call the +\fBTcl_ObjCmdProc\fR \fIproc\fR in the future. +The old string-based \fBTcl_CmdProc\fR associated with the command +is retained and its address can be obtained by subsequent +\fBTcl_GetCommandInfo\fR calls. This is done for backwards compatibility. +.PP +\fIDeleteProc\fR will be invoked when (if) \fIname\fR is deleted. +This can occur through a call to \fBTcl_DeleteCommand\fR, +\fBTcl_DeleteCommandFromToken\fR, or \fBTcl_DeleteInterp\fR, +or by replacing \fIname\fR in another call to \fBTcl_CreateObjCommand\fR. +\fIDeleteProc\fR is invoked before the command is deleted, and gives the +application an opportunity to release any structures associated +with the command. \fIDeleteProc\fR should have arguments and +result that match the type \fBTcl_CmdDeleteProc\fR: +.CS +typedef void Tcl_CmdDeleteProc(ClientData \fIclientData\fR); +.CE +The \fIclientData\fR argument will be the same as the \fIclientData\fR +argument passed to \fBTcl_CreateObjCommand\fR. +.PP +\fBTcl_DeleteCommand\fR deletes a command from a command interpreter. +Once the call completes, attempts to invoke \fIcmdName\fR in +\fIinterp\fR will result in errors. +If \fIcmdName\fR isn't bound as a command in \fIinterp\fR then +\fBTcl_DeleteCommand\fR does nothing and returns -1; otherwise +it returns 0. +There are no restrictions on \fIcmdName\fR: it may refer to +a built-in command, an application-specific command, or a Tcl procedure. +If \fIname\fR contains any \fB::\fR namespace qualifiers, +the command is deleted from the specified namespace. +.PP +Given a token returned by \fBTcl_CreateObjCommand\fR, +\fBTcl_DeleteCommandFromToken\fR deletes the command +from a command interpreter. +It will delete a command even if that command has been renamed. +Once the call completes, attempts to invoke the command in +\fIinterp\fR will result in errors. +If the command corresponding to \fItoken\fR +has already been deleted from \fIinterp\fR then +\fBTcl_DeleteCommand\fR does nothing and returns -1; +otherwise it returns 0. +.PP +\fBTcl_GetCommandInfo\fR checks to see whether its \fIcmdName\fR argument +exists as a command in \fIinterp\fR. +\fIcmdName\fR may include \fB::\fR namespace qualifiers +to identify a command in a particular namespace. +If the command is not found, then it returns 0. +Otherwise it places information about the command +in the \fBTcl_CmdInfo\fR structure +pointed to by \fIinfoPtr\fR and returns 1. +A \fBTcl_CmdInfo\fR structure has the following fields: +.CS +typedef struct Tcl_CmdInfo { + int isNativeObjectProc; + Tcl_ObjCmdProc *objProc; + ClientData objClientData; + Tcl_CmdProc *proc; + ClientData clientData; + Tcl_CmdDeleteProc *deleteProc; + ClientData deleteData; + Tcl_Namespace *namespacePtr; +} Tcl_CmdInfo; +.CE +The \fIisNativeObjectProc\fR field has the value 1 +if \fBTcl_CreateObjCommand\fR was called to register the command; +it is 0 if only \fBTcl_CreateCommand\fR was called. +It allows a program to determine whether it is faster to +call \fIobjProc\fR or \fIproc\fR: +\fIobjProc\fR is normally faster +if \fIisNativeObjectProc\fR has the value 1. +The fields \fIobjProc\fR and \fIobjClientData\fR +have the same meaning as the \fIproc\fR and \fIclientData\fR +arguments to \fBTcl_CreateObjCommand\fR; +they hold information about the object-based command procedure +that the Tcl interpreter calls to implement the command. +The fields \fIproc\fR and \fIclientData\fR +hold information about the string-based command procedure +that implements the command. +If \fBTcl_CreateCommand\fR was called for this command, +this is the procedure passed to it; +otherwise, this is a compatibility procedure +registered by \fBTcl_CreateObjCommand\fR +that simply calls the command's +object-based procedure after converting its string arguments to Tcl objects. +The field \fIdeleteData\fR is the ClientData value +to pass to \fIdeleteProc\fR; it is normally the same as +\fIclientData\fR but may be set independently using the +\fBTcl_SetCommandInfo\fR procedure. +The field \fInamespacePtr\fR holds a pointer to the +Tcl_Namespace that contains the command. +.PP +\fBTcl_SetCommandInfo\fR is used to modify the procedures and +ClientData values associated with a command. +Its \fIcmdName\fR argument is the name of a command in \fIinterp\fR. +\fIcmdName\fR may include \fB::\fR namespace qualifiers +to identify a command in a particular namespace. +If this command does not exist then \fBTcl_SetCommandInfo\fR returns 0. +Otherwise, it copies the information from \fI*infoPtr\fR to +Tcl's internal structure for the command and returns 1. +Note that this procedure allows the ClientData for a command's +deletion procedure to be given a different value than the ClientData +for its command procedure. +Note that \fBTcl_SetCmdInfo\fR will not change a command's namespace; +you must use \fBTcl_RenameCommand\fR to do that. +.PP +\fBTcl_GetCommandName\fR provides a mechanism for tracking commands +that have been renamed. +Given a token returned by \fBTcl_CreateObjCommand\fR +when the command was created, \fBTcl_GetCommandName\fR returns the +string name of the command. If the command has been renamed since it +was created, then \fBTcl_GetCommandName\fR returns the current name. +This name does not include any \fB::\fR namespace qualifiers. +The command corresponding to \fItoken\fR must not have been deleted. +The string returned by \fBTcl_GetCommandName\fR is in dynamic memory +owned by Tcl and is only guaranteed to retain its value as long as the +command isn't deleted or renamed; callers should copy the string if +they need to keep it for a long time. + +.SH "SEE ALSO" +Tcl_CreateCommand, Tcl_ResetResult, Tcl_SetObjResult + +.SH KEYWORDS +bind, command, create, delete, namespace, object diff --git a/mk4/modtcl/tcl8.3.4/doc/CrtSlave.3 b/mk4/modtcl/tcl8.3.4/doc/CrtSlave.3 new file mode 100644 index 0000000..c2b2e71 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/CrtSlave.3 @@ -0,0 +1,231 @@ +'\" +'\" Copyright (c) 1995-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: CrtSlave.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_CreateSlave 3 7.6 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_IsSafe, Tcl_MakeSafe, Tcl_CreateSlave, Tcl_GetSlave, Tcl_GetMaster, Tcl_GetInterpPath, Tcl_CreateAlias, Tcl_CreateAliasObj, Tcl_GetAlias, Tcl_GetAliasObj, Tcl_ExposeCommand, Tcl_HideCommand \- manage multiple Tcl interpreters, aliases and hidden commands. +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +int +\fBTcl_IsSafe\fR(\fIinterp\fR) +.sp +int +\fBTcl_MakeSafe\fR(\fIinterp\fR) +.sp +Tcl_Interp * +\fBTcl_CreateSlave\fR(\fIinterp, slaveName, isSafe\fR) +.sp +Tcl_Interp * +\fBTcl_GetSlave\fR(\fIinterp, slaveName\fR) +.sp +Tcl_Interp * +\fBTcl_GetMaster\fR(\fIinterp\fR) +.sp +int +\fBTcl_GetInterpPath\fR(\fIaskingInterp, slaveInterp\fR) +.sp +.VS +int +\fBTcl_CreateAlias\fR(\fIslaveInterp, srcCmd, targetInterp, targetCmd, argc, argv\fR) +.sp +int +\fBTcl_CreateAliasObj\fR(\fIslaveInterp, srcCmd, targetInterp, targetCmd, objc, objv\fR) +.VE +.sp +int +\fBTcl_GetAlias\fR(\fIinterp, srcCmd, targetInterpPtr, targetCmdPtr, argcPtr, argvPtr\fR) +.sp +.VS +int +\fBTcl_GetAliasObj\fR(\fIinterp, srcCmd, targetInterpPtr, targetCmdPtr, objcPtr, objvPtr\fR) +.sp +int +\fBTcl_ExposeCommand\fR(\fIinterp, hiddenCmdName, cmdName\fR) +.sp +int +\fBTcl_HideCommand\fR(\fIinterp, cmdName, hiddenCmdName\fR) +.SH ARGUMENTS +.AS Tcl_InterpDeleteProc **hiddenCmdName +.AP Tcl_Interp *interp in +Interpreter in which to execute the specified command. +.AP char *slaveName in +Name of slave interpreter to create or manipulate. +.AP int isSafe in +If non-zero, a ``safe'' slave that is suitable for running untrusted code +is created, otherwise a trusted slave is created. +.AP Tcl_Interp *slaveInterp in +Interpreter to use for creating the source command for an alias (see +below). +.AP char *srcCmd in +Name of source command for alias. +.AP Tcl_Interp *targetInterp in +Interpreter that contains the target command for an alias. +.AP char *targetCmd in +Name of target command for alias in \fItargetInterp\fR. +.AP int argc in +Count of additional arguments to pass to the alias command. +.AP char **argv in +Vector of strings, the additional arguments to pass to the alias command. +This storage is owned by the caller. +.AP int objc in +Count of additional object arguments to pass to the alias object command. +.AP Tcl_Object **objv in +Vector of Tcl_Obj structures, the additional object argumenst to pass to +the alias object command. +This storage is owned by the caller. +.AP Tcl_Interp **targetInterpPtr in +Pointer to location to store the address of the interpreter where a target +command is defined for an alias. +.AP char **targetCmdPtr out +Pointer to location to store the address of the name of the target command +for an alias. +.AP int *argcPtr out +Pointer to location to store count of additional arguments to be passed to +the alias. The location is in storage owned by the caller. +.AP char ***argvPtr out +Pointer to location to store a vector of strings, the additional arguments +to pass to an alias. The location is in storage owned by the caller, the +vector of strings is owned by the called function. +.AP int *objcPtr out +Pointer to location to store count of additional object arguments to be +passed to the alias. The location is in storage owned by the caller. +.AP Tcl_Obj ***objvPtr out +Pointer to location to store a vector of Tcl_Obj structures, the additional +arguments to pass to an object alias command. The location is in storage +owned by the caller, the vector of Tcl_Obj structures is owned by the +called function. +.VS +.AP char *cmdName in +Name of an exposed command to hide or create. +.AP char *hiddenCmdName in +Name under which a hidden command is stored and with which it can be +exposed or invoked. +.VE +.BE + +.SH DESCRIPTION +.PP +These procedures are intended for access to the multiple interpreter +facility from inside C programs. They enable managing multiple interpreters +in a hierarchical relationship, and the management of aliases, commands +that when invoked in one interpreter execute a command in another +interpreter. The return value for those procedures that return an \fBint\fR +is either \fBTCL_OK\fR or \fBTCL_ERROR\fR. If \fBTCL_ERROR\fR is returned +then the \fBresult\fR field of the interpreter contains an error message. +.PP +\fBTcl_CreateSlave\fR creates a new interpreter as a slave of \fIinterp\fR. +It also creates a slave command named \fIslaveName\fR in \fIinterp\fR which +allows \fIinterp\fR to manipulate the new slave. +If \fIisSafe\fR is zero, the command creates a trusted slave in which Tcl +code has access to all the Tcl commands. +If it is \fB1\fR, the command creates a ``safe'' slave in which Tcl code +has access only to set of Tcl commands defined as ``Safe Tcl''; see the +manual entry for the Tcl \fBinterp\fR command for details. +If the creation of the new slave interpreter failed, \fBNULL\fR is returned. +.PP +\fBTcl_IsSafe\fR returns \fB1\fR if \fIinterp\fR is ``safe'' (was created +with the \fBTCL_SAFE_INTERPRETER\fR flag specified), +\fB0\fR otherwise. +.PP +\fBTcl_MakeSafe\fR makes \fIinterp\fR ``safe'' by removing all +non-core and core unsafe functionality. Note that if you call this after +adding some extension to an interpreter, all traces of that extension will +be removed from the interpreter. +.PP +\fBTcl_GetSlave\fR returns a pointer to a slave interpreter of +\fIinterp\fR. The slave interpreter is identified by \fIslaveName\fR. +If no such slave interpreter exists, \fBNULL\fR is returned. +.PP +\fBTcl_GetMaster\fR returns a pointer to the master interpreter of +\fIinterp\fR. If \fIinterp\fR has no master (it is a +top-level interpreter) then \fBNULL\fR is returned. +.PP +\fBTcl_GetInterpPath\fR sets the \fIresult\fR field in \fIaskingInterp\fR +to the relative path between \fIaskingInterp\fR and \fIslaveInterp\fR; +\fIslaveInterp\fR must be a slave of \fIaskingInterp\fR. If the computation +of the relative path succeeds, \fBTCL_OK\fR is returned, else +\fBTCL_ERROR\fR is returned and the \fIresult\fR field in +\fIaskingInterp\fR contains the error message. +.PP +.VS +\fBTcl_CreateAlias\fR creates an object command named \fIsrcCmd\fR in +\fIslaveInterp\fR that when invoked, will cause the command \fItargetCmd\fR +to be invoked in \fItargetInterp\fR. The arguments specified by the strings +contained in \fIargv\fR are always prepended to any arguments supplied in the +invocation of \fIsrcCmd\fR and passed to \fItargetCmd\fR. +This operation returns \fBTCL_OK\fR if it succeeds, or \fBTCL_ERROR\fR if +it fails; in that case, an error message is left in the object result +of \fIslaveInterp\fR. +Note that there are no restrictions on the ancestry relationship (as +created by \fBTcl_CreateSlave\fR) between \fIslaveInterp\fR and +\fItargetInterp\fR. Any two interpreters can be used, without any +restrictions on how they are related. +.PP +\fBTcl_CreateAliasObj\fR is similar to \fBTcl_CreateAlias\fR except +that it takes a vector of objects to pass as additional arguments instead +of a vector of strings. +.VE +.PP +\fBTcl_GetAlias\fR returns information about an alias \fIaliasName\fR +in \fIinterp\fR. Any of the result fields can be \fBNULL\fR, in +which case the corresponding datum is not returned. If a result field is +non\-\fBNULL\fR, the address indicated is set to the corresponding datum. +For example, if \fItargetNamePtr\fR is non\-\fBNULL\fR it is set to a +pointer to the string containing the name of the target command. +.VS +.PP +\fBTcl_GetAliasObj\fR is similar to \fBTcl_GetAlias\fR except that it +returns a pointer to a vector of Tcl_Obj structures instead of a vector of +strings. +.PP +\fBTcl_ExposeCommand\fR moves the command named \fIhiddenCmdName\fR from +the set of hidden commands to the set of exposed commands, putting +it under the name +\fIcmdName\fR. +\fIHiddenCmdName\fR must be the name of an existing hidden +command, or the operation will return \fBTCL_ERROR\fR and leave an error +message in the \fIresult\fR field in \fIinterp\fR. +If an exposed command named \fIcmdName\fR already exists, +the operation returns \fBTCL_ERROR\fR and leaves an error message in the +object result of \fIinterp\fR. +If the operation succeeds, it returns \fBTCL_OK\fR. +After executing this command, attempts to use \fIcmdName\fR in a call to +\fBTcl_Eval\fR or with the Tcl \fBeval\fR command will again succeed. +.PP +\fBTcl_HideCommand\fR moves the command named \fIcmdName\fR from the set of +exposed commands to the set of hidden commands, under the name +\fIhiddenCmdName\fR. +\fICmdName\fR must be the name of an existing exposed +command, or the operation will return \fBTCL_ERROR\fR and leave an error +message in the object result of \fIinterp\fR. +Currently both \fIcmdName\fR and \fIhiddenCmdName\fR must not contain +namespace qualifiers, or the operation will return \fBTCL_ERROR\fR and +leave an error message in the object result of \fIinterp\fR. +The \fICmdName\fR will be looked up in the global namespace, and not +relative to the current namespace, even if the current namespace is not the +global one. +If a hidden command whose name is \fIhiddenCmdName\fR already +exists, the operation also returns \fBTCL_ERROR\fR and the \fIresult\fR +field in \fIinterp\fR contains an error message. +If the operation succeeds, it returns \fBTCL_OK\fR. +After executing this command, attempts to use \fIcmdName\fR in a call to +\fBTcl_Eval\fR or with the Tcl \fBeval\fR command will fail. +.PP +For a description of the Tcl interface to multiple interpreters, see +\fIinterp(n)\fR. +.SH "SEE ALSO" +interp + +.SH KEYWORDS +alias, command, exposed commands, hidden commands, interpreter, invoke, +master, slave, + diff --git a/mk4/modtcl/tcl8.3.4/doc/CrtTimerHdlr.3 b/mk4/modtcl/tcl8.3.4/doc/CrtTimerHdlr.3 new file mode 100644 index 0000000..5571818 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/CrtTimerHdlr.3 @@ -0,0 +1,76 @@ +'\" +'\" Copyright (c) 1990 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: CrtTimerHdlr.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_CreateTimerHandler 3 7.5 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_CreateTimerHandler, Tcl_DeleteTimerHandler \- call a procedure at a +given time +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +Tcl_TimerToken +\fBTcl_CreateTimerHandler\fR(\fImilliseconds, proc, clientData\fR) +.sp +\fBTcl_DeleteTimerHandler\fR(\fItoken\fR) +.SH ARGUMENTS +.AS Tcl_TimerToken milliseconds +.AP int milliseconds in +How many milliseconds to wait before invoking \fIproc\fR. +.AP Tcl_TimerProc *proc in +Procedure to invoke after \fImilliseconds\fR have elapsed. +.AP ClientData clientData in +Arbitrary one-word value to pass to \fIproc\fR. +.AP Tcl_TimerToken token in +Token for previously-created timer handler (the return value +from some previous call to \fBTcl_CreateTimerHandler\fR). +.BE + +.SH DESCRIPTION +.PP +\fBTcl_CreateTimerHandler\fR arranges for \fIproc\fR to be +invoked at a time \fImilliseconds\fR milliseconds in the +future. +The callback to \fIproc\fR will be made by \fBTcl_DoOneEvent\fR, +so \fBTcl_CreateTimerHandler\fR is only useful in programs that +dispatch events through \fBTcl_DoOneEvent\fR or through Tcl commands +such as \fBvwait\fR. +The call to \fIproc\fR may not be made at the exact time given by +\fImilliseconds\fR: it will be made at the next opportunity +after that time. For example, if \fBTcl_DoOneEvent\fR isn't +called until long after the time has elapsed, or if there +are other pending events to process before the call to +\fIproc\fR, then the call to \fIproc\fR will be delayed. +.PP +\fIProc\fR should have arguments and return value that match +the type \fBTcl_TimerProc\fR: +.CS +typedef void Tcl_TimerProc(ClientData \fIclientData\fR); +.CE +The \fIclientData\fR parameter to \fIproc\fR is a +copy of the \fIclientData\fR argument given to +\fBTcl_CreateTimerHandler\fR when the callback +was created. Typically, \fIclientData\fR points to a data +structure containing application-specific information about +what to do in \fIproc\fR. +.PP +\fBTcl_DeleteTimerHandler\fR may be called to delete a +previously-created timer handler. It deletes the handler +indicated by \fItoken\fR so that no call to \fIproc\fR +will be made; if that handler no longer exists +(e.g. because the time period has already elapsed and \fIproc\fR +has been invoked then \fBTcl_DeleteTimerHandler\fR does nothing. +The tokens returned by \fBTcl_CreateTimerHandler\fR never have +a value of NULL, so if NULL is passed to \fBTcl_DeleteTimerHandler\fR +then the procedure does nothing. + +.SH KEYWORDS +callback, clock, handler, timer diff --git a/mk4/modtcl/tcl8.3.4/doc/CrtTrace.3 b/mk4/modtcl/tcl8.3.4/doc/CrtTrace.3 new file mode 100644 index 0000000..cfb2e4e --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/CrtTrace.3 @@ -0,0 +1,106 @@ +'\" +'\" Copyright (c) 1989-1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: CrtTrace.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_CreateTrace 3 "" Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_CreateTrace, Tcl_DeleteTrace \- arrange for command execution to be traced +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +Tcl_Trace +\fBTcl_CreateTrace\fR(\fIinterp, level, proc, clientData\fR) +.sp +\fBTcl_DeleteTrace\fR(\fIinterp, trace\fR) +.SH ARGUMENTS +.AS Tcl_CmdTraceProc (clientData)() +.AP Tcl_Interp *interp in +Interpreter containing command to be traced or untraced. +.AP int level in +Only commands at or below this nesting level will be traced. 1 means +top-level commands only, 2 means top-level commands or those that are +invoked as immediate consequences of executing top-level commands +(procedure bodies, bracketed commands, etc.) and so on. +.AP Tcl_CmdTraceProc *proc in +Procedure to call for each command that's executed. See below for +details on the calling sequence. +.AP ClientData clientData in +Arbitrary one-word value to pass to \fIproc\fR. +.AP Tcl_Trace trace in +Token for trace to be removed (return value from previous call +to \fBTcl_CreateTrace\fR). +.BE + +.SH DESCRIPTION +.PP +\fBTcl_CreateTrace\fR arranges for command tracing. From now on, \fIproc\fR +will be invoked before Tcl calls command procedures to process +commands in \fIinterp\fR. The return value from +\fBTcl_CreateTrace\fR is a token for the trace, +which may be passed to \fBTcl_DeleteTrace\fR to remove the trace. There may +be many traces in effect simultaneously for the same command interpreter. +.PP +\fIProc\fR should have arguments and result that match the +type \fBTcl_CmdTraceProc\fR: +.CS +typedef void Tcl_CmdTraceProc( + ClientData \fIclientData\fR, + Tcl_Interp *\fIinterp\fR, + int \fIlevel\fR, + char *\fIcommand\fR, + Tcl_CmdProc *\fIcmdProc\fR, + ClientData \fIcmdClientData\fR, + int \fIargc\fR, + char *\fIargv\fR[]); +.CE +The \fIclientData\fR and \fIinterp\fR parameters are +copies of the corresponding arguments given to \fBTcl_CreateTrace\fR. +\fIClientData\fR typically points to an application-specific +data structure that describes what to do when \fIproc\fR +is invoked. \fILevel\fR gives the nesting level of the command +(1 for top-level commands passed to \fBTcl_Eval\fR by the application, +2 for the next-level commands passed to \fBTcl_Eval\fR as part of parsing +or interpreting level-1 commands, and so on). \fICommand\fR +points to a string containing the text of the +command, before any argument substitution. +\fICmdProc\fR contains the address of the command procedure that +will be called to process the command (i.e. the \fIproc\fR argument +of some previous call to \fBTcl_CreateCommand\fR) and \fIcmdClientData\fR +contains the associated client data for \fIcmdProc\fR (the \fIclientData\fR +value passed to \fBTcl_CreateCommand\fR). \fIArgc\fR and \fIargv\fR give +the final argument information that will be passed to \fIcmdProc\fR, after +command, variable, and backslash substitution. +\fIProc\fR must not modify the \fIcommand\fR or \fIargv\fR strings. +.PP +Tracing will only occur for commands at nesting level less than +or equal to the \fIlevel\fR parameter (i.e. the \fIlevel\fR +parameter to \fIproc\fR will always be less than or equal to the +\fIlevel\fR parameter to \fBTcl_CreateTrace\fR). +.PP +Calls to \fIproc\fR will be made by the Tcl parser immediately before +it calls the command procedure for the command (\fIcmdProc\fR). This +occurs after argument parsing and substitution, so tracing for +substituted commands occurs before tracing of the commands +containing the substitutions. If there is a syntax error in a +command, or if there is no command procedure associated with a +command name, then no tracing will occur for that command. If a +string passed to Tcl_Eval contains multiple commands (bracketed, or +on different lines) then multiple calls to \fIproc\fR will occur, +one for each command. The \fIcommand\fR string for each of these +trace calls will reflect only a single command, not the entire string +passed to Tcl_Eval. +.PP +\fBTcl_DeleteTrace\fR removes a trace, so that no future calls will be +made to the procedure associated with the trace. After \fBTcl_DeleteTrace\fR +returns, the caller should never again use the \fItrace\fR token. + +.SH KEYWORDS +command, create, delete, interpreter, trace diff --git a/mk4/modtcl/tcl8.3.4/doc/DString.3 b/mk4/modtcl/tcl8.3.4/doc/DString.3 new file mode 100644 index 0000000..9fb01f4 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/DString.3 @@ -0,0 +1,151 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: DString.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_DString 3 7.4 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_DStringInit, Tcl_DStringAppend, Tcl_DStringAppendElement, Tcl_DStringStartSublist, Tcl_DStringEndSublist, Tcl_DStringLength, Tcl_DStringValue, Tcl_DStringSetLength, Tcl_DStringFree, Tcl_DStringResult, Tcl_DStringGetResult \- manipulate dynamic strings +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +\fBTcl_DStringInit\fR(\fIdsPtr\fR) +.sp +char * +\fBTcl_DStringAppend\fR(\fIdsPtr, string, length\fR) +.sp +char * +\fBTcl_DStringAppendElement\fR(\fIdsPtr, string\fR) +.sp +\fBTcl_DStringStartSublist\fR(\fIdsPtr\fR) +.sp +\fBTcl_DStringEndSublist\fR(\fIdsPtr\fR) +.sp +int +\fBTcl_DStringLength\fR(\fIdsPtr\fR) +.sp +char * +\fBTcl_DStringValue\fR(\fIdsPtr\fR) +.sp +\fBTcl_DStringSetLength\fR(\fIdsPtr, newLength\fR) +.sp +\fBTcl_DStringTrunc\fR(\fIdsPtr, newLength\fR) +.sp +\fBTcl_DStringFree\fR(\fIdsPtr\fR) +.sp +\fBTcl_DStringResult\fR(\fIinterp, dsPtr\fR) +.sp +\fBTcl_DStringGetResult\fR(\fIinterp, dsPtr\fR) +.SH ARGUMENTS +.AS Tcl_DString newLength +.AP Tcl_DString *dsPtr in/out +Pointer to structure that is used to manage a dynamic string. +.AP char *string in +Pointer to characters to add to dynamic string. +.AP int length in +Number of characters from string to add to dynamic string. If -1, +add all characters up to null terminating character. +.AP int newLength in +New length for dynamic string, not including null terminating +character. +.AP Tcl_Interp *interp in/out +Interpreter whose result is to be set from or moved to the +dynamic string. +.BE + +.SH DESCRIPTION +.PP +Dynamic strings provide a mechanism for building up arbitrarily long +strings by gradually appending information. If the dynamic string is +short then there will be no memory allocation overhead; as the string +gets larger, additional space will be allocated as needed. +.PP +\fBTcl_DStringInit\fR initializes a dynamic string to zero length. +The Tcl_DString structure must have been allocated by the caller. +No assumptions are made about the current state of the structure; +anything already in it is discarded. +If the structure has been used previously, \fBTcl_DStringFree\fR should +be called first to free up any memory allocated for the old +string. +.PP +\fBTcl_DStringAppend\fR adds new information to a dynamic string, +allocating more memory for the string if needed. +If \fIlength\fR is less than zero then everything in \fIstring\fR +is appended to the dynamic string; otherwise \fIlength\fR +specifies the number of bytes to append. +\fBTcl_DStringAppend\fR returns a pointer to the characters of +the new string. The string can also be retrieved from the +\fIstring\fR field of the Tcl_DString structure. +.PP +\fBTcl_DStringAppendElement\fR is similar to \fBTcl_DStringAppend\fR +except that it doesn't take a \fIlength\fR argument (it appends +all of \fIstring\fR) and it converts the string to a proper list element +before appending. +\fBTcl_DStringAppendElement\fR adds a separator space before the +new list element unless the new list element is the first in a +list or sub-list (i.e. either the current string is empty, or it +contains the single character ``{'', or the last two characters of +the current string are `` {''). +\fBTcl_DStringAppendElement\fR returns a pointer to the +characters of the new string. +.PP +\fBTcl_DStringStartSublist\fR and \fBTcl_DStringEndSublist\fR can be +used to create nested lists. +To append a list element that is itself a sublist, first +call \fBTcl_DStringStartSublist\fR, then call \fBTcl_DStringAppendElement\fR +for each of the elements in the sublist, then call +\fBTcl_DStringEndSublist\fR to end the sublist. +\fBTcl_DStringStartSublist\fR appends a space character if needed, +followed by an open brace; \fBTcl_DStringEndSublist\fR appends +a close brace. +Lists can be nested to any depth. +.PP +\fBTcl_DStringLength\fR is a macro that returns the current length +of a dynamic string (not including the terminating null character). +\fBTcl_DStringValue\fR is a macro that returns a pointer to the +current contents of a dynamic string. +.PP +.PP +\fBTcl_DStringSetLength\fR changes the length of a dynamic string. +If \fInewLength\fR is less than the string's current length, then +the string is truncated. +If \fInewLength\fR is greater than the string's current length, +then the string will become longer and new space will be allocated +for the string if needed. +However, \fBTcl_DStringSetLength\fR will not initialize the new +space except to provide a terminating null character; it is up to the +caller to fill in the new space. +\fBTcl_DStringSetLength\fR does not free up the string's storage space +even if the string is truncated to zero length, so \fBTcl_DStringFree\fR +will still need to be called. +.PP +\fBTcl_DStringTrunc\fR changes the length of a dynamic string. +This procedure is now deprecated. \fBTcl_DStringSetLength\fR should +be used instead. +.PP +\fBTcl_DStringFree\fR should be called when you're finished using +the string. It frees up any memory that was allocated for the string +and reinitializes the string's value to an empty string. +.PP +\fBTcl_DStringResult\fR sets the result of \fIinterp\fR to the value of +the dynamic string given by \fIdsPtr\fR. It does this by moving +a pointer from \fIdsPtr\fR to the interpreter's result. +This saves the cost of allocating new memory and copying the string. +\fBTcl_DStringResult\fR also reinitializes the dynamic string to +an empty string. +.PP +\fBTcl_DStringGetResult\fR does the opposite of \fBTcl_DStringResult\fR. +It sets the value of \fIdsPtr\fR to the result of \fIinterp\fR and +it clears \fIinterp\fR's result. +If possible it does this by moving a pointer rather than by copying +the string. + +.SH KEYWORDS +append, dynamic string, free, result diff --git a/mk4/modtcl/tcl8.3.4/doc/DetachPids.3 b/mk4/modtcl/tcl8.3.4/doc/DetachPids.3 new file mode 100644 index 0000000..504b2be --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/DetachPids.3 @@ -0,0 +1,77 @@ +'\" +'\" Copyright (c) 1989-1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: DetachPids.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_DetachPids 3 "" Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_DetachPids, Tcl_ReapDetachedProcs, Tcl_WaitPid \- manage child processes in background +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +\fBTcl_DetachPids\fR(\fInumPids, pidPtr\fR) +.sp +\fBTcl_ReapDetachedProcs\fR() +.sp +Tcl_Pid +\fBTcl_WaitPid\fR(\fIpid, statPtr, options\fR) +.SH ARGUMENTS +.AS int *statusPtr +.AP int numPids in +Number of process ids contained in the array pointed to by \fIpidPtr\fR. +.AP int *pidPtr in +Address of array containing \fInumPids\fR process ids. +.AP Tcl_Pid pid in +The id of the process (pipe) to wait for. +.AP int* statPtr out +The result of waiting on a process (pipe). Either 0 or ECHILD. +.AP int options +The options controlling the wait. WNOHANG specifies not to wait when +checking the process. +.BE +.SH DESCRIPTION +.PP +\fBTcl_DetachPids\fR and \fBTcl_ReapDetachedProcs\fR provide a +mechanism for managing subprocesses that are running in background. +These procedures are needed because the parent of a process must +eventually invoke the \fBwaitpid\fR kernel call (or one of a few other +similar kernel calls) to wait for the child to exit. Until the +parent waits for the child, the child's state cannot be completely +reclaimed by the system. If a parent continually creates children +and doesn't wait on them, the system's process table will eventually +overflow, even if all the children have exited. +.PP +\fBTcl_DetachPids\fR may be called to ask Tcl to take responsibility +for one or more processes whose process ids are contained in the +\fIpidPtr\fR array passed as argument. The caller presumably +has started these processes running in background and doesn't +want to have to deal with them again. +.PP +\fBTcl_ReapDetachedProcs\fR invokes the \fBwaitpid\fR kernel call +on each of the background processes so that its state can be cleaned +up if it has exited. If the process hasn't exited yet, +\fBTcl_ReapDetachedProcs\fR doesn't wait for it to exit; it will check again +the next time it is invoked. +Tcl automatically calls \fBTcl_ReapDetachedProcs\fR each time the +\fBexec\fR command is executed, so in most cases it isn't necessary +for any code outside of Tcl to invoke \fBTcl_ReapDetachedProcs\fR. +However, if you call \fBTcl_DetachPids\fR in situations where the +\fBexec\fR command may never get executed, you may wish to call +\fBTcl_ReapDetachedProcs\fR from time to time so that background +processes can be cleaned up. +.PP +\fBTcl_WaitPid\fR is a thin wrapper around the facilities provided by +the operating system to wait on the end of a spawned process and to +check a whether spawned process is still running. It is used by +\fBTcl_ReapDetachedProcs\fR and the channel system to portably access +the operating system. + +.SH KEYWORDS +background, child, detach, process, wait diff --git a/mk4/modtcl/tcl8.3.4/doc/DoOneEvent.3 b/mk4/modtcl/tcl8.3.4/doc/DoOneEvent.3 new file mode 100644 index 0000000..4c3b320 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/DoOneEvent.3 @@ -0,0 +1,108 @@ +'\" +'\" Copyright (c) 1990-1992 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: DoOneEvent.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_DoOneEvent 3 7.5 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_DoOneEvent \- wait for events and invoke event handlers +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +int +\fBTcl_DoOneEvent\fR(\fIflags\fR) +.SH ARGUMENTS +.AS int flags +.AP int flags in +This parameter is normally zero. It may be an OR-ed combination +of any of the following flag bits: +TCL_WINDOW_EVENTS, +TCL_FILE_EVENTS, TCL_TIMER_EVENTS, TCL_IDLE_EVENTS, TCL_ALL_EVENTS, or +TCL_DONT_WAIT. +.BE + +.SH DESCRIPTION +.PP +This procedure is the entry point to Tcl's event loop; it is responsible for +waiting for events and dispatching event handlers created with +procedures such as \fBTk_CreateEventHandler\fR, \fBTcl_CreateFileHandler\fR, +\fBTcl_CreateTimerHandler\fR, and \fBTcl_DoWhenIdle\fR. +\fBTcl_DoOneEvent\fR checks to see if +events are already present on the Tcl event queue; if so, +it calls the handler(s) for the first (oldest) event, removes it from +the queue, and returns. +If there are no events ready to be handled, then \fBTcl_DoOneEvent\fR +checks for new events from all possible sources. +If any are found, it puts all of them on Tcl's event queue, calls +handlers for the first event on the queue, and returns. +If no events are found, \fBTcl_DoOneEvent\fR checks for \fBTcl_DoWhenIdle\fR +callbacks; if any are found, it invokes all of them and returns. +Finally, if no events or idle callbacks have been found, then +\fBTcl_DoOneEvent\fR sleeps until an event occurs; then it adds any +new events to the Tcl event queue, calls handlers for the first event, +and returns. +The normal return value is 1 to signify that some event +was processed (see below for other alternatives). +.PP +If the \fIflags\fR argument to \fBTcl_DoOneEvent\fR is non-zero, +it restricts the kinds of events that will be processed by +\fBTcl_DoOneEvent\fR. +\fIFlags\fR may be an OR-ed combination of any of the following bits: +.TP 27 +\fBTCL_WINDOW_EVENTS\fR \- +Process window system events. +.TP 27 +\fBTCL_FILE_EVENTS\fR \- +Process file events. +.TP 27 +\fBTCL_TIMER_EVENTS\fR \- +Process timer events. +.TP 27 +\fBTCL_IDLE_EVENTS\fR \- +Process idle callbacks. +.TP 27 +\fBTCL_ALL_EVENTS\fR \- +Process all kinds of events: equivalent to OR-ing together all of the +above flags or specifying none of them. +.TP 27 +\fBTCL_DONT_WAIT\fR \- +Don't sleep: process only events that are ready at the time of the +call. +.LP +If any of the flags \fBTCL_WINDOW_EVENTS\fR, \fBTCL_FILE_EVENTS\fR, +\fBTCL_TIMER_EVENTS\fR, or \fBTCL_IDLE_EVENTS\fR is set, then the only +events that will be considered are those for which flags are set. +Setting none of these flags is equivalent to the value +\fBTCL_ALL_EVENTS\fR, which causes all event types to be processed. +If an application has defined additional event sources with +\fBTcl_CreateEventSource\fR, then additional \fIflag\fR values +may also be valid, depending on those event sources. +.PP +The \fBTCL_DONT_WAIT\fR flag causes \fBTcl_DoOneEvent\fR not to put +the process to sleep: it will check for events but if none are found +then it returns immediately with a return value of 0 to indicate +that no work was done. +\fBTcl_DoOneEvent\fR will also return 0 without doing anything if +the only alternative is to block forever (this can happen, for example, +if \fIflags\fR is \fBTCL_IDLE_EVENTS\fR and there are no +\fBTcl_DoWhenIdle\fR callbacks pending, or if no event handlers or +timer handlers exist). +.PP +\fBTcl_DoOneEvent\fR may be invoked recursively. For example, +it is possible to invoke \fBTcl_DoOneEvent\fR recursively +from a handler called by \fBTcl_DoOneEvent\fR. This sort +of operation is useful in some modal situations, such +as when a +notification dialog has been popped up and an application wishes to +wait for the user to click a button in the dialog before +doing anything else. + +.SH KEYWORDS +callback, event, handler, idle, timer diff --git a/mk4/modtcl/tcl8.3.4/doc/DoWhenIdle.3 b/mk4/modtcl/tcl8.3.4/doc/DoWhenIdle.3 new file mode 100644 index 0000000..76c9e17 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/DoWhenIdle.3 @@ -0,0 +1,86 @@ +'\" +'\" Copyright (c) 1990 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: DoWhenIdle.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_DoWhenIdle 3 7.5 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_DoWhenIdle, Tcl_CancelIdleCall \- invoke a procedure when there are no pending events +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +\fBTcl_DoWhenIdle\fR(\fIproc, clientData\fR) +.sp +\fBTcl_CancelIdleCall\fR(\fIproc, clientData\fR) +.SH ARGUMENTS +.AS Tcl_IdleProc clientData +.AP Tcl_IdleProc *proc in +Procedure to invoke. +.AP ClientData clientData in +Arbitrary one-word value to pass to \fIproc\fR. +.BE + +.SH DESCRIPTION +.PP +\fBTcl_DoWhenIdle\fR arranges for \fIproc\fR to be invoked +when the application becomes idle. The application is +considered to be idle when \fBTcl_DoOneEvent\fR has been +called, couldn't find any events to handle, and is about +to go to sleep waiting for an event to occur. At this +point all pending \fBTcl_DoWhenIdle\fR handlers are +invoked. For each call to \fBTcl_DoWhenIdle\fR there will +be a single call to \fIproc\fR; after \fIproc\fR is +invoked the handler is automatically removed. +\fBTcl_DoWhenIdle\fR is only usable in programs that +use \fBTcl_DoOneEvent\fR to dispatch events. +.PP +\fIProc\fR should have arguments and result that match the +type \fBTcl_IdleProc\fR: +.CS +typedef void Tcl_IdleProc(ClientData \fIclientData\fR); +.CE +The \fIclientData\fR parameter to \fIproc\fR is a copy of the \fIclientData\fR +argument given to \fBTcl_DoWhenIdle\fR. Typically, \fIclientData\fR +points to a data structure containing application-specific information about +what \fIproc\fR should do. +.PP +\fBTcl_CancelIdleCall\fR +may be used to cancel one or more previous +calls to \fBTcl_DoWhenIdle\fR: if there is a \fBTcl_DoWhenIdle\fR +handler registered for \fIproc\fR and \fIclientData\fR, then it +is removed without invoking it. If there is more than one +handler on the idle list that refers to \fIproc\fR and \fIclientData\fR, +all of the handlers are removed. If no existing handlers match +\fIproc\fR and \fIclientData\fR then nothing happens. +.PP +\fBTcl_DoWhenIdle\fR is most useful in situations where +(a) a piece of work will have to be done but (b) it's +possible that something will happen in the near future +that will change what has to be done or require something +different to be done. \fBTcl_DoWhenIdle\fR allows the +actual work to be deferred until all pending events have +been processed. At this point the exact work to be done +will presumably be known and it can be done exactly once. +.PP +For example, \fBTcl_DoWhenIdle\fR might be used by an editor +to defer display updates until all pending commands have +been processed. Without this feature, redundant redisplays +might occur in some situations, such as the processing of +a command file. +.SH BUGS +.PP +At present it is not safe for an idle callback to reschedule itself +continuously. This will interact badly with certain features of Tk +that attempt to wait for all idle callbacks to complete. If you would +like for an idle callback to reschedule itself continuously, it is +better to use a timer handler with a zero timeout period. + +.SH KEYWORDS +callback, defer, idle callback diff --git a/mk4/modtcl/tcl8.3.4/doc/DoubleObj.3 b/mk4/modtcl/tcl8.3.4/doc/DoubleObj.3 new file mode 100644 index 0000000..a6adb12 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/DoubleObj.3 @@ -0,0 +1,79 @@ +'\" +'\" Copyright (c) 1996-1997 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: DoubleObj.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_DoubleObj 3 8.0 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_NewDoubleObj, Tcl_SetDoubleObj, Tcl_GetDoubleFromObj \- manipulate Tcl objects as floating-point values +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +Tcl_Obj * +\fBTcl_NewDoubleObj\fR(\fIdoubleValue\fR) +.sp +\fBTcl_SetDoubleObj\fR(\fIobjPtr, doubleValue\fR) +.sp +int +\fBTcl_GetDoubleFromObj\fR(\fIinterp, objPtr, doublePtr\fR) +.SH ARGUMENTS +.AS Tcl_Interp doubleValue in/out +.AP double doubleValue in +A double-precision floating point value used to initialize or set a double object. +.AP Tcl_Obj *objPtr in/out +For \fBTcl_SetDoubleObj\fR, this points to the object to be converted +to double type. +For \fBTcl_GetDoubleFromObj\fR, this refers to the object +from which to get a double value; +if \fIobjPtr\fR does not already point to a double object, +an attempt will be made to convert it to one. +.AP Tcl_Interp *interp in/out +If an error occurs during conversion, +an error message is left in the interpreter's result object +unless \fIinterp\fR is NULL. +.AP double *doublePtr out +Points to place to store the double value +obtained from \fIobjPtr\fR. +.BE + +.SH DESCRIPTION +.PP +These procedures are used to create, modify, and read +double Tcl objects from C code. +\fBTcl_NewDoubleObj\fR and \fBTcl_SetDoubleObj\fR +will create a new object of double type +or modify an existing object to have double type. +Both of these procedures set the object to have the +double-precision floating point value given by \fIdoubleValue\fR; +\fBTcl_NewDoubleObj\fR returns a pointer to a newly created object +with reference count zero. +Both procedures set the object's type to be double +and assign the double value to the object's internal representation +\fIdoubleValue\fR member. +\fBTcl_SetDoubleObj\fR invalidates any old string representation +and, if the object is not already a double object, +frees any old internal representation. +.PP +\fBTcl_GetDoubleFromObj\fR attempts to return a double value +from the Tcl object \fIobjPtr\fR. +If the object is not already a double object, +it will attempt to convert it to one. +If an error occurs during conversion, it returns \fBTCL_ERROR\fR +and leaves an error message in the interpreter's result object +unless \fIinterp\fR is NULL. +Otherwise, it returns \fBTCL_OK\fR and stores the double value +in the address given by \fIdoublePtr\fR. +If the object is not already a double object, +the conversion will free any old internal representation. + +.SH "SEE ALSO" +Tcl_NewObj, Tcl_DecrRefCount, Tcl_IncrRefCount, Tcl_GetObjResult + +.SH KEYWORDS +double, double object, double type, internal representation, object, object type, string representation diff --git a/mk4/modtcl/tcl8.3.4/doc/DumpActiveMemory.3 b/mk4/modtcl/tcl8.3.4/doc/DumpActiveMemory.3 new file mode 100644 index 0000000..eb59436 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/DumpActiveMemory.3 @@ -0,0 +1,68 @@ +'\" +'\" Copyright (c) 1992-1999 Karl Lehenbauer and Mark Diekhans. +'\" Copyright (c) 2000 by Scriptics Corporation. +'\" All rights reserved. +'\" +'\" RCS: @(#) $Id: DumpActiveMemory.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH "Tcl_DumpActiveMemory" 3 8.1 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_DumpActiveMemory, Tcl_InitMemory, Tcl_ValidateAllMemory \- Validated memory allocation interface. +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +int +\fBTcl_DumpActiveMemory\fR(\fIfileName\fR) +.sp +void +\fBTcl_InitMemory\fR(\fIinterp\fR) +.sp +void +\fBTcl_ValidateAllMemory\fR(\fIfileName, line\fR) + +.SH ARGUMENTS +.AP Tcl_Interp *interp in +Tcl interpreter in which to add commands. +.AP char *fileName in +For \fBTcl_DumpActiveMemory\fR, name of the file to which memory +information will be written. For \fBTcl_ValidateAllMemory\fR, name of +the file from which the call is being made (normally \fB__FILE__\fR). +.AP int line in +Line number at which the call to \fBTcl_ValidateAllMemory\fR is made +(normally \fB__LINE__\fR). +.BE + +.SH DESCRIPTION +These functions provide access to Tcl memory debugging information. +They are only available when Tcl has been compiled with +\fBTCL_MEM_DEBUG\fR defined at compile-time. +.PP +\fBTcl_DumpActiveMemory\fR will output a list of all currently +allocated memory to the specified file. The information output for +each allocated block of memory is: starting and ending addresses +(excluding guard zone), size, source file where \fBckalloc\fR was +called to allocate the block and line number in that file. It is +especially useful to call \fBTcl_DumpActiveMemory\fR after the Tcl +interpreter has been deleted. +.PP +\fBTcl_InitMemory\fR adds the Tcl \fBmemory\fR command to the +interpreter given by \fIinterp\fR. It is called by \fBTcl_Main\fR +when Tcl has been compiled with \fBTCL_MEM_DEBUG\fR defined. +.PP +\fBTcl_ValidateAllMemory\fR forces a validation of the guard zones of +all currently allocated blocks of memory. Normally validation of a +block occurs when its freed, unless full validation is enabled, in +which case validation of all blocks occurs when \fBckalloc\fR and +\fBckfree\fR are called. This function forces the validation to occur +at any point. + +.SH "SEE ALSO" +TCL_MEM_DEBUG, memory + +.SH KEYWORDS +memory, debug + + diff --git a/mk4/modtcl/tcl8.3.4/doc/Encoding.3 b/mk4/modtcl/tcl8.3.4/doc/Encoding.3 new file mode 100644 index 0000000..fb89775 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/Encoding.3 @@ -0,0 +1,523 @@ +'\" +'\" Copyright (c) 1997-1998 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: Encoding.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_GetEncoding 3 "8.1" Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_GetEncoding, Tcl_FreeEncoding, Tcl_ExternalToUtfDString, Tcl_ExternalToUtf, Tcl_UtfToExternalDString, Tcl_UtfToExternal, Tcl_WinTCharToUtf, Tcl_WinUtfToTChar, Tcl_GetEncodingName, Tcl_SetSystemEncoding, Tcl_GetEncodingNames, Tcl_CreateEncoding, Tcl_GetDefaultEncodingDir, Tcl_SetDefaultEncodingDir \- procedures for creating and using encodings. +.SH SYNOPSIS +.nf +\fB#include \fR +\fB#include \fR \fI/* Tcl_Win* functions only */\fR +.sp +Tcl_Encoding +\fBTcl_GetEncoding\fR(\fIinterp, name\fR) +.sp +void +\fBTcl_FreeEncoding\fR(\fIencoding\fR) +.sp +char * +\fBTcl_ExternalToUtfDString\fR(\fIencoding, src, srcLen, dstPtr\fR) +.sp +int +\fBTcl_ExternalToUtf\fR(\fIinterp, encoding, src, srcLen, flags, statePtr, dst, dstLen, srcReadPtr, dstWrotePtr, + dstCharsPtr\fR) +.sp +char * +\fBTcl_UtfToExternalDString\fR(\fIencoding, src, srcLen, dstPtr\fR) +.sp +int +\fBTcl_UtfToExternal\fR(\fIinterp, encoding, src, srcLen, flags, statePtr, dst, dstLen, srcReadPtr, dstWrotePtr, + dstCharsPtr\fR) +.sp +char * +\fBTcl_WinTCharToUtf\fR(\fItsrc, srcLen, dstPtr\fR) +.sp +TCHAR * +\fBTcl_WinUtfToTChar\fR(\fIsrc, srcLen, dstPtr\fR) +.sp +char * +\fBTcl_GetEncodingName\fR(\fIencoding\fR) +.sp +int +\fBTcl_SetSystemEncoding\fR(\fIinterp, name\fR) +.sp +void +\fBTcl_GetEncodingNames\fR(\fIinterp\fR) +.sp +Tcl_Encoding +\fBTcl_CreateEncoding\fR(\fItypePtr\fR) +.sp +char * +\fBTcl_GetDefaultEncodingDir\fR(\fIvoid\fR) +.sp +void +\fBTcl_SetDefaultEncodingDir\fR(\fIpath\fR) + + +.SH ARGUMENTS +.AS Tcl_EncodingState *dstWrotePtr +.AP Tcl_Interp *interp in +Interpreter to use for error reporting, or NULL if no error reporting is +desired. +.AP "CONST char" *name in +Name of encoding to load. +.AP Tcl_Encoding encoding in +The encoding to query, free, or use for converting text. If \fIencoding\fR is +NULL, the current system encoding is used. +.AP "CONST char" *src in +For the \fBTcl_ExternalToUtf\fR functions, an array of bytes in the +specified encoding that are to be converted to UTF-8. For the +\fBTcl_UtfToExternal\fR and \fBTcl_WinUtfToTChar\fR functions, an array of +UTF-8 characters to be converted to the specified encoding. +.AP "CONST TCHAR" *tsrc in +An array of Windows TCHAR characters to convert to UTF-8. +.AP int srcLen in +Length of \fIsrc\fR or \fItsrc\fR in bytes. If the length is negative, the +encoding-specific length of the string is used. +.AP Tcl_DString *dstPtr out +Pointer to an uninitialized or free \fBTcl_DString\fR in which the converted +result will be stored. +.AP int flags in +Various flag bits OR-ed together. +TCL_ENCODING_START signifies that the +source buffer is the first block in a (potentially multi-block) input +stream, telling the conversion routine to reset to an initial state and +perform any initialization that needs to occur before the first byte is +converted. TCL_ENCODING_END signifies that the source buffer is the last +block in a (potentially multi-block) input stream, telling the conversion +routine to perform any finalization that needs to occur after the last +byte is converted and then to reset to an initial state. +TCL_ENCODING_STOPONERROR signifies that the conversion routine should +return immediately upon reading a source character that doesn't exist in +the target encoding; otherwise a default fallback character will +automatically be substituted. +.AP Tcl_EncodingState *statePtr in/out +Used when converting a (generally long or indefinite length) byte stream +in a piece by piece fashion. The conversion routine stores its current +state in \fI*statePtr\fR after \fIsrc\fR (the buffer containing the +current piece) has been converted; that state information must be passed +back when converting the next piece of the stream so the conversion +routine knows what state it was in when it left off at the end of the +last piece. May be NULL, in which case the value specified for \fIflags\fR +is ignored and the source buffer is assumed to contain the complete string to +convert. +.AP char *dst out +Buffer in which the converted result will be stored. No more than +\fIdstLen\fR bytes will be stored in \fIdst\fR. +.AP int dstLen in +The maximum length of the output buffer \fIdst\fR in bytes. +.AP int *srcReadPtr out +Filled with the number of bytes from \fIsrc\fR that were actually +converted. This may be less than the original source length if there was +a problem converting some source characters. May be NULL. +.AP int *dstWrotePtr out +Filled with the number of bytes that were actually stored in the output +buffer as a result of the conversion. May be NULL. +.AP int *dstCharsPtr out +Filled with the number of characters that correspond to the number of bytes +stored in the output buffer. May be NULL. +.AP Tcl_EncodingType *typePtr in +Structure that defines a new type of encoding. +.AP char *path in +A path to the location of the encoding file. +.BE +.SH INTRODUCTION +.PP +These routines convert between Tcl's internal character representation, +UTF-8, and character representations used by various operating systems or +file systems, such as Unicode, ASCII, or Shift-JIS. When operating on +strings, such as such as obtaining the names of files or displaying +characters using international fonts, the strings must be translated into +one or possibly multiple formats that the various system calls can use. For +instance, on a Japanese Unix workstation, a user might obtain a filename +represented in the EUC-JP file encoding and then translate the characters to +the jisx0208 font encoding in order to display the filename in a Tk widget. +The purpose of the encoding package is to help bridge the translation gap. +UTF-8 provides an intermediate staging ground for all the various +encodings. In the example above, text would be translated into UTF-8 from +whatever file encoding the operating system is using. Then it would be +translated from UTF-8 into whatever font encoding the display routines +require. +.PP +Some basic encodings are compiled into Tcl. Others can be defined by the +user or dynamically loaded from encoding files in a +platform-independent manner. +.SH DESCRIPTION +.PP +\fBTcl_GetEncoding\fR finds an encoding given its \fIname\fR. The name may +refer to a builtin Tcl encoding, a user-defined encoding registered by +calling \fBTcl_CreateEncoding\fR, or a dynamically-loadable encoding +file. The return value is a token that represents the encoding and can be +used in subsequent calls to procedures such as \fBTcl_GetEncodingName\fR, +\fBTcl_FreeEncoding\fR, and \fBTcl_UtfToExternal\fR. If the name did not +refer to any known or loadable encoding, NULL is returned and an error +message is returned in \fIinterp\fR. +.PP +The encoding package maintains a database of all encodings currently in use. +The first time \fIname\fR is seen, \fBTcl_GetEncoding\fR returns an +encoding with a reference count of 1. If the same \fIname\fR is requested +further times, then the reference count for that encoding is incremented +without the overhead of allocating a new encoding and all its associated +data structures. +.PP +When an \fIencoding\fR is no longer needed, \fBTcl_FreeEncoding\fR +should be called to release it. When an \fIencoding\fR is no longer in use +anywhere (i.e., it has been freed as many times as it has been gotten) +\fBTcl_FreeEncoding\fR will release all storage the encoding was using +and delete it from the database. +.PP +\fBTcl_ExternalToUtfDString\fR converts a source buffer \fIsrc\fR from the +specified \fIencoding\fR into UTF-8. The converted bytes are stored in +\fIdstPtr\fR, which is then NULL terminated. The caller should eventually +call \fBTcl_DStringFree\fR to free any information stored in \fIdstPtr\fR. +When converting, if any of the characters in the source buffer cannot be +represented in the target encoding, a default fallback character will be +used. The return value is a pointer to the value stored in the DString. +.PP +\fBTcl_ExternalToUtf\fR converts a source buffer \fIsrc\fR from the specified +\fIencoding\fR into UTF-8. Up to \fIsrcLen\fR bytes are converted from the +source buffer and up to \fIdstLen\fR converted bytes are stored in \fIdst\fR. +In all cases, \fI*srcReadPtr\fR is filled with the number of bytes that were +successfully converted from \fIsrc\fR and \fI*dstWrotePtr\fR is filled with +the corresponding number of bytes that were stored in \fIdst\fR. The return +value is one of the following: +.RS +.IP \fBTCL_OK\fR 29 +All bytes of \fIsrc\fR were converted. +.IP \fBTCL_CONVERT_NOSPACE\fR 29 +The destination buffer was not large enough for all of the converted data; as +many characters as could fit were converted though. +.IP \fBTCL_CONVERT_MULTIBYTE\fR 29 +The last fews bytes in the source buffer were the beginning of a multibyte +sequence, but more bytes were needed to complete this sequence. A +subsequent call to the conversion routine should pass a buffer containing +the unconverted bytes that remained in \fIsrc\fR plus some further bytes +from the source stream to properly convert the formerly split-up multibyte +sequence. +.IP \fBTCL_CONVERT_SYNTAX\fR 29 +The source buffer contained an invalid character sequence. This may occur +if the input stream has been damaged or if the input encoding method was +misidentified. +.IP \fBTCL_CONVERT_UNKNOWN\fR 29 +The source buffer contained a character that could not be represented in +the target encoding and TCL_ENCODING_STOPONERROR was specified. +.RE +.LP +\fBTcl_UtfToExternalDString\fR converts a source buffer \fIsrc\fR from UTF-8 +into the specified \fIencoding\fR. The converted bytes are stored in +\fIdstPtr\fR, which is then terminated with the appropriate encoding-specific +NULL. The caller should eventually call \fBTcl_DStringFree\fR to free any +information stored in \fIdstPtr\fR. When converting, if any of the +characters in the source buffer cannot be represented in the target +encoding, a default fallback character will be used. The return value is +a pointer to the value stored in the DString. +.PP +\fBTcl_UtfToExternal\fR converts a source buffer \fIsrc\fR from UTF-8 into +the specified \fIencoding\fR. Up to \fIsrcLen\fR bytes are converted from +the source buffer and up to \fIdstLen\fR converted bytes are stored in +\fIdst\fR. In all cases, \fI*srcReadPtr\fR is filled with the number of +bytes that were successfully converted from \fIsrc\fR and \fI*dstWrotePtr\fR +is filled with the corresponding number of bytes that were stored in +\fIdst\fR. The return values are the same as the return values for +\fBTcl_ExternalToUtf\fR. +.PP +\fBTcl_WinUtfToTChar\fR and \fBTcl_WinTCharToUtf\fR are +Windows-only convenience +functions for converting between UTF-8 and Windows strings. On Windows 95 +(as with the Macintosh and Unix operating systems), +all strings exchanged between Tcl and the operating system are "char" +based. On Windows NT, some strings exchanged between Tcl and the +operating system are "char" oriented while others are in Unicode. By +convention, in Windows a TCHAR is a character in the ANSI code page +on Windows 95 and a Unicode character on Windows NT. +.PP +If you planned to use the same "char" based interfaces on both Windows +95 and Windows NT, you could use \fBTcl_UtfToExternal\fR and +\fBTcl_ExternalToUtf\fR (or their \fBTcl_DString\fR equivalents) with an +encoding of NULL (the current system encoding). On the other hand, +if you planned to use the Unicode interface when running on Windows NT +and the "char" interfaces when running on Windows 95, you would have +to perform the following type of test over and over in your program +(as represented in psuedo-code): +.CS +if (running NT) { + encoding <- Tcl_GetEncoding("unicode"); + nativeBuffer <- Tcl_UtfToExternal(encoding, utfBuffer); + Tcl_FreeEncoding(encoding); +} else { + nativeBuffer <- Tcl_UtfToExternal(NULL, utfBuffer); +.CE +\fBTcl_WinUtfToTChar\fR and \fBTcl_WinTCharToUtf\fR automatically +handle this test and use the proper encoding based on the current +operating system. \fBTcl_WinUtfToTChar\fR returns a pointer to +a TCHAR string, and \fBTcl_WinTCharToUtf\fR expects a TCHAR string +pointer as the \fIsrc\fR string. Otherwise, these functions +behave identically to \fBTcl_UtfToExternalDString\fR and +\fBTcl_ExternalToUtfDString\fR. +.PP +\fBTcl_GetEncodingName\fR is roughly the inverse of \fBTcl_GetEncoding\fR. +Given an \fIencoding\fR, the return value is the \fIname\fR argument that +was used to create the encoding. The string returned by +\fBTcl_GetEncodingName\fR is only guaranteed to persist until the +\fIencoding\fR is deleted. The caller must not modify this string. +.PP +\fBTcl_SetSystemEncoding\fR sets the default encoding that should be used +whenever the user passes a NULL value for the \fIencoding\fR argument to +any of the other encoding functions. If \fIname\fR is NULL, the system +encoding is reset to the default system encoding, \fBbinary\fR. If the +name did not refer to any known or loadable encoding, TCL_ERROR is +returned and an error message is left in \fIinterp\fR. Otherwise, this +procedure increments the reference count of the new system encoding, +decrements the reference count of the old system encoding, and returns +TCL_OK. +.PP +\fBTcl_GetEncodingNames\fR sets the \fIinterp\fR result to a list +consisting of the names of all the encodings that are currently defined +or can be dynamically loaded, searching the encoding path specified by +\fBTcl_SetDefaultEncodingDir\fR. This procedure does not ensure that the +dynamically-loadable encoding files contain valid data, but merely that they +exist. +.PP +\fBTcl_CreateEncoding\fR defines a new encoding and registers the C +procedures that are called back to convert between the encoding and +UTF-8. Encodings created by \fBTcl_CreateEncoding\fR are thereafter +visible in the database used by \fBTcl_GetEncoding\fR. Just as with the +\fBTcl_GetEncoding\fR procedure, the return value is a token that +represents the encoding and can be used in subsequent calls to other +encoding functions. \fBTcl_CreateEncoding\fR returns an encoding with a +reference count of 1. If an encoding with the specified \fIname\fR +already exists, then its entry in the database is replaced with the new +encoding; the token for the old encoding will remain valid and continue +to behave as before, but users of the new token will now call the new +encoding procedures. +.PP +The \fItypePtr\fR argument to \fBTcl_CreateEncoding\fR contains information +about the name of the encoding and the procedures that will be called to +convert between this encoding and UTF-8. It is defined as follows: +.PP +.CS +typedef struct Tcl_EncodingType { + CONST char *\fIencodingName\fR; + Tcl_EncodingConvertProc *\fItoUtfProc\fR; + Tcl_EncodingConvertProc *\fIfromUtfProc\fR; + Tcl_EncodingFreeProc *\fIfreeProc\fR; + ClientData \fIclientData\fR; + int \fInullSize\fR; +} Tcl_EncodingType; +.CE +.PP +The \fIencodingName\fR provides a string name for the encoding, by +which it can be referred in other procedures such as +\fBTcl_GetEncoding\fR. The \fItoUtfProc\fR refers to a callback +procedure to invoke to convert text from this encoding into UTF-8. +The \fIfromUtfProc\fR refers to a callback procedure to invoke to +convert text from UTF-8 into this encoding. The \fIfreeProc\fR refers +to a callback procedure to invoke when this encoding is deleted. The +\fIfreeProc\fR field may be NULL. The \fIclientData\fR contains an +arbitrary one-word value passed to \fItoUtfProc\fR, \fIfromUtfProc\fR, +and \fIfreeProc\fR whenever they are called. Typically, this is a +pointer to a data structure containing encoding-specific information +that can be used by the callback procedures. For instance, two very +similar encodings such as \fBascii\fR and \fBmacRoman\fR may use the +same callback procedure, but use different values of \fIclientData\fR +to control its behavior. The \fInullSize\fR specifies the number of +zero bytes that signify end-of-string in this encoding. It must be +\fB1\fR (for single-byte or multi-byte encodings like ASCII or +Shift-JIS) or \fB2\fR (for double-byte encodings like Unicode). +Constant-sized encodings with 3 or more bytes per character (such as +CNS11643) are not accepted. +.PP +The callback procedures \fItoUtfProc\fR and \fIfromUtfProc\fR should match the +type \fBTcl_EncodingConvertProc\fR: +.PP +.CS +typedef int Tcl_EncodingConvertProc( + ClientData \fIclientData\fR, + CONST char *\fIsrc\fR, + int \fIsrcLen\fR, + int \fIflags\fR, + Tcl_Encoding *\fIstatePtr\fR, + char *\fIdst\fR, + int \fIdstLen\fR, + int *\fIsrcReadPtr\fR, + int *\fIdstWrotePtr\fR, + int *\fIdstCharsPtr\fR); +.CE +.PP +The \fItoUtfProc\fR and \fIfromUtfProc\fR procedures are called by the +\fBTcl_ExternalToUtf\fR or \fBTcl_UtfToExternal\fR family of functions to +perform the actual conversion. The \fIclientData\fR parameter to these +procedures is the same as the \fIclientData\fR field specified to +\fBTcl_CreateEncoding\fR when the encoding was created. The remaining +arguments to the callback procedures are the same as the arguments, +documented at the top, to \fBTcl_ExternalToUtf\fR or +\fBTcl_UtfToExternal\fR, with the following exceptions. If the +\fIsrcLen\fR argument to one of those high-level functions is negative, +the value passed to the callback procedure will be the appropriate +encoding-specific string length of \fIsrc\fR. If any of the \fIsrcReadPtr\fR, +\fIdstWrotePtr\fR, or \fIdstCharsPtr\fR arguments to one of the high-level +functions is NULL, the corresponding value passed to the callback +procedure will be a non-NULL location. +.PP +The callback procedure \fIfreeProc\fR, if non-NULL, should match the type +\fBTcl_EncodingFreeProc\fR: +.CS +typedef void Tcl_EncodingFreeProc( + ClientData \fIclientData\fR); +.CE +.PP +This \fIfreeProc\fR function is called when the encoding is deleted. The +\fIclientData\fR parameter is the same as the \fIclientData\fR field +specified to \fBTcl_CreateEncoding\fR when the encoding was created. +.PP + +\fBTcl_GetDefaultEncodingDir\fR and \fBTcl_SetDefaultEncodingDir\fR +access and set the directory to use when locating the default encoding +files. If this value is not NULL, the \fBTclpInitLibraryPath\fR routine +appends the path to the head of the search path, and uses this path as +the first place to look into when trying to locate the encoding file. + +.SH "ENCODING FILES" +Space would prohibit precompiling into Tcl every possible encoding +algorithm, so many encodings are stored on disk as dynamically-loadable +encoding files. This behavior also allows the user to create additional +encoding files that can be loaded using the same mechanism. These +encoding files contain information about the tables and/or escape +sequences used to map between an external encoding and Unicode. The +external encoding may consist of single-byte, multi-byte, or double-byte +characters. +.PP +Each dynamically-loadable encoding is represented as a text file. The +initial line of the file, beginning with a ``#'' symbol, is a comment +that provides a human-readable description of the file. The next line +identifies the type of encoding file. It can be one of the following +letters: +.IP "[1] \fBS\fR" +A single-byte encoding, where one character is always one byte long in the +encoding. An example is \fBiso8859-1\fR, used by many European languages. +.IP "[2] \fBD\fR" +A double-byte encoding, where one character is always two bytes long in the +encoding. An example is \fBbig5\fR, used for Chinese text. +.IP "[3] \fBM\fR" +A multi-byte encoding, where one character may be either one or two bytes long. +Certain bytes are a lead bytes, indicating that another byte must follow +and that together the two bytes represent one character. Other bytes are not +lead bytes and represent themselves. An example is \fBshiftjis\fR, used by +many Japanese computers. +.IP "[4] \fBE\fR" +An escape-sequence encoding, specifying that certain sequences of bytes +do not represent characters, but commands that describe how following bytes +should be interpreted. +.PP +The rest of the lines in the file depend on the type. +.PP +Cases [1], [2], and [3] are collectively referred to as table-based encoding +files. The lines in a table-based encoding file are in the same +format as this example taken from the \fBshiftjis\fR encoding (this is not +the complete file): +.CS +# Encoding file: shiftjis, multi-byte +M +003F 0 40 +00 +0000000100020003000400050006000700080009000A000B000C000D000E000F +0010001100120013001400150016001700180019001A001B001C001D001E001F +0020002100220023002400250026002700280029002A002B002C002D002E002F +0030003100320033003400350036003700380039003A003B003C003D003E003F +0040004100420043004400450046004700480049004A004B004C004D004E004F +0050005100520053005400550056005700580059005A005B005C005D005E005F +0060006100620063006400650066006700680069006A006B006C006D006E006F +0070007100720073007400750076007700780079007A007B007C007D203E007F +0080000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000FF61FF62FF63FF64FF65FF66FF67FF68FF69FF6AFF6BFF6CFF6DFF6EFF6F +FF70FF71FF72FF73FF74FF75FF76FF77FF78FF79FF7AFF7BFF7CFF7DFF7EFF7F +FF80FF81FF82FF83FF84FF85FF86FF87FF88FF89FF8AFF8BFF8CFF8DFF8EFF8F +FF90FF91FF92FF93FF94FF95FF96FF97FF98FF99FF9AFF9BFF9CFF9DFF9EFF9F +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +81 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +300030013002FF0CFF0E30FBFF1AFF1BFF1FFF01309B309C00B4FF4000A8FF3E +FFE3FF3F30FD30FE309D309E30034EDD30053006300730FC20152010FF0F005C +301C2016FF5C2026202520182019201C201DFF08FF0930143015FF3BFF3DFF5B +FF5D30083009300A300B300C300D300E300F30103011FF0B221200B100D70000 +00F7FF1D2260FF1CFF1E22662267221E22342642264000B0203220332103FFE5 +FF0400A200A3FF05FF03FF06FF0AFF2000A72606260525CB25CF25CE25C725C6 +25A125A025B325B225BD25BC203B301221922190219121933013000000000000 +000000000000000000000000000000002208220B2286228722822283222A2229 +000000000000000000000000000000002227222800AC21D221D4220022030000 +0000000000000000000000000000000000000000222022A52312220222072261 +2252226A226B221A223D221D2235222B222C0000000000000000000000000000 +212B2030266F266D266A2020202100B6000000000000000025EF000000000000 +.CE +.PP +The third line of the file is three numbers. The first number is the +fallback character (in base 16) to use when converting from UTF-8 to this +encoding. The second number is a \fB1\fR if this file represents the +encoding for a symbol font, or \fB0\fR otherwise. The last number (in base +10) is how many pages of data follow. +.PP +Subsequent lines in the example above are pages that describe how to map +from the encoding into 2-byte Unicode. The first line in a page identifies +the page number. Following it are 256 double-byte numbers, arranged as 16 +rows of 16 numbers. Given a character in the encoding, the high byte of +that character is used to select which page, and the low byte of that +character is used as an index to select one of the double-byte numbers in +that page \- the value obtained being the corresponding Unicode character. +By examination of the example above, one can see that the characters 0x7E +and 0x8163 in \fBshiftjis\fR map to 203E and 2026 in Unicode, respectively. +.PP +Following the first page will be all the other pages, each in the same +format as the first: one number identifying the page followed by 256 +double-byte Unicode characters. If a character in the encoding maps to the +Unicode character 0000, it means that the character doesn't actually exist. +If all characters on a page would map to 0000, that page can be omitted. +.PP +Case [4] is the escape-sequence encoding file. The lines in an this type of +file are in the same format as this example taken from the \fBiso2022-jp\fR +encoding: +.CS +.ta 1.5i +# Encoding file: iso2022-jp, escape-driven +E +init {} +final {} +iso8859-1 \\x1b(B +jis0201 \\x1b(J +jis0208 \\x1b$@ +jis0208 \\x1b$B +jis0212 \\x1b$(D +gb2312 \\x1b$A +ksc5601 \\x1b$(C +.CE +.PP +In the file, the first column represents an option and the second column +is the associated value. \fBinit\fR is a string to emit or expect before +the first character is converted, while \fBfinal\fR is a string to emit +or expect after the last character. All other options are names of +table-based encodings; the associated value is the escape-sequence that +marks that encoding. Tcl syntax is used for the values; in the above +example, for instance, ``\fB{}\fR'' represents the empty string and +``\fB\\x1b\fR'' represents character 27. +.PP +When \fBTcl_GetEncoding\fR encounters an encoding \fIname\fR that has not +been loaded, it attempts to load an encoding file called \fIname\fB.enc\fR +from the \fBencoding\fR subdirectory of each directory specified in the +library path \fB$tcl_libPath\fR. If the encoding file exists, but is +malformed, an error message will be left in \fIinterp\fR. +.SH KEYWORDS +utf, encoding, convert + + + diff --git a/mk4/modtcl/tcl8.3.4/doc/Eval.3 b/mk4/modtcl/tcl8.3.4/doc/Eval.3 new file mode 100644 index 0000000..71cfccb --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/Eval.3 @@ -0,0 +1,199 @@ +'\" +'\" Copyright (c) 1989-1993 The Regents of the University of California. +'\" Copyright (c) 1994-1997 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: Eval.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_Eval 3 8.1 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_EvalObjEx, Tcl_EvalFile, Tcl_EvalObjv, Tcl_Eval, Tcl_EvalEx, Tcl_GlobalEval, Tcl_GlobalEvalObj, Tcl_VarEval, Tcl_VarEvalVA \- execute Tcl scripts +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +.VS +int +\fBTcl_EvalObjEx\fR(\fIinterp, objPtr, flags\fR) +.sp +int +\fBTcl_EvalFile\fR(\fIinterp, fileName\fR) +.sp +int +\fBTcl_EvalObjv\fR(\fIinterp, objc, objv, flags\fR) +.sp +int +\fBTcl_Eval\fR(\fIinterp, script\fR) +.sp +int +\fBTcl_EvalEx\fR(\fIinterp, script, numBytes, flags\fR) +.sp +int +\fBTcl_GlobalEval\fR(\fIinterp, script\fR) +.sp +int +\fBTcl_GlobalEvalObj\fR(\fIinterp, objPtr, flags\fR) +.sp +int +\fBTcl_VarEval\fR(\fIinterp, string, string, ... \fB(char *) NULL\fR) +.sp +int +\fBTcl_VarEvalVA\fR(\fIinterp, argList\fR) +.SH ARGUMENTS +.AS Tcl_Interp **termPtr; +.AP Tcl_Interp *interp in +Interpreter in which to execute the script. The interpreter's result is +modified to hold the result or error message from the script. +.AP Tcl_Obj *objPtr in +A Tcl object containing the script to execute. +.AP int flags in +ORed combination of flag bits that specify additional options. +\fBTCL_EVAL_GLOBAL\fR and \fBTCL_EVAL_DIRECT\fR are currently supported. +.AP char *fileName in +Name of a file containing a Tcl script. +.AP int objc in +The number of objects in the array pointed to by \fIobjPtr\fR; +this is also the number of words in the command. +.AP Tcl_Obj **objv in +Points to an array of pointers to objects; each object holds the +value of a single word in the command to execute. +.AP int numBytes in +The number of bytes in \fIscript\fR, not including any +null terminating character. If \-1, then all characters up to the +first null byte are used. +.AP char *script in +Points to first byte of script to execute (NULL terminated and UTF-8). +This script must be in writable memory: temporary modifications are made +to it during parsing. +.AP char *string in +String forming part of a Tcl script. +.AP va_list argList in +An argument list which must have been initialised using +\fBTCL_VARARGS_START\fR, and cleared using \fBva_end\fR. +.BE + +.SH DESCRIPTION +.PP +The procedures described here are invoked to execute Tcl scripts in +various forms. +\fBTcl_EvalObjEx\fR is the core procedure and is used by many of the others. +It executes the commands in the script stored in \fIobjPtr\fR +until either an error occurs or the end of the script is reached. +If this is the first time \fIobjPtr\fR has been executed, +its commands are compiled into bytecode instructions +which are then executed. The +bytecodes are saved in \fIobjPtr\fR so that the compilation step +can be skipped if the object is evaluated again in the future. +.PP +The return value from \fBTcl_EvalObjEx\fR (and all the other procedures +described here) is a Tcl completion code with +one of the values \fBTCL_OK\fR, \fBTCL_ERROR\fR, \fBTCL_RETURN\fR, +\fBTCL_BREAK\fR, or \fBTCL_CONTINUE\fR. +In addition, a result value or error message is left in \fIinterp\fR's +result; it can be retrieved using \fBTcl_GetObjResult\fR. +.PP +\fBTcl_EvalFile\fR reads the file given by \fIfileName\fR and evaluates +its contents as a Tcl script. It returns the same information as +\fBTcl_EvalObjEx\fR. +If the file couldn't be read then a Tcl error is returned to describe +why the file couldn't be read. +.PP +\fBTcl_EvalObjv\fR executes a single pre-parsed command instead of a +script. The \fIobjc\fR and \fIobjv\fR arguments contain the values +of the words for the Tcl command, one word in each object in +\fIobjv\fR. \fBTcl_EvalObjv\fR evaluates the command and returns +a completion code and result just like \fBTcl_EvalObjEx\fR. +.PP +\fBTcl_Eval\fR is similar to \fBTcl_EvalObjEx\fR except that the script to +be executed is supplied as a string instead of an object and no compilation +occurs. The string should be a proper UTF-8 string as converted by +\fBTcl_ExternalToUtfDString\fR or \fBTcl_ExternalToUtf\fR when it is known +to possibly contain upper ascii characters who's possible combinations +might be a UTF-8 special code. The string is parsed and executed directly +(using \fBTcl_EvalObjv\fR) instead of compiling it and executing the +bytecodes. In situations where it is known that the script will never be +executed again, \fBTcl_Eval\fR may be faster than \fBTcl_EvalObjEx\fR. +\fBTcl_Eval\fR returns a completion code and result just like +\fBTcl_EvalObjEx\fR. Note: for backward compatibility with versions before +Tcl 8.0, \fBTcl_Eval\fR copies the object result in \fIinterp\fR to +\fIinterp->result\fR (use is deprecated) where it can be accessed directly. +This makes \fBTcl_Eval\fR somewhat slower than \fBTcl_EvalEx\fR, which +doesn't do the copy. +.PP +\fBTcl_EvalEx\fR is an extended version of \fBTcl_Eval\fR that takes +additional arguments \fInumBytes\fR and \fIflags\fR. For the +efficiency reason given above, \fBTcl_EvalEx\fR is generally preferred +over \fBTcl_Eval\fR. +.PP +\fBTcl_GlobalEval\fR and \fBTcl_GlobalEvalObj\fR are older procedures +that are now deprecated. They are similar to \fBTcl_EvalEx\fR and +\fBTcl_EvalObjEx\fR except that the script is evaluated in the global +namespace and its variable context consists of global variables only +(it ignores any Tcl procedures that are active). These functions are +equivalent to using the \fBTCL_EVAL_GLOBAL\fR flag (see below). +.PP +\fBTcl_VarEval\fR takes any number of string arguments +of any length, concatenates them into a single string, +then calls \fBTcl_Eval\fR to execute that string as a Tcl command. +It returns the result of the command and also modifies +\fIinterp->result\fR in the same way as \fBTcl_Eval\fR. +The last argument to \fBTcl_VarEval\fR must be NULL to indicate the end +of arguments. \fBTcl_VarEval\fR is now deprecated. +.PP +\fBTcl_VarEvalVA\fR is the same as \fBTcl_VarEval\fR except that +instead of taking a variable number of arguments it takes an argument +list. Like \fBTcl_VarEval\fR, \fBTcl_VarEvalVA\fR is deprecated. + +.SH "FLAG BITS" +Any ORed combination of the following values may be used for the +\fIflags\fR argument to procedures such as \fBTcl_EvalObjEx\fR: +.TP 23 +\fBTCL_EVAL_DIRECT\fR +This flag is only used by \fBTcl_EvalObjEx\fR; it is ignored by +other procedures. If this flag bit is set, the script is not +compiled to bytecodes; instead it is executed directly +as is done by \fBTcl_EvalEx\fR. The +\fBTCL_EVAL_DIRECT\fR flag is useful in situations where the +contents of an object are going to change immediately, so the +bytecodes won't be reused in a future execution. In this case, +it's faster to execute the script directly. +.TP 23 +\fBTCL_EVAL_GLOBAL\fR +If this flag is set, the script is processed at global level. This +means that it is evaluated in the global namespace and its variable +context consists of global variables only (it ignores any Tcl +procedures at are active). + +.SH "MISCELLANEOUS DETAILS" +.PP +During the processing of a Tcl command it is legal to make nested +calls to evaluate other commands (this is how procedures and +some control structures are implemented). +If a code other than \fBTCL_OK\fR is returned +from a nested \fBTcl_EvalObjEx\fR invocation, +then the caller should normally return immediately, +passing that same return code back to its caller, +and so on until the top-level application is reached. +A few commands, like \fBfor\fR, will check for certain +return codes, like \fBTCL_BREAK\fR and \fBTCL_CONTINUE\fR, and process them +specially without returning. +.PP +\fBTcl_EvalObjEx\fR keeps track of how many nested \fBTcl_EvalObjEx\fR +invocations are in progress for \fIinterp\fR. +If a code of \fBTCL_RETURN\fR, \fBTCL_BREAK\fR, or \fBTCL_CONTINUE\fR is +about to be returned from the topmost \fBTcl_EvalObjEx\fR +invocation for \fIinterp\fR, +it converts the return code to \fBTCL_ERROR\fR +and sets \fIinterp\fR's result to an error message indicating that +the \fBreturn\fR, \fBbreak\fR, or \fBcontinue\fR command was +invoked in an inappropriate place. +This means that top-level applications should never see a return code +from \fBTcl_EvalObjEx\fR other then \fBTCL_OK\fR or \fBTCL_ERROR\fR. +.VE + +.SH KEYWORDS +execute, file, global, object, result, script diff --git a/mk4/modtcl/tcl8.3.4/doc/Exit.3 b/mk4/modtcl/tcl8.3.4/doc/Exit.3 new file mode 100644 index 0000000..b0737a5 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/Exit.3 @@ -0,0 +1,131 @@ +'\" +'\" Copyright (c) 1995-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: Exit.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_Exit 3 8.1 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_Exit, Tcl_Finalize, Tcl_CreateExitHandler, Tcl_DeleteExitHandler, Tcl_ExitThread, Tcl_FinalizeThread, Tcl_CreateThreadExitHandler, Tcl_DeleteThreadExitHandler \- end the application or thread (and invoke exit handlers) +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +\fBTcl_Exit\fR(\fIstatus\fR) +.sp +\fBTcl_Finalize\fR() +.sp +\fBTcl_CreateExitHandler\fR(\fIproc, clientData\fR) +.sp +\fBTcl_DeleteExitHandler\fR(\fIproc, clientData\fR) +.sp +\fBTcl_ExitThread\fR(\fIstatus\fR) +.sp +\fBTcl_FinalizeThread\fR() +.sp +\fBTcl_CreateThreadExitHandler\fR(\fIproc, clientData\fR) +.sp +\fBTcl_DeleteThreadExitHandler\fR(\fIproc, clientData\fR) +.SH ARGUMENTS +.AS Tcl_ExitProc clientData +.AP int status in +Provides information about why the application or thread exited. +Exact meaning may +be platform-specific. 0 usually means a normal exit, any nonzero value +usually means that an error occurred. +.AP Tcl_ExitProc *proc in +Procedure to invoke before exiting application. +.AP ClientData clientData in +Arbitrary one-word value to pass to \fIproc\fR. +.BE + +.SH DESCRIPTION +.PP +The procedures described here provide a graceful mechanism to end the +execution of a \fBTcl\fR application. Exit handlers are invoked to cleanup the +application's state before ending the execution of \fBTcl\fR code. +.PP +Invoke \fBTcl_Exit\fR to end a \fBTcl\fR application and to exit from this +process. This procedure is invoked by the \fBexit\fR command, and can be +invoked anyplace else to terminate the application. +No-one should ever invoke the \fBexit\fR system procedure directly; always +invoke \fBTcl_Exit\fR instead, so that it can invoke exit handlers. +Note that if other code invokes \fBexit\fR system procedure directly, or +otherwise causes the application to terminate without calling +\fBTcl_Exit\fR, the exit handlers will not be run. +\fBTcl_Exit\fR internally invokes the \fBexit\fR system call, thus it never +returns control to its caller. +.PP +\fBTcl_Finalize\fR is similar to \fBTcl_Exit\fR except that it does not +exit from the current process. +It is useful for cleaning up when a process is finished using \fBTcl\fR but +wishes to continue executing, and when \fBTcl\fR is used in a dynamically +loaded extension that is about to be unloaded. +On some systems \fBTcl\fR is automatically notified when it is being +unloaded, and it calls \fBTcl_Finalize\fR internally; on these systems it +not necessary for the caller to explicitly call \fBTcl_Finalize\fR. +However, to ensure portability, your code should always invoke +\fBTcl_Finalize\fR when \fBTcl\fR is being unloaded, to ensure that the +code will work on all platforms. \fBTcl_Finalize\fR can be safely called +more than once. +.PP +.VS +\fBTcl_ExitThread\fR is used to terminate the current thread and invoke +per-thread exit handlers. This finalization is done by +\fBTcl_FinalizeThread\fR, which you can call if you just want to clean +up per-thread state and invoke the thread exit handlers. +\fBTcl_Finalize\fR calls \fBTcl_FinalizeThread\fR for the current +thread automatically. +.VE +.PP +\fBTcl_CreateExitHandler\fR arranges for \fIproc\fR to be invoked +by \fBTcl_Finalize\fR and \fBTcl_Exit\fR. +\fBTcl_CreateThreadExitHandler\fR arranges for \fIproc\fR to be invoked +by \fBTcl_FinalizeThread\fR and \fBTcl_ExitThread\fR. +This provides a hook for cleanup operations such as flushing buffers +and freeing global memory. +\fIProc\fR should match the type \fBTcl_ExitProc\fR: +.CS +typedef void Tcl_ExitProc(ClientData \fIclientData\fR); +.CE +The \fIclientData\fR parameter to \fIproc\fR is a +copy of the \fIclientData\fR argument given to +\fBTcl_CreateExitHandler\fR or \fBTcl_CreateThreadExitHandler\fR when +the callback +was created. Typically, \fIclientData\fR points to a data +structure containing application-specific information about +what to do in \fIproc\fR. +.PP +\fBTcl_DeleteExitHandler\fR and \fBTcl_DeleteThreadExitHandler\fR may be +called to delete a +previously-created exit handler. It removes the handler +indicated by \fIproc\fR and \fIclientData\fR so that no call +to \fIproc\fR will be made. If no such handler exists then +\fBTcl_DeleteExitHandler\fR or \fBTcl_DeleteThreadExitHandler\fR does nothing. +.PP +.VS +.PP +\fBTcl_Finalize\fR and \fBTcl_Exit\fR execute all registered exit handlers, +in reverse order from the order in which they were registered. +This matches the natural order in which extensions are loaded and unloaded; +if extension \fBA\fR loads extension \fBB\fR, it usually +unloads \fBB\fR before it itself is unloaded. +If extension \fBA\fR registers its exit handlers before loading extension +\fBB\fR, this ensures that any exit handlers for \fBB\fR will be executed +before the exit handlers for \fBA\fR. +.VE +.VS +.PP +\fBTcl_Finalize\fR and \fBTcl_Exit\fR call \fBTcl_FinalizeThread\fR +and the thread exit handlers \fIafter\fR +the process-wide exit handlers. This is because thread finalization shuts +down the I/O channel system, so any attempt at I/O by the global exit +handlers will vanish into the bitbucket. +.VE + +.SH KEYWORDS +callback, cleanup, dynamic loading, end application, exit, unloading, thread diff --git a/mk4/modtcl/tcl8.3.4/doc/ExprLong.3 b/mk4/modtcl/tcl8.3.4/doc/ExprLong.3 new file mode 100644 index 0000000..f60346c --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/ExprLong.3 @@ -0,0 +1,112 @@ +'\" +'\" Copyright (c) 1989-1993 The Regents of the University of California. +'\" Copyright (c) 1994-1997 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: ExprLong.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_ExprLong 3 7.0 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_ExprLong, Tcl_ExprDouble, Tcl_ExprBoolean, Tcl_ExprString \- evaluate an expression +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +int +\fBTcl_ExprLong\fR(\fIinterp, string, longPtr\fR) +.sp +int +\fBTcl_ExprDouble\fR(\fIinterp, string, doublePtr\fR) +.sp +int +\fBTcl_ExprBoolean\fR(\fIinterp, string, booleanPtr\fR) +.sp +int +\fBTcl_ExprString\fR(\fIinterp, string\fR) +.SH ARGUMENTS +.AS Tcl_Interp *booleanPtr +.AP Tcl_Interp *interp in +Interpreter in whose context to evaluate \fIstring\fR or \fIobjPtr\fR. +.AP char *string in +Expression to be evaluated. Must be in writable memory (the expression +parser makes temporary modifications to the string during parsing, which +it undoes before returning). +.AP long *longPtr out +Pointer to location in which to store the integer value of the +expression. +.AP int *doublePtr out +Pointer to location in which to store the floating-point value of the +expression. +.AP int *booleanPtr out +Pointer to location in which to store the 0/1 boolean value of the +expression. +.BE + +.SH DESCRIPTION +.PP +These four procedures all evaluate the expression +given by the \fIstring\fR argument +and return the result in one of four different forms. +The expression can have any of the forms accepted by the \fBexpr\fR command. +Note that these procedures have been largely replaced by the +object-based procedures \fBTcl_ExprLongObj\fR, \fBTcl_ExprDoubleObj\fR, +\fBTcl_ExprBooleanObj\fR, and \fBTcl_ExprStringObj\fR. +Those object-based procedures evaluate an expression held in a Tcl object +instead of a string. +The object argument can retain an internal representation +that is more efficient to execute. +.PP +The \fIinterp\fR argument refers to an interpreter used to +evaluate the expression (e.g. for variables and nested Tcl +commands) and to return error information. +.PP +For all of these procedures the return value is a standard +Tcl result: \fBTCL_OK\fR means the expression was successfully +evaluated, and \fBTCL_ERROR\fR means that an error occurred while +evaluating the expression. +If \fBTCL_ERROR\fR is returned then +the interpreter's result will hold a message describing the error. +If an error occurs while executing a Tcl command embedded in +the expression then that error will be returned. +.PP +If the expression is successfully evaluated, then its value is +returned in one of four forms, depending on which procedure +is invoked. +\fBTcl_ExprLong\fR stores an integer value at \fI*longPtr\fR. +If the expression's actual value is a floating-point number, +then it is truncated to an integer. +If the expression's actual value is a non-numeric string then +an error is returned. +.PP +\fBTcl_ExprDouble\fR stores a floating-point value at \fI*doublePtr\fR. +If the expression's actual value is an integer, it is converted to +floating-point. +If the expression's actual value is a non-numeric string then +an error is returned. +.PP +\fBTcl_ExprBoolean\fR stores a 0/1 integer value at \fI*booleanPtr\fR. +If the expression's actual value is an integer or floating-point +number, then they store 0 at \fI*booleanPtr\fR if +the value was zero and 1 otherwise. +If the expression's actual value is a non-numeric string then +it must be one of the values accepted by \fBTcl_GetBoolean\fR +such as ``yes'' or ``no'', or else an error occurs. +.PP +\fBTcl_ExprString\fR returns the value of the expression as a +string stored in the interpreter's result. +If the expression's actual value is an integer +then \fBTcl_ExprString\fR converts it to a string using \fBsprintf\fR +with a ``%d'' converter. +If the expression's actual value is a floating-point +number, then \fBTcl_ExprString\fR calls \fBTcl_PrintDouble\fR +to convert it to a string. + +.SH "SEE ALSO" +Tcl_ExprLongObj, Tcl_ExprDoubleObj, Tcl_ExprBooleanObj, Tcl_ExprObj + +.SH KEYWORDS +boolean, double, evaluate, expression, integer, object, string diff --git a/mk4/modtcl/tcl8.3.4/doc/ExprLongObj.3 b/mk4/modtcl/tcl8.3.4/doc/ExprLongObj.3 new file mode 100644 index 0000000..95dedff --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/ExprLongObj.3 @@ -0,0 +1,104 @@ +'\" +'\" Copyright (c) 1996-1997 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: ExprLongObj.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_ExprLongObj 3 8.0 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_ExprLongObj, Tcl_ExprDoubleObj, Tcl_ExprBooleanObj, Tcl_ExprObj \- evaluate an expression +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +int +\fBTcl_ExprLongObj\fR(\fIinterp, objPtr, longPtr\fR) +.sp +int +\fBTcl_ExprDoubleObj\fR(\fIinterp, objPtr, doublePtr\fR) +.sp +int +\fBTcl_ExprBooleanObj\fR(\fIinterp, objPtr, booleanPtr\fR) +.sp +int +\fBTcl_ExprObj\fR(\fIinterp, objPtr, resultPtrPtr\fR) +.SH ARGUMENTS +.AS Tcl_Interp *resultPtrPtr out +.AP Tcl_Interp *interp in +Interpreter in whose context to evaluate \fIstring\fR or \fIobjPtr\fR. +.AP Tcl_Obj *objPtr in +Pointer to an object containing the expression to evaluate. +.AP long *longPtr out +Pointer to location in which to store the integer value of the +expression. +.AP int *doublePtr out +Pointer to location in which to store the floating-point value of the +expression. +.AP int *booleanPtr out +Pointer to location in which to store the 0/1 boolean value of the +expression. +.AP Tcl_Obj *resultPtrPtr out +Pointer to location in which to store a pointer to the object +that is the result of the expression. +.BE + +.SH DESCRIPTION +.PP +These four procedures all evaluate an expression, returning +the result in one of four different forms. +The expression is given by the \fIobjPtr\fR argument, and it +can have any of the forms accepted by the \fBexpr\fR command. +.PP +The \fIinterp\fR argument refers to an interpreter used to +evaluate the expression (e.g. for variables and nested Tcl +commands) and to return error information. +.PP +For all of these procedures the return value is a standard +Tcl result: \fBTCL_OK\fR means the expression was successfully +evaluated, and \fBTCL_ERROR\fR means that an error occurred while +evaluating the expression. +If \fBTCL_ERROR\fR is returned, +then a message describing the error +can be retrieved using \fBTcl_GetObjResult\fR. +If an error occurs while executing a Tcl command embedded in +the expression then that error will be returned. +.PP +If the expression is successfully evaluated, then its value is +returned in one of four forms, depending on which procedure +is invoked. +\fBTcl_ExprLongObj\fR stores an integer value at \fI*longPtr\fR. +If the expression's actual value is a floating-point number, +then it is truncated to an integer. +If the expression's actual value is a non-numeric string then +an error is returned. +.PP +\fBTcl_ExprDoubleObj\fR stores a floating-point value at \fI*doublePtr\fR. +If the expression's actual value is an integer, it is converted to +floating-point. +If the expression's actual value is a non-numeric string then +an error is returned. +.PP +\fBTcl_ExprBooleanObj\fR stores a 0/1 integer value at \fI*booleanPtr\fR. +If the expression's actual value is an integer or floating-point +number, then they store 0 at \fI*booleanPtr\fR if +the value was zero and 1 otherwise. +If the expression's actual value is a non-numeric string then +it must be one of the values accepted by \fBTcl_GetBoolean\fR +such as ``yes'' or ``no'', or else an error occurs. +.PP +If \fBTcl_ExprObj\fR successfully evaluates the expression, +it stores a pointer to the Tcl object +containing the expression's value at \fI*resultPtrPtr\fR. +In this case, the caller is responsible for calling +\fBTcl_DecrRefCount\fR to decrement the object's reference count +when it is finished with the object. + +.SH "SEE ALSO" +Tcl_ExprLong, Tcl_ExprDouble, Tcl_ExprBoolean, Tcl_ExprString, Tcl_GetObjResult + +.SH KEYWORDS +boolean, double, evaluate, expression, integer, object, string diff --git a/mk4/modtcl/tcl8.3.4/doc/FindExec.3 b/mk4/modtcl/tcl8.3.4/doc/FindExec.3 new file mode 100644 index 0000000..3df5f3c --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/FindExec.3 @@ -0,0 +1,58 @@ +'\" +'\" Copyright (c) 1995-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: FindExec.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_FindExecutable 3 8.1 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_FindExecutable, Tcl_GetNameOfExecutable \- identify or return the name of the binary file containing the application +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +void +\fBTcl_FindExecutable\fR(\fIargv0\fR) +.sp +CONST char * +\fBTcl_GetNameOfExecutable\fR() +.SH ARGUMENTS +.AS char *argv0 in +.AP char *argv0 in +The first command-line argument to the program, which gives the +application's name. +.BE + +.SH DESCRIPTION +.PP +The \fBTcl_FindExecutable\fR procedure computes the full path name of +the executable file from which the application was invoked and saves +it for Tcl's internal use. +The executable's path name is needed for several purposes in +Tcl. For example, it is needed on some platforms in the +implementation of the \fBload\fR command. +It is also returned by the \fBinfo nameofexecutable\fR command. +.PP +On UNIX platforms this procedure is typically invoked as the very +first thing in the application's main program; it must be passed +\fIargv[0]\fR as its argument. It is important not to change the +working directory before the invocation. +\fBTcl_FindExecutable\fR uses \fIargv0\fR +along with the \fBPATH\fR environment variable to find the +application's executable, if possible. If it fails to find +the binary, then future calls to \fBinfo nameofexecutable\fR +will return an empty string. +.PP +\fBTcl_GetNameOfExecutable\fR simply returns a pointer to the +internal full path name of the executable file as computed by +\fBTcl_FindExecutable\fR. This procedure call is the C API +equivalent to the \fBinfo nameofexecutable\fR command. NULL +is returned if the internal full path name has not been +computed or unknown. + +.SH KEYWORDS +binary, executable file diff --git a/mk4/modtcl/tcl8.3.4/doc/GetCwd.3 b/mk4/modtcl/tcl8.3.4/doc/GetCwd.3 new file mode 100644 index 0000000..723aef5 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/GetCwd.3 @@ -0,0 +1,54 @@ +'\" +'\" Copyright (c) 1998-1999 Scriptics Corportation +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: GetCwd.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_GetCwd 3 8.1 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_GetCwd, Tcl_Chdir \- manipulate the current working directory +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +char * +\fBTcl_GetCwd\fR(\fIinterp\fR, \fIbufferPtr\fR) +.sp +int +\fBTcl_Chdir\fR(\fIpath\fR) +.SH ARGUMENTS +.AS Tcl_DString *bufferPtr +.AP Tcl_Interp *interp in +Interpreter in which to report an error, if any. +.AP Tcl_DString *bufferPtr in/out +This dynamic string is used to store the current working directory. +At the time of the call it should be uninitialized or free. The +caller must eventually call \fBTcl_DStringFree\fR to free up +anything stored here. +.AP char *path in +File path in UTF\-8 format. +.BE + +.SH DESCRIPTION +.PP +These procedures may be used to manipulate the current working +directory for the application. They provide C\-level access to +the same functionality as the Tcl \fBpwd\fR command. +.PP +\fBTcl_GetCwd\fR returns a pointer to a string specifying the current +directory, or NULL if the current directory could not be determined. +If NULL is returned, an error message is left in the interp's result. +Storage for the result string is allocated in bufferPtr; the caller +must call \fBTcl_DStringFree()\fR when the result is no longer needed. +The format of the path is UTF\-8. +.PP +\fBTcl_Chdir\fR changes the applications current working directory to +the value specified in \fIpath\fR. The format of the passed in string +must be UTF\-8. The function returns -1 on error or 0 on success. + +.SH KEYWORDS +pwd diff --git a/mk4/modtcl/tcl8.3.4/doc/GetHostName.3 b/mk4/modtcl/tcl8.3.4/doc/GetHostName.3 new file mode 100644 index 0000000..058a14b --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/GetHostName.3 @@ -0,0 +1,28 @@ +'\" +'\" Copyright (c) 1998-2000 by Scriptics Corporation. +'\" All rights reserved. +'\" +'\" RCS: @(#) $Id: GetHostName.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_GetHostName 3 8.3 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_GetHostName \- get the name of the local host +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +char * +\fBTcl_GetHostName\fR() + +.SH DESCRIPTION +.PP +\fBTcl_GetHostName\fR is a utility procedure used by some of the +Tcl commands. It returns a pointer to a string containing the name +for the current machine, or an empty string if the name cannot be +determined. The string is statically allocated, and the caller must +not modify of free it. +.PP +.SH KEYWORDS +hostname diff --git a/mk4/modtcl/tcl8.3.4/doc/GetIndex.3 b/mk4/modtcl/tcl8.3.4/doc/GetIndex.3 new file mode 100644 index 0000000..b77cb57 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/GetIndex.3 @@ -0,0 +1,102 @@ +'\" +'\" Copyright (c) 1997 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: GetIndex.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_GetIndexFromObj 3 8.1 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_GetIndexFromObj, Tcl_GetIndexFromObjStruct \- lookup string in table of keywords +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +int +\fBTcl_GetIndexFromObj\fR(\fIinterp, objPtr, tablePtr, msg, flags, +indexPtr\fR) +.VS +.sp +int +\fBTcl_GetIndexFromObjStruct\fR(\fIinterp, objPtr, tablePtr, offset, +msg, flags, indexPtr\fR) +.VE +.SH ARGUMENTS +.AS Tcl_Interp **tablePtr +.AP Tcl_Interp *interp in +Interpreter to use for error reporting; if NULL, then no message is +provided on errors. +.AP Tcl_Obj *objPtr in/out +The string value of this object is used to search through \fItablePtr\fR. +The internal representation is modified to hold the index of the matching +table entry. +.AP char **tablePtr in +An array of null-terminated strings. The end of the array is marked +by a NULL string pointer. +.VS +.AP int offset in +The offset to add to tablePtr to get to the next string in the +list. The end of the array is marked by a NULL string pointer. +.VE +.AP char *msg in +Null-terminated string describing what is being looked up, such as +\fBoption\fR. This string is included in error messages. +.AP int flags in +OR-ed combination of bits providing additional information for +operation. The only bit that is currently defined is \fBTCL_EXACT\fR. +.AP int *indexPtr out +The index of the string in \fItablePtr\fR that matches the value of +\fIobjPtr\fR is returned here. +.BE + +.SH DESCRIPTION +.PP +This procedure provides an efficient way for looking up keywords, +switch names, option names, and similar things where the value of +an object must be one of a predefined set of values. +\fIObjPtr\fR is compared against each of +the strings in \fItablePtr\fR to find a match. A match occurs if +\fIobjPtr\fR's string value is identical to one of the strings in +\fItablePtr\fR, or if it is a unique abbreviation +for exactly one of the strings in \fItablePtr\fR and the +\fBTCL_EXACT\fR flag was not specified; in either case +the index of the matching entry is stored at \fI*indexPtr\fR +and TCL_OK is returned. +.PP +If there is no matching entry, +TCL_ERROR is returned and an error message is left in \fIinterp\fR's +result if \fIinterp\fR isn't NULL. \fIMsg\fR is included in the +error message to indicate what was being looked up. For example, +if \fImsg\fR is \fBoption\fR the error message will have a form like +\fBbad option "firt": must be first, second, or third\fR. +.PP +If \fBTcl_GetIndexFromObj\fR completes successfully it modifies the +internal representation of \fIobjPtr\fR to hold the address of +the table and the index of the matching entry. If \fBTcl_GetIndexFromObj\fR +is invoked again with the same \fIobjPtr\fR and \fItablePtr\fR +arguments (e.g. during a reinvocation of a Tcl command), it returns +the matching index immediately without having to redo the lookup +operation. Note: \fBTcl_GetIndexFromObj\fR assumes that the entries +in \fItablePtr\fR are static: they must not change between +invocations. If the value of \fIobjPtr\fR is the empty string, +\fBTcl_GetIndexFromObj\fR will treat it as a non-matching value +and return TCL_ERROR. +.VS +.PP +\fBTcl_GetIndexFromObjStruct\fR works just like +\fBTcl_GetIndexFromObj\fR, except that instead of treating +\fItablePtr\fR as an array of string pointers, it treats it as the +first in a series of string ptrs that are spaced apart by \fIoffset\fR +bytes. This is particularly useful when processing things like +\fBTk_ConfigurationSpec\fR, whose string keys are in the same place in +each of several array elements. +.VE + +.SH "SEE ALSO" +Tcl_WrongNumArgs + +.SH KEYWORDS +index, object, table lookup diff --git a/mk4/modtcl/tcl8.3.4/doc/GetInt.3 b/mk4/modtcl/tcl8.3.4/doc/GetInt.3 new file mode 100644 index 0000000..47eeae6 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/GetInt.3 @@ -0,0 +1,81 @@ +'\" +'\" Copyright (c) 1989-1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: GetInt.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_GetInt 3 "" Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_GetInt, Tcl_GetDouble, Tcl_GetBoolean \- convert from string to integer, double, or boolean +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +int +\fBTcl_GetInt\fR(\fIinterp, string, intPtr\fR) +.sp +int +\fBTcl_GetDouble\fR(\fIinterp, string, doublePtr\fR) +.sp +int +\fBTcl_GetBoolean\fR(\fIinterp, string, boolPtr\fR) +.SH ARGUMENTS +.AS Tcl_Interp *doublePtr +.AP Tcl_Interp *interp in +Interpreter to use for error reporting. +.AP char *string in +Textual value to be converted. +.AP int *intPtr out +Points to place to store integer value converted from \fIstring\fR. +.AP double *doublePtr out +Points to place to store double-precision floating-point +value converted from \fIstring\fR. +.AP int *boolPtr out +Points to place to store boolean value (0 or 1) converted from \fIstring\fR. +.BE + +.SH DESCRIPTION +.PP +These procedures convert from strings to integers or double-precision +floating-point values or booleans (represented as 0- or 1-valued +integers). Each of the procedures takes a \fIstring\fR argument, +converts it to an internal form of a particular type, and stores +the converted value at the location indicated by the procedure's +third argument. If all goes well, each of the procedures returns +TCL_OK. If \fIstring\fR doesn't have the proper syntax for the +desired type then TCL_ERROR is returned, an error message is left +in the interpreter's result, and nothing is stored at *\fIintPtr\fR +or *\fIdoublePtr\fR or *\fIboolPtr\fR. +.PP +\fBTcl_GetInt\fR expects \fIstring\fR to consist of a collection +of integer digits, optionally signed and optionally preceded by +white space. If the first two characters of \fIstring\fR are ``0x'' +then \fIstring\fR is expected to be in hexadecimal form; otherwise, +if the first character of \fIstring\fR is ``0'' then \fIstring\fR +is expected to be in octal form; otherwise, \fIstring\fR is +expected to be in decimal form. +.PP +\fBTcl_GetDouble\fR expects \fIstring\fR to consist of a floating-point +number, which is: white space; a sign; a sequence of digits; a +decimal point; a sequence of digits; the letter ``e''; and a +signed decimal exponent. Any of the fields may be omitted, except that +the digits either before or after the decimal point must be present +and if the ``e'' is present then it must be followed by the +exponent number. +.PP +\fBTcl_GetBoolean\fR expects \fIstring\fR to specify a boolean +value. If \fIstring\fR is any of \fB0\fR, \fBfalse\fR, +\fBno\fR, or \fBoff\fR, then \fBTcl_GetBoolean\fR stores a zero +value at \fI*boolPtr\fR. +If \fIstring\fR is any of \fB1\fR, \fBtrue\fR, \fByes\fR, or \fBon\fR, +then 1 is stored at \fI*boolPtr\fR. +Any of these values may be abbreviated, and upper-case spellings +are also acceptable. + +.SH KEYWORDS +boolean, conversion, double, floating-point, integer diff --git a/mk4/modtcl/tcl8.3.4/doc/GetOpnFl.3 b/mk4/modtcl/tcl8.3.4/doc/GetOpnFl.3 new file mode 100644 index 0000000..94678fb --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/GetOpnFl.3 @@ -0,0 +1,61 @@ +'\" +'\" Copyright (c) 1996-1997 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: GetOpnFl.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +.so man.macros +.TH Tcl_GetOpenFile 3 8.0 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_GetOpenFile \- Get a standard IO File * handle from a channel. (Unix only) +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +int +\fBTcl_GetOpenFile\fR(\fIinterp, string, write, checkUsage, filePtr\fR) +.sp +.SH ARGUMENTS +.AS Tcl_Interp checkUsage +.AP Tcl_Interp *interp in +Tcl interpreter from which file handle is to be obtained. +.AP char *string in +String identifying channel, such as \fBstdin\fR or \fBfile4\fR. +.AP int write in +Non-zero means the file will be used for writing, zero means it will +be used for reading. +.AP int checkUsage in +If non-zero, then an error will be generated if the file wasn't opened +for the access indicated by \fIwrite\fR. +.AP ClientData *filePtr out +Points to word in which to store pointer to FILE structure for +the file given by \fIstring\fR. +.BE + +.SH DESCRIPTION +.PP +\fBTcl_GetOpenFile\fR takes as argument a file identifier of the form +returned by the \fBopen\fR command and +returns at \fI*filePtr\fR a pointer to the FILE structure for +the file. +The \fIwrite\fR argument indicates whether the FILE pointer will +be used for reading or writing. +In some cases, such as a channel that connects to a pipeline of +subprocesses, different FILE pointers will be returned for reading +and writing. +\fBTcl_GetOpenFile\fR normally returns TCL_OK. +If an error occurs in \fBTcl_GetOpenFile\fR (e.g. \fIstring\fR didn't +make any sense or \fIcheckUsage\fR was set and the file wasn't opened +for the access specified by \fIwrite\fR) then TCL_ERROR is returned +and the interpreter's result will contain an error message. +In the current implementation \fIcheckUsage\fR is ignored and consistency +checks are always performed. +.VS +.PP +Note that this interface is only supported on the Unix platform. +.VE + +.SH KEYWORDS +channel, file handle, permissions, pipeline, read, write diff --git a/mk4/modtcl/tcl8.3.4/doc/GetStdChan.3 b/mk4/modtcl/tcl8.3.4/doc/GetStdChan.3 new file mode 100644 index 0000000..4e30730 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/GetStdChan.3 @@ -0,0 +1,73 @@ +'\" +'\" Copyright (c) 1996 by Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: GetStdChan.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_GetStdChannel 3 7.5 Tcl "Tcl Library Procedures" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +Tcl_GetStdChannel, Tcl_SetStdChannel \- procedures for retrieving and replacing the standard channels +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +Tcl_Channel +\fBTcl_GetStdChannel\fR(\fItype\fR) +.sp +\fBTcl_SetStdChannel\fR(\fIchannel, type\fR) +.sp +.SH ARGUMENTS +.AS Tcl_Channel channel in +.AP int type in +The identifier for the standard channel to retrieve or modify. Must be one of +\fBTCL_STDIN\fR, \fBTCL_STDOUT\fR, or \fBTCL_STDERR\fR. +.AP Tcl_Channel channel in +The channel to use as the new value for the specified standard channel. +.BE + +.SH DESCRIPTION +.PP +Tcl defines three special channels that are used by various I/O related +commands if no other channels are specified. The standard input channel +has a channel name of \fBstdin\fR and is used by \fBread\fR and \fBgets\fR. +The standard output channel is named \fBstdout\fR and is used by +\fBputs\fR. The standard error channel is named \fBstderr\fR and is used for +reporting errors. In addition, the standard channels are inherited by any +child processes created using \fBexec\fR or \fBopen\fR in the absence of any +other redirections. +.PP +The standard channels are actually aliases for other normal channels. The +current channel associated with a standard channel can be retrieved by calling +\fBTcl_GetStdChannel\fR with one of +\fBTCL_STDIN\fR, \fBTCL_STDOUT\fR, or \fBTCL_STDERR\fR as the \fItype\fR. The +return value will be a valid channel, or NULL. +.PP +A new channel can be set for the standard channel specified by \fItype\fR +by calling \fBTcl_SetStdChannel\fR with a new channel or NULL in the +\fIchannel\fR argument. If the specified channel is closed by a later call to +\fBTcl_Close\fR, then the corresponding standard channel will automatically be +set to NULL. +.PP +If \fBTcl_GetStdChannel\fR is called before \fBTcl_SetStdChannel\fR, Tcl will +construct a new channel to wrap the appropriate platform-specific standard +file handle. If \fBTcl_SetStdChannel\fR is called before +\fBTcl_GetStdChannel\fR, then the default channel will not be created. +.PP +If one of the standard channels is set to NULL, either by calling +\fBTcl_SetStdChannel\fR with a null \fIchannel\fR argument, or by calling +\fBTcl_Close\fR on the channel, then the next call to \fBTcl_CreateChannel\fR +will automatically set the standard channel with the newly created channel. If +more than one standard channel is NULL, then the standard channels will be +assigned starting with standard input, followed by standard output, with +standard error being last. + +.SH "SEE ALSO" +Tcl_Close(3), Tcl_CreateChannel(3) + +.SH KEYWORDS +standard channel, standard input, standard output, standard error diff --git a/mk4/modtcl/tcl8.3.4/doc/GetVersion.3 b/mk4/modtcl/tcl8.3.4/doc/GetVersion.3 new file mode 100644 index 0000000..5615b9c --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/GetVersion.3 @@ -0,0 +1,49 @@ +'\" +'\" Copyright (c) 1999 Scriptics Corporation +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: GetVersion.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_GetVersion 3 7.5 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_GetVersion \- get the version of the library at runtime +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +\fBTcl_GetVersion\fR(\fImajor, minor, patchLevel, type\fR) +.SH ARGUMENTS +.AP int *major out +Major version number of the Tcl library. +.AP int *minor out +Minor version number of the Tcl library. +.AP int *patchLevel out +The patch level of the Tcl library (or alpha or beta number). +.AP Tcl_ReleaseType *type out +The type of release, also indicates the type of patch level. Can be +one of \fBTCL_ALPHA_RELEASE\fR, \fBTCL_BETA_RELEASE\fR, or +\fBTCL_FINAL_RELEASE\fR. +.BE + +.SH DESCRIPTION +.PP +\fBTcl_GetVersion\fR should be used to query the version number +of the Tcl library at runtime. This is useful when using a +dynamically loaded Tcl library or when writing a stubs-aware +extension. For instance, if you write an extension that is +linked against the Tcl stubs library, it could be loaded into +a program linked to an older version of Tcl than you expected. +Use \fBTcl_GetVersion\fR to verify that fact, and possibly to +change the behavior of your extension. +.PP +If may pass a NULL for any of the arguments. For instance if +you do not care about the \fIpatchLevel\fR of the library, pass +a NULL for the \fIpatchLevel\fR argument. + +.SH KEYWORDS +version, patchlevel, major, minor, alpha, beta, release + diff --git a/mk4/modtcl/tcl8.3.4/doc/Hash.3 b/mk4/modtcl/tcl8.3.4/doc/Hash.3 new file mode 100644 index 0000000..3202c34 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/Hash.3 @@ -0,0 +1,208 @@ +'\" +'\" Copyright (c) 1989-1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: Hash.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_Hash 3 "" Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_InitHashTable, Tcl_DeleteHashTable, Tcl_CreateHashEntry, Tcl_DeleteHashEntry, Tcl_FindHashEntry, Tcl_GetHashValue, Tcl_SetHashValue, Tcl_GetHashKey, Tcl_FirstHashEntry, Tcl_NextHashEntry, Tcl_HashStats \- procedures to manage hash tables +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +\fBTcl_InitHashTable\fR(\fItablePtr, keyType\fR) +.sp +\fBTcl_DeleteHashTable\fR(\fItablePtr\fR) +.sp +Tcl_HashEntry * +\fBTcl_CreateHashEntry\fR(\fItablePtr, key, newPtr\fR) +.sp +\fBTcl_DeleteHashEntry\fR(\fIentryPtr\fR) +.sp +Tcl_HashEntry * +\fBTcl_FindHashEntry\fR(\fItablePtr, key\fR) +.sp +ClientData +\fBTcl_GetHashValue\fR(\fIentryPtr\fR) +.sp +\fBTcl_SetHashValue\fR(\fIentryPtr, value\fR) +.sp +char * +\fBTcl_GetHashKey\fR(\fItablePtr, entryPtr\fR) +.sp +Tcl_HashEntry * +\fBTcl_FirstHashEntry\fR(\fItablePtr, searchPtr\fR) +.sp +Tcl_HashEntry * +\fBTcl_NextHashEntry\fR(\fIsearchPtr\fR) +.sp +char * +\fBTcl_HashStats\fR(\fItablePtr\fR) +.SH ARGUMENTS +.AS Tcl_HashSearch *searchPtr +.AP Tcl_HashTable *tablePtr in +Address of hash table structure (for all procedures but +\fBTcl_InitHashTable\fR, this must have been initialized by +previous call to \fBTcl_InitHashTable\fR). +.AP int keyType in +Kind of keys to use for new hash table. Must be either +TCL_STRING_KEYS, TCL_ONE_WORD_KEYS, or an integer value +greater than 1. +.AP char *key in +Key to use for probe into table. Exact form depends on +\fIkeyType\fR used to create table. +.AP int *newPtr out +The word at \fI*newPtr\fR is set to 1 if a new entry was created +and 0 if there was already an entry for \fIkey\fR. +.AP Tcl_HashEntry *entryPtr in +Pointer to hash table entry. +.AP ClientData value in +New value to assign to hash table entry. Need not have type +ClientData, but must fit in same space as ClientData. +.AP Tcl_HashSearch *searchPtr in +Pointer to record to use to keep track of progress in enumerating +all the entries in a hash table. +.BE + +.SH DESCRIPTION +.PP +A hash table consists of zero or more entries, each consisting of +a key and a value. +Given the key for an entry, the hashing routines can very quickly +locate the entry, and hence its value. +There may be at most one entry in a hash table with a +particular key, but many entries may have the same value. +Keys can take one of three forms: strings, +one-word values, or integer arrays. +All of the keys in a given table have the same form, which is +specified when the table is initialized. +.PP +The value of a hash table entry can be anything that fits in +the same space as a ``char *'' pointer. +Values for hash table entries are managed entirely by clients, +not by the hash module itself. +Typically each entry's value is a pointer to a data structure +managed by client code. +.PP +Hash tables grow gracefully as the number of entries increases, +so that there are always less than three entries per hash bucket, +on average. +This allows for fast lookups regardless of the number of entries +in a table. +.PP +\fBTcl_InitHashTable\fR initializes a structure that describes +a new hash table. +The space for the structure is provided by the caller, not by +the hash module. +The value of \fIkeyType\fR indicates what kinds of keys will +be used for all entries in the table. \fIKeyType\fR must have +one of the following values: +.IP \fBTCL_STRING_KEYS\fR 25 +Keys are null-terminated ASCII strings. +They are passed to hashing routines using the address of the +first character of the string. +.IP \fBTCL_ONE_WORD_KEYS\fR 25 +Keys are single-word values; they are passed to hashing routines +and stored in hash table entries as ``char *'' values. +The pointer value is the key; it need not (and usually doesn't) +actually point to a string. +.IP \fIother\fR 25 +If \fIkeyType\fR is not TCL_STRING_KEYS or TCL_ONE_WORD_KEYS, +then it must be an integer value greater than 1. +In this case the keys will be arrays of ``int'' values, where +\fIkeyType\fR gives the number of ints in each key. +This allows structures to be used as keys. +All keys must have the same size. +Array keys are passed into hashing functions using the address +of the first int in the array. +.PP +\fBTcl_DeleteHashTable\fR deletes all of the entries in a hash +table and frees up the memory associated with the table's +bucket array and entries. +It does not free the actual table structure (pointed to +by \fItablePtr\fR), since that memory is assumed to be managed +by the client. +\fBTcl_DeleteHashTable\fR also does not free or otherwise +manipulate the values of the hash table entries. +If the entry values point to dynamically-allocated memory, then +it is the client's responsibility to free these structures +before deleting the table. +.PP +\fBTcl_CreateHashEntry\fR locates the entry corresponding to a +particular key, creating a new entry in the table if there +wasn't already one with the given key. +If an entry already existed with the given key then \fI*newPtr\fR +is set to zero. +If a new entry was created, then \fI*newPtr\fR is set to a non-zero +value and the value of the new entry will be set to zero. +The return value from \fBTcl_CreateHashEntry\fR is a pointer to +the entry, which may be used to retrieve and modify the entry's +value or to delete the entry from the table. +.PP +\fBTcl_DeleteHashEntry\fR will remove an existing entry from a +table. +The memory associated with the entry itself will be freed, but +the client is responsible for any cleanup associated with the +entry's value, such as freeing a structure that it points to. +.PP +\fBTcl_FindHashEntry\fR is similar to \fBTcl_CreateHashEntry\fR +except that it doesn't create a new entry if the key doesn't exist; +instead, it returns NULL as result. +.PP +\fBTcl_GetHashValue\fR and \fBTcl_SetHashValue\fR are used to +read and write an entry's value, respectively. +Values are stored and retrieved as type ``ClientData'', which is +large enough to hold a pointer value. On almost all machines this is +large enough to hold an integer value too. +.PP +\fBTcl_GetHashKey\fR returns the key for a given hash table entry, +either as a pointer to a string, a one-word (``char *'') key, or +as a pointer to the first word of an array of integers, depending +on the \fIkeyType\fR used to create a hash table. +In all cases \fBTcl_GetHashKey\fR returns a result with type +``char *''. +When the key is a string or array, the result of \fBTcl_GetHashKey\fR +points to information in the table entry; this information will +remain valid until the entry is deleted or its table is deleted. +.PP +\fBTcl_FirstHashEntry\fR and \fBTcl_NextHashEntry\fR may be used +to scan all of the entries in a hash table. +A structure of type ``Tcl_HashSearch'', provided by the client, +is used to keep track of progress through the table. +\fBTcl_FirstHashEntry\fR initializes the search record and +returns the first entry in the table (or NULL if the table is +empty). +Each subsequent call to \fBTcl_NextHashEntry\fR returns the +next entry in the table or +NULL if the end of the table has been reached. +A call to \fBTcl_FirstHashEntry\fR followed by calls to +\fBTcl_NextHashEntry\fR will return each of the entries in +the table exactly once, in an arbitrary order. +It is unadvisable to modify the structure of the table, e.g. +by creating or deleting entries, while the search is in +progress. +.PP +\fBTcl_HashStats\fR returns a dynamically-allocated string with +overall information about a hash table, such as the number of +entries it contains, the number of buckets in its hash array, +and the utilization of the buckets. +It is the caller's responsibility to free the result string +by passing it to \fBckfree\fR. +.PP +The header file \fBtcl.h\fR defines the actual data structures +used to implement hash tables. +This is necessary so that clients can allocate Tcl_HashTable +structures and so that macros can be used to read and write +the values of entries. +However, users of the hashing routines should never refer directly +to any of the fields of any of the hash-related data structures; +use the procedures and macros defined here. + +.SH KEYWORDS +hash table, key, lookup, search, value diff --git a/mk4/modtcl/tcl8.3.4/doc/Init.3 b/mk4/modtcl/tcl8.3.4/doc/Init.3 new file mode 100644 index 0000000..b0398a4 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/Init.3 @@ -0,0 +1,37 @@ +'\" +'\" Copyright (c) 1998-2000 by Scriptics Corporation. +'\" All rights reserved. +'\" +'\" RCS: @(#) $Id: Init.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_Init 3 8.0 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_Init \- find and source initialization script +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +int +\fBTcl_Init\fR(\fIinterp\fR) +.SH ARGUMENTS +.AP Tcl_Interp *interp in +Interpreter to initialize. +.BE + +.SH DESCRIPTION +.PP +\fBTcl_Init\fR is a helper procedure that finds and \fBsource\fR's the +\fBinit.tcl\fR script, which should exist somewhere on the Tcl library +path. On Macintosh systems, it additionally checks for an \fBInit\fR +resource and sources the contents of that resource if \fBinit.tcl\fR +cannot be found. +.PP +\fBTcl_Init\fR is typically called from \fBTcl_AppInit\fR procedures. + +.SH "SEE ALSO" +Tcl_AppInit, Tcl_Main + +.SH KEYWORDS +application, initialization, interpreter diff --git a/mk4/modtcl/tcl8.3.4/doc/InitStubs.3 b/mk4/modtcl/tcl8.3.4/doc/InitStubs.3 new file mode 100644 index 0000000..3ba510e --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/InitStubs.3 @@ -0,0 +1,91 @@ +'\" +'\" Copyright (c) 1999 Scriptics Corportation +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: InitStubs.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_InitStubs 3 8.1 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_InitStubs \- initialize the Tcl stubs mechanism +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +char * +\fBTcl_InitStubs\fR(\fIinterp, version, exact\fR) +.SH ARGUMENTS +.AS Tcl_Interp *interp in +.AP Tcl_Interp *interp in +Tcl interpreter handle. +.AP char *version in +A version string consisting of one or more decimal numbers +separated by dots. +.AP int exact in +Non-zero means that only the particular version specified by +\fIversion\fR is acceptable. +Zero means that versions newer than \fIversion\fR are also +acceptable as long as they have the same major version number +as \fIversion\fR. +.BE +.SH INTRODUCTION +.PP +The Tcl stubs mechanism defines a way to dynamically bind +extensions to a particular Tcl implementation at run time. +This provides two significant benefits to Tcl users: +.IP 1) 5 +Extensions that use the stubs mechanism can be loaded into +multiple versions of Tcl without being recompiled or +relinked. +.IP 2) 5 +Extensions that use the stubs mechanism can be dynamically +loaded into statically-linked Tcl applications. +.PP +The stubs mechanism accomplishes this by exporting function tables +that define an interface to the Tcl API. The extension then accesses +the Tcl API through offsets into the function table, so there are no +direct references to any of the Tcl library's symbols. This +redirection is transparent to the extension, so an extension writer +can continue to use all public Tcl functions as documented. +.PP +The stubs mechanism requires no changes to applications incorporating +Tcl interpreters. Only developers creating C-based Tcl extensions +need to take steps to use the stubs mechanism with their extensions. +.PP +Enabling the stubs mechanism for an extension requires the following +steps: +.IP 1) 5 +Call \fBTcl_InitStubs\fR in the extension before calling any other +Tcl functions. +.IP 2) 5 +Define the USE_TCL_STUBS symbol. Typically, you would include the +-DUSE_TCL_STUBS flag when compiling the extension. +.IP 3) 5 +Link the extension with the Tcl stubs library instead of the standard +Tcl library. On Unix platforms, the library name is +\fIlibtclstub8.1.a\fR; on Windows platforms, the library name is +\fItclstub81.lib\fR. +.PP +If the extension also requires the Tk API, it must also call +\fBTk_InitStubs\fR to initialize the Tk stubs interface and link +with the Tk stubs libraries. See the \fBTk_InitStubs\fR page for +more information. +.SH DESCRIPTION +\fBTcl_InitStubs\fR attempts to initialize the stub table pointers +and ensure that the correct version of Tcl is loaded. In addition +to an interpreter handle, it accepts as arguments a version number +and a Boolean flag indicating whether the extension requires +an exact version match or not. If \fIexact\fR is 0, then the +extension is indicating that newer versions of Tcl are acceptable +as long as they have the same major version number as \fIversion\fR; +non-zero means that only the specified \fIversion\fR is acceptable. +\fBTcl_InitStubs\fR returns a string containing the actual version +of Tcl satisfying the request, or NULL if the Tcl version is not +acceptable, does not support stubs, or any other error condition occurred. +.SH "SEE ALSO" +\fBTk_InitStubs\fR +.SH KEYWORDS +stubs diff --git a/mk4/modtcl/tcl8.3.4/doc/IntObj.3 b/mk4/modtcl/tcl8.3.4/doc/IntObj.3 new file mode 100644 index 0000000..5465b7b --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/IntObj.3 @@ -0,0 +1,104 @@ +'\" +'\" Copyright (c) 1996-1997 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: IntObj.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_IntObj 3 8.0 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_NewIntObj, Tcl_NewLongObj, Tcl_SetIntObj, Tcl_SetLongObj, Tcl_GetIntFromObj, Tcl_GetLongFromObj \- manipulate Tcl objects as integers +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +Tcl_Obj * +\fBTcl_NewIntObj\fR(\fIintValue\fR) +.sp +Tcl_Obj * +\fBTcl_NewLongObj\fR(\fIlongValue\fR) +.sp +\fBTcl_SetIntObj\fR(\fIobjPtr, intValue\fR) +.sp +\fBTcl_SetLongObj\fR(\fIobjPtr, longValue\fR) +.sp +int +\fBTcl_GetIntFromObj\fR(\fIinterp, objPtr, intPtr\fR) +.sp +int +\fBTcl_GetLongFromObj\fR(\fIinterp, objPtr, longPtr\fR) +.SH ARGUMENTS +.AS Tcl_Interp *interp +.AP int intValue in +Integer value used to initialize or set an integer object. +.AP long longValue in +Long integer value used to initialize or set an integer object. +.AP Tcl_Obj *objPtr in/out +For \fBTcl_SetIntObj\fR and \fBTcl_SetLongObj\fR, +this points to the object to be converted to integer type. +For \fBTcl_GetIntFromObj\fR and \fBTcl_GetLongFromObj\fR, +this refers to the object +from which to get an integer or long integer value; +if \fIobjPtr\fR does not already point to an integer object, +an attempt will be made to convert it to one. +.AP Tcl_Interp *interp in/out +If an error occurs during conversion, +an error message is left in the interpreter's result object +unless \fIinterp\fR is NULL. +.AP int *intPtr out +Points to place to store the integer value +obtained by \fBTcl_GetIntFromObj\fR from \fIobjPtr\fR. +.AP long *longPtr out +Points to place to store the long integer value +obtained by \fBTcl_GetLongFromObj\fR from \fIobjPtr\fR. +.BE + +.SH DESCRIPTION +.PP +These procedures are used to create, modify, and read +integer Tcl objects from C code. +\fBTcl_NewIntObj\fR, \fBTcl_NewLongObj\fR, +\fBTcl_SetIntObj\fR, and \fBTcl_SetLongObj\fR +create a new object of integer type +or modify an existing object to have integer type. +\fBTcl_NewIntObj\fR and \fBTcl_SetIntObj\fR set the object to have the +integer value given by \fIintValue\fR, +while \fBTcl_NewLongObj\fR and \fBTcl_SetLongObj\fR +set the object to have the +long integer value given by \fIlongValue\fR. +\fBTcl_NewIntObj\fR and \fBTcl_NewLongObj\fR +return a pointer to a newly created object with reference count zero. +These procedures set the object's type to be integer +and assign the integer value to the object's internal representation +\fIlongValue\fR member. +\fBTcl_SetIntObj\fR and \fBTcl_SetLongObj\fR +invalidate any old string representation and, +if the object is not already an integer object, +free any old internal representation. +.PP +\fBTcl_GetIntFromObj\fR and \fBTcl_GetLongFromObj\fR +attempt to return an integer value from the Tcl object \fIobjPtr\fR. +If the object is not already an integer object, +they will attempt to convert it to one. +If an error occurs during conversion, they return \fBTCL_ERROR\fR +and leave an error message in the interpreter's result object +unless \fIinterp\fR is NULL. +Also, if the long integer held in the object's internal representation +\fIlongValue\fR member can not be represented in a (non-long) integer, +\fBTcl_GetIntFromObj\fR returns \fBTCL_ERROR\fR +and leaves an error message in the interpreter's result object +unless \fIinterp\fR is NULL. +Otherwise, both procedures return \fBTCL_OK\fR and +store the integer or the long integer value +in the address given by \fIintPtr\fR and \fIlongPtr\fR respectively. +If the object is not already an integer object, +the conversion will free any old internal representation. + +.SH "SEE ALSO" +Tcl_NewObj, Tcl_DecrRefCount, Tcl_IncrRefCount, Tcl_GetObjResult + +.SH KEYWORDS +integer, integer object, integer type, internal representation, object, object type, string representation diff --git a/mk4/modtcl/tcl8.3.4/doc/Interp.3 b/mk4/modtcl/tcl8.3.4/doc/Interp.3 new file mode 100644 index 0000000..929be7b --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/Interp.3 @@ -0,0 +1,126 @@ +'\" +'\" Copyright (c) 1989-1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: Interp.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_Interp 3 7.5 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_Interp \- client-visible fields of interpreter structures +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +typedef struct { + char *\fIresult\fR; + Tcl_FreeProc *\fIfreeProc\fR; + int \fIerrorLine\fR; +} Tcl_Interp; + +typedef void Tcl_FreeProc(char *\fIblockPtr\fR); +.BE + +.SH DESCRIPTION +.PP +The \fBTcl_CreateInterp\fR procedure returns a pointer to a Tcl_Interp +structure. This pointer is then passed into other Tcl procedures +to process commands in the interpreter and perform other operations +on the interpreter. Interpreter structures contain many many fields +that are used by Tcl, but only three that may be accessed by +clients: \fIresult\fR, \fIfreeProc\fR, and \fIerrorLine\fR. +.PP +The \fIresult\fR and \fIfreeProc\fR fields are used to return +results or error messages from commands. +This information is returned by command procedures back to \fBTcl_Eval\fR, +and by \fBTcl_Eval\fR back to its callers. +The \fIresult\fR field points to the string that represents the +result or error message, and the \fIfreeProc\fR field tells how +to dispose of the storage for the string when it isn't needed anymore. +The easiest way for command procedures to manipulate these +fields is to call procedures like \fBTcl_SetResult\fR +or \fBTcl_AppendResult\fR; they +will hide all the details of managing the fields. +The description below is for those procedures that manipulate the +fields directly. +.PP +Whenever a command procedure returns, it must ensure +that the \fIresult\fR field of its interpreter points to the string +being returned by the command. +The \fIresult\fR field must always point to a valid string. +If a command wishes to return no result then \fIinterp->result\fR +should point to an empty string. +Normally, results are assumed to be statically allocated, +which means that the contents will not change before the next time +\fBTcl_Eval\fR is called or some other command procedure is invoked. +.VS +In this case, the \fIfreeProc\fR field must be zero. +Alternatively, a command procedure may dynamically +allocate its return value (e.g. using \fBTcl_Alloc\fR) +and store a pointer to it in \fIinterp->result\fR. +In this case, the command procedure must also set \fIinterp->freeProc\fR +to the address of a procedure that can free the value, or \fBTCL_DYNAMIC\fR +if the storage was allocated directly by Tcl or by a call to +\fBTcl_Alloc\fR. +.VE +If \fIinterp->freeProc\fR is non-zero, then Tcl will call \fIfreeProc\fR +to free the space pointed to by \fIinterp->result\fR before it +invokes the next command. +If a client procedure overwrites \fIinterp->result\fR when +\fIinterp->freeProc\fR is non-zero, then it is responsible for calling +\fIfreeProc\fR to free the old \fIinterp->result\fR (the \fBTcl_FreeResult\fR +macro should be used for this purpose). +.PP +\fIFreeProc\fR should have arguments and result that match the +\fBTcl_FreeProc\fR declaration above: it receives a single +argument which is a pointer to the result value to free. +.VS +In most applications \fBTCL_DYNAMIC\fR is the only non-zero value ever +used for \fIfreeProc\fR. +.VE +However, an application may store a different procedure address +in \fIfreeProc\fR in order to use an alternate memory allocator +or in order to do other cleanup when the result memory is freed. +.PP +As part of processing each command, \fBTcl_Eval\fR initializes +\fIinterp->result\fR +and \fIinterp->freeProc\fR just before calling the command procedure for +the command. The \fIfreeProc\fR field will be initialized to zero, +and \fIinterp->result\fR will point to an empty string. Commands that +do not return any value can simply leave the fields alone. +Furthermore, the empty string pointed to by \fIresult\fR is actually +part of an array of \fBTCL_RESULT_SIZE\fR characters (approximately 200). +If a command wishes to return a short string, it can simply copy +it to the area pointed to by \fIinterp->result\fR. Or, it can use +the sprintf procedure to generate a short result string at the location +pointed to by \fIinterp->result\fR. +.PP +It is a general convention in Tcl-based applications that the result +of an interpreter is normally in the initialized state described +in the previous paragraph. +Procedures that manipulate an interpreter's result (e.g. by +returning an error) will generally assume that the result +has been initialized when the procedure is called. +If such a procedure is to be called after the result has been +changed, then \fBTcl_ResetResult\fR should be called first to +reset the result to its initialized state. The direct use of +\fIinterp->result\fR is strongly deprecated (see \fBTcl_SetResult\fR). +.PP +The \fIerrorLine\fR +field is valid only after \fBTcl_Eval\fR returns +a \fBTCL_ERROR\fR return code. In this situation the \fIerrorLine\fR +field identifies the line number of the command being executed when +the error occurred. The line numbers are relative to the command +being executed: 1 means the first line of the command passed to +\fBTcl_Eval\fR, 2 means the second line, and so on. +The \fIerrorLine\fR field is typically used in conjunction with +\fBTcl_AddErrorInfo\fR to report information about where an error +occurred. +\fIErrorLine\fR should not normally be modified except by \fBTcl_Eval\fR. + +.SH KEYWORDS +free, initialized, interpreter, malloc, result diff --git a/mk4/modtcl/tcl8.3.4/doc/LinkVar.3 b/mk4/modtcl/tcl8.3.4/doc/LinkVar.3 new file mode 100644 index 0000000..d9fd3ef --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/LinkVar.3 @@ -0,0 +1,115 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: LinkVar.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_LinkVar 3 7.5 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_LinkVar, Tcl_UnlinkVar, Tcl_UpdateLinkedVar \- link Tcl variable to C variable +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +int +\fBTcl_LinkVar\fR(\fIinterp, varName, addr, type\fR) +.sp +\fBTcl_UnlinkVar\fR(\fIinterp, varName\fR) +.sp +\fBTcl_UpdateLinkedVar\fR(\fIinterp, varName\fR) +.SH ARGUMENTS +.AS Tcl_Interp writable +.AP Tcl_Interp *interp in +Interpreter that contains \fIvarName\fR. +Also used by \fBTcl_LinkVar\fR to return error messages. +.AP char *varName in +Name of global variable. Must be in writable memory: Tcl may make +temporary modifications to it while parsing the variable name. +.AP char *addr in +Address of C variable that is to be linked to \fIvarName\fR. +.AP int type in +Type of C variable. Must be one of TCL_LINK_INT, TCL_LINK_DOUBLE, +TCL_LINK_BOOLEAN, or TCL_LINK_STRING, optionally OR'ed with +TCL_LINK_READ_ONLY to make Tcl variable read-only. +.BE + +.SH DESCRIPTION +.PP +\fBTcl_LinkVar\fR uses variable traces to keep the Tcl variable +named by \fIvarName\fR in sync with the C variable at the address +given by \fIaddr\fR. +Whenever the Tcl variable is read the value of the C variable will +be returned, and whenever the Tcl variable is written the C +variable will be updated to have the same value. +\fBTcl_LinkVar\fR normally returns TCL_OK; if an error occurs +while setting up the link (e.g. because \fIvarName\fR is the +name of array) then TCL_ERROR is returned and the interpreter's result +contains an error message. +.PP +The \fItype\fR argument specifies the type of the C variable, +and must have one of the following values, optionally OR'ed with +TCL_LINK_READ_ONLY: +.TP +\fBTCL_LINK_INT\fR +The C variable is of type \fBint\fR. +Any value written into the Tcl variable must have a proper integer +form acceptable to \fBTcl_GetInt\fR; attempts to write +non-integer values into \fIvarName\fR will be rejected with +Tcl errors. +.TP +\fBTCL_LINK_DOUBLE\fR +The C variable is of type \fBdouble\fR. +Any value written into the Tcl variable must have a proper real +form acceptable to \fBTcl_GetDouble\fR; attempts to write +non-real values into \fIvarName\fR will be rejected with +Tcl errors. +.TP +\fBTCL_LINK_BOOLEAN\fR +The C variable is of type \fBint\fR. +If its value is zero then it will read from Tcl as ``0''; +otherwise it will read from Tcl as ``1''. +Whenever \fIvarName\fR is +modified, the C variable will be set to a 0 or 1 value. +Any value written into the Tcl variable must have a proper boolean +form acceptable to \fBTcl_GetBoolean\fR; attempts to write +non-boolean values into \fIvarName\fR will be rejected with +Tcl errors. +.TP +\fBTCL_LINK_STRING\fR +The C variable is of type \fBchar *\fR. +.VS +If its value is not null then it must be a pointer to a string +allocated with \fBTcl_Alloc\fR. +.VE +Whenever the Tcl variable is modified the current C string will be +freed and new memory will be allocated to hold a copy of the variable's +new value. +If the C variable contains a null pointer then the Tcl variable +will read as ``NULL''. +.PP +If the TCL_LINK_READ_ONLY flag is present in \fItype\fR then the +variable will be read-only from Tcl, so that its value can only be +changed by modifying the C variable. +Attempts to write the variable from Tcl will be rejected with errors. +.PP +\fBTcl_UnlinkVar\fR removes the link previously set up for the +variable given by \fIvarName\fR. If there does not exist a link +for \fIvarName\fR then the procedure has no effect. +.PP +\fBTcl_UpdateLinkedVar\fR may be invoked after the C variable has +changed to force the Tcl variable to be updated immediately. +In many cases this procedure is not needed, since any attempt to +read the Tcl variable will return the latest value of the C variable. +However, if a trace has been set on the Tcl variable (such as a +Tk widget that wishes to display the value of the variable), the +trace will not trigger when the C variable has changed. +\fBTcl_UpdateLinkedVar\fR ensures that any traces on the Tcl +variable are invoked. + +.SH KEYWORDS +boolean, integer, link, read-only, real, string, traces, variable diff --git a/mk4/modtcl/tcl8.3.4/doc/ListObj.3 b/mk4/modtcl/tcl8.3.4/doc/ListObj.3 new file mode 100644 index 0000000..258f694 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/ListObj.3 @@ -0,0 +1,247 @@ +'\" +'\" Copyright (c) 1996-1997 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: ListObj.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_ListObj 3 8.0 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_ListObjAppendList, Tcl_ListObjAppendElement, Tcl_NewListObj, Tcl_SetListObj, Tcl_ListObjGetElements, Tcl_ListObjLength, Tcl_ListObjIndex, Tcl_ListObjReplace \- manipulate Tcl objects as lists +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +int +\fBTcl_ListObjAppendList\fR(\fIinterp, listPtr, elemListPtr\fR) +.sp +int +\fBTcl_ListObjAppendElement\fR(\fIinterp, listPtr, objPtr\fR) +.sp +Tcl_Obj * +\fBTcl_NewListObj\fR(\fIobjc, objv\fR) +.sp +\fBTcl_SetListObj\fR(\fIobjPtr, objc, objv\fR) +.sp +int +\fBTcl_ListObjGetElements\fR(\fIinterp, listPtr, objcPtr, objvPtr\fR) +.sp +int +\fBTcl_ListObjLength\fR(\fIinterp, listPtr, intPtr\fR) +.sp +int +\fBTcl_ListObjIndex\fR(\fIinterp, listPtr, index, objPtrPtr\fR) +.sp +int +\fBTcl_ListObjReplace\fR(\fIinterp, listPtr, first, count, objc, objv\fR) +.SH ARGUMENTS +.AS Tcl_Interp "*CONST objv[]" out +.AP Tcl_Interp *interp in +If an error occurs while converting an object to be a list object, +an error message is left in the interpreter's result object +unless \fIinterp\fR is NULL. +.AP Tcl_Obj *listPtr in/out +Points to the list object to be manipulated. +If \fIlistPtr\fR does not already point to a list object, +an attempt will be made to convert it to one. +.AP Tcl_Obj *elemListPtr in/out +For \fBTcl_ListObjAppendList\fR, this points to a list object +containing elements to be appended onto \fIlistPtr\fR. +Each element of *\fIelemListPtr\fR will +become a new element of \fIlistPtr\fR. +If *\fIelemListPtr\fR is not NULL and +does not already point to a list object, +an attempt will be made to convert it to one. +.AP Tcl_Obj *objPtr in +For \fBTcl_ListObjAppendElement\fR, +points to the Tcl object that will be appended to \fIlistPtr\fR. +For \fBTcl_SetListObj\fR, +this points to the Tcl object that will be converted to a list object +containing the \fIobjc\fR elements of the array referenced by \fIobjv\fR. +.AP int *objcPtr in +Points to location where \fBTcl_ListObjGetElements\fR +stores the number of element objects in \fIlistPtr\fR. +.AP Tcl_Obj ***objvPtr out +A location where \fBTcl_ListObjGetElements\fR stores a pointer to an array +of pointers to the element objects of \fIlistPtr\fR. +.AP int objc in +The number of Tcl objects that \fBTcl_NewListObj\fR +will insert into a new list object, +and \fBTcl_ListObjReplace\fR will insert into \fIlistPtr\fR. +For \fBTcl_SetListObj\fR, +the number of Tcl objects to insert into \fIobjPtr\fR. +.VS +.AP Tcl_Obj "*CONST\ objv[]" in +An array of pointers to objects. +\fBTcl_NewListObj\fR will insert these objects into a new list object +and \fBTcl_ListObjReplace\fR will insert them into an existing \fIlistPtr\fR. +Each object will become a separate list element. +.VE +.AP int *intPtr out +Points to location where \fBTcl_ListObjLength\fR +stores the length of the list. +.AP int index in +Index of the list element that \fBTcl_ListObjIndex\fR +is to return. +The first element has index 0. +.AP Tcl_Obj **objPtrPtr out +Points to place where \fBTcl_ListObjIndex\fR is to store +a pointer to the resulting list element object. +.AP int first in +Index of the starting list element that \fBTcl_ListObjReplace\fR +is to replace. +The list's first element has index 0. +.AP int count in +The number of elements that \fBTcl_ListObjReplace\fR +is to replace. +.BE + +.SH DESCRIPTION +.PP +Tcl list objects have an internal representation that supports +the efficient indexing and appending. +The procedures described in this man page are used to +create, modify, index, and append to Tcl list objects from C code. +.PP +\fBTcl_ListObjAppendList\fR and \fBTcl_ListObjAppendElement\fR +both add one or more objects +to the end of the list object referenced by \fIlistPtr\fR. +\fBTcl_ListObjAppendList\fR appends each element of the list object +referenced by \fIelemListPtr\fR while +\fBTcl_ListObjAppendElement\fR appends the single object +referenced by \fIobjPtr\fR. +Both procedures will convert the object referenced by \fIlistPtr\fR +to a list object if necessary. +If an error occurs during conversion, +both procedures return \fBTCL_ERROR\fR and leave an error message +in the interpreter's result object if \fIinterp\fR is not NULL. +Similarly, if \fIelemListPtr\fR does not already refer to a list object, +\fBTcl_ListObjAppendList\fR will attempt to convert it to one +and if an error occurs during conversion, +will return \fBTCL_ERROR\fR +and leave an error message in the interpreter's result object +if interp is not NULL. +Both procedures invalidate any old string representation of \fIlistPtr\fR +and, if it was converted to a list object, +free any old internal representation. +Similarly, \fBTcl_ListObjAppendList\fR frees any old internal representation +of \fIelemListPtr\fR if it converts it to a list object. +After appending each element in \fIelemListPtr\fR, +\fBTcl_ListObjAppendList\fR increments the element's reference count +since \fIlistPtr\fR now also refers to it. +For the same reason, \fBTcl_ListObjAppendElement\fR +increments \fIobjPtr\fR's reference count. +If no error occurs, +the two procedures return \fBTCL_OK\fR after appending the objects. +.PP +\fBTcl_NewListObj\fR and \fBTcl_SetListObj\fR +create a new object or modify an existing object to hold +the \fIobjc\fR elements of the array referenced by \fIobjv\fR +where each element is a pointer to a Tcl object. +If \fIobjc\fR is less than or equal to zero, +they return an empty object. +The new object's string representation is left invalid. +The two procedures increment the reference counts +of the elements in \fIobjc\fR since the list object now refers to them. +The new list object returned by \fBTcl_NewListObj\fR +has reference count zero. +.PP +\fBTcl_ListObjGetElements\fR returns a count and a pointer to an array of +the elements in a list object. It returns the count by storing it in the +address \fIobjcPtr\fR. Similarly, it returns the array pointer by storing +it in the address \fIobjvPtr\fR. +The memory pointed to is managed by Tcl and should not be freed by the +caller. +If \fIlistPtr\fR is not already a list object, \fBTcl_ListObjGetElements\fR +will attempt to convert it to one; if the conversion fails, it returns +\fBTCL_ERROR\fR and leaves an error message in the interpreter's result +object if \fIinterp\fR is not NULL. +Otherwise it returns \fBTCL_OK\fR after storing the count and array pointer. +.PP +\fBTcl_ListObjLength\fR returns the number of elements in the list object +referenced by \fIlistPtr\fR. +It returns this count by storing an integer in the address \fIintPtr\fR. +If the object is not already a list object, +\fBTcl_ListObjLength\fR will attempt to convert it to one; +if the conversion fails, it returns \fBTCL_ERROR\fR +and leaves an error message in the interpreter's result object +if \fIinterp\fR is not NULL. +Otherwise it returns \fBTCL_OK\fR after storing the list's length. +.PP +The procedure \fBTcl_ListObjIndex\fR returns a pointer to the object +at element \fIindex\fR in the list referenced by \fIlistPtr\fR. +It returns this object by storing a pointer to it +in the address \fIobjPtrPtr\fR. +If \fIlistPtr\fR does not already refer to a list object, +\fBTcl_ListObjIndex\fR will attempt to convert it to one; +if the conversion fails, it returns \fBTCL_ERROR\fR +and leaves an error message in the interpreter's result object +if \fIinterp\fR is not NULL. +If the index is out of range, +that is, \fIindex\fR is negative or +greater than or equal to the number of elements in the list, +\fBTcl_ListObjIndex\fR stores a NULL in \fIobjPtrPtr\fR +and returns \fBTCL_OK\fR. +Otherwise it returns \fBTCL_OK\fR after storing the element's +object pointer. +The reference count for the list element is not incremented; +the caller must do that if it needs to retain a pointer to the element. +.PP +\fBTcl_ListObjReplace\fR replaces zero or more elements +of the list referenced by \fIlistPtr\fR +with the \fIobjc\fR objects in the array referenced by \fIobjv\fR. +If \fIlistPtr\fR does not point to a list object, +\fBTcl_ListObjReplace\fR will attempt to convert it to one; +if the conversion fails, it returns \fBTCL_ERROR\fR +and leaves an error message in the interpreter's result object +if \fIinterp\fR is not NULL. +Otherwise, it returns \fBTCL_OK\fR after replacing the objects. +If \fIobjv\fR is NULL, no new elements are added. +If the argument \fIfirst\fR is zero or negative, +it refers to the first element. +If \fIfirst\fR is greater than or equal to the +number of elements in the list, then no elements are deleted; +the new elements are appended to the list. +\fIcount\fR gives the number of elements to replace. +If \fIcount\fR is zero or negative then no elements are deleted; +the new elements are simply inserted before the one +designated by \fIfirst\fR. +\fBTcl_ListObjReplace\fR invalidates \fIlistPtr\fR's +old string representation. +The reference counts of any elements inserted from \fIobjv\fR +are incremented since the resulting list now refers to them. +Similarly, the reference counts for any replaced objects are decremented. +.PP +Because \fBTcl_ListObjReplace\fR combines +both element insertion and deletion, +it can be used to implement a number of list operations. +For example, the following code inserts the \fIobjc\fR objects +referenced by the array of object pointers \fIobjv\fR +just before the element \fIindex\fR of the list referenced by \fIlistPtr\fR: +.CS +result = Tcl_ListObjReplace(interp, listPtr, index, 0, objc, objv); +.CE +Similarly, the following code appends the \fIobjc\fR objects +referenced by the array \fIobjv\fR +to the end of the list \fIlistPtr\fR: +.CS +result = Tcl_ListObjLength(interp, listPtr, &length); +if (result == TCL_OK) { + result = Tcl_ListObjReplace(interp, listPtr, length, 0, objc, objv); +} +.CE +The \fIcount\fR list elements starting at \fIfirst\fR can be deleted +by simply calling \fBTcl_ListObjReplace\fR +with a NULL \fIobjvPtr\fR: +.CS +result = Tcl_ListObjReplace(interp, listPtr, first, count, 0, NULL); +.CE + +.SH "SEE ALSO" +Tcl_NewObj, Tcl_DecrRefCount, Tcl_IncrRefCount, Tcl_GetObjResult + +.SH KEYWORDS +append, index, insert, internal representation, length, list, list object, list type, object, object type, replace, string representation diff --git a/mk4/modtcl/tcl8.3.4/doc/Notifier.3 b/mk4/modtcl/tcl8.3.4/doc/Notifier.3 new file mode 100644 index 0000000..27d4bca --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/Notifier.3 @@ -0,0 +1,602 @@ +'\" +'\" Copyright (c) 1998-1999 Scriptics Corporation +'\" Copyright (c) 1995-1997 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: Notifier.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Notifier 3 8.1 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_CreateEventSource, Tcl_DeleteEventSource, Tcl_SetMaxBlockTime, Tcl_QueueEvent, Tcl_ThreadQueueEvent, Tcl_ThreadAlert, Tcl_GetCurrentThread, Tcl_DeleteEvents, Tcl_InitNotifier, Tcl_FinalizeNotifier, Tcl_WaitForEvent, Tcl_AlertNotifier, Tcl_SetTimer, Tcl_ServiceAll, Tcl_ServiceEvent, Tcl_GetServiceMode, Tcl_SetServiceMode \- the event queue and notifier interfaces +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +void +\fBTcl_CreateEventSource\fR(\fIsetupProc, checkProc, clientData\fR) +.sp +void +\fBTcl_DeleteEventSource\fR(\fIsetupProc, checkProc, clientData\fR) +.sp +void +\fBTcl_SetMaxBlockTime\fR(\fItimePtr\fR) +.sp +void +\fBTcl_QueueEvent\fR(\fIevPtr, position\fR) +.VS 8.1 +.sp +void +\fBTcl_ThreadQueueEvent\fR(\fIthreadId, evPtr, position\fR) +.sp +void +\fBTcl_ThreadAlert\fR(\fIthreadId, clientData\fR) +.sp +Tcl_ThreadId +\fBTcl_GetCurrentThread\fR() +.sp +void +\fBTcl_DeleteEvents\fR(\fIdeleteProc, clientData\fR) +.sp +ClientData +\fBTcl_InitNotifier\fR() +.sp +void +\fBTcl_FinalizeNotifier\fR(\fIclientData\fR) +.sp +int +\fBTcl_WaitForEvent\fR(\fItimePtr\fR) +.sp +void +\fBTcl_AlertNotifier\fR(\fIclientData\fR) +.sp +void +\fBTcl_SetTimer\fR(\fItimePtr\fR) +.sp +int +\fBTcl_ServiceAll\fR() +.sp +int +\fBTcl_ServiceEvent\fR(\fIflags\fR) +.sp +int +\fBTcl_GetServiceMode\fR() +.sp +int +\fBTcl_SetServiceMode\fR(\fImode\fR) +.VE + +.SH ARGUMENTS +.AS Tcl_EventDeleteProc milliseconds +.AP Tcl_EventSetupProc *setupProc in +Procedure to invoke to prepare for event wait in \fBTcl_DoOneEvent\fR. +.AP Tcl_EventCheckProc *checkProc in +Procedure for \fBTcl_DoOneEvent\fR to invoke after waiting for +events. Checks to see if any events have occurred and, if so, +queues them. +.AP ClientData clientData in +Arbitrary one-word value to pass to \fIsetupProc\fR, \fIcheckProc\fR, or +\fIdeleteProc\fR. +.AP Tcl_Time *timePtr in +Indicates the maximum amount of time to wait for an event. This +is specified as an interval (how long to wait), not an absolute +time (when to wakeup). If the pointer passed to \fBTcl_WaitForEvent\fR +is NULL, it means there is no maximum wait time: wait forever if +necessary. +.AP Tcl_Event *evPtr in +An event to add to the event queue. The storage for the event must +have been allocated by the caller using \fBTcl_Alloc\fR or \fBckalloc\fR. +.AP Tcl_QueuePosition position in +Where to add the new event in the queue: \fBTCL_QUEUE_TAIL\fR, +\fBTCL_QUEUE_HEAD\fR, or \fBTCL_QUEUE_MARK\fR. +.AP Tcl_ThreadId threadId in +A unique identifier for a thread. +.AP Tcl_EventDeleteProc *deleteProc in +Procedure to invoke for each queued event in \fBTcl_DeleteEvents\fR. +.AP int flags in +What types of events to service. These flags are the same as those +passed to \fBTcl_DoOneEvent\fR. +.VS 8.1 +.AP int mode in +Inidicates whether events should be serviced by \fBTcl_ServiceAll\fR. +Must be one of \fBTCL_SERVICE_NONE\fR or \fBTCL_SERVICE_ALL\fR. +.VE +.BE + +.SH INTRODUCTION +.PP +The interfaces described here are used to customize the Tcl event +loop. The two most common customizations are to add new sources of +events and to merge Tcl's event loop with some other event loop, such +as one provided by an application in which Tcl is embedded. Each of +these tasks is described in a separate section below. +.PP +The procedures in this manual entry are the building blocks out of which +the Tcl event notifier is constructed. The event notifier is the lowest +layer in the Tcl event mechanism. It consists of three things: +.IP [1] +Event sources: these represent the ways in which events can be +generated. For example, there is a timer event source that implements +the \fBTcl_CreateTimerHandler\fR procedure and the \fBafter\fR +command, and there is a file event source that implements the +\fBTcl_CreateFileHandler\fR procedure on Unix systems. An event +source must work with the notifier to detect events at the right +times, record them on the event queue, and eventually notify +higher-level software that they have occurred. The procedures +\fBTcl_CreateEventSource\fR, \fBTcl_DeleteEventSource\fR, +and \fBTcl_SetMaxBlockTime\fR, \fBTcl_QueueEvent\fR, and +\fBTcl_DeleteEvents\fR are used primarily by event sources. +.IP [2] +The event queue: for non-threaded applications, +there is a single queue for the whole application, +containing events that have been detected but not yet serviced. Event +sources place events onto the queue so that they may be processed in +order at appropriate times during the event loop. The event queue +guarantees a fair discipline of event handling, so that no event +source can starve the others. It also allows events to be saved for +servicing at a future time. +.VS 8.1 +Threaded applications work in a +similar manner, except that there is a separate event queue for +each thread containing a Tcl interpreter. +\fBTcl_QueueEvent\fR is used (primarily +by event sources) to add events to the event queue and +\fBTcl_DeleteEvents\fR is used to remove events from the queue without +processing them. In a threaded application, \fBTcl_QueueEvent\fR adds +an event to the current thread's queue, and \fBTcl_ThreadQueueEvent\fR +adds an event to a queue in a specific thread. +.IP [3] +The event loop: in order to detect and process events, the application +enters a loop that waits for events to occur, places them on the event +queue, and then processes them. Most applications will do this by +calling the procedure \fBTcl_DoOneEvent\fR, which is described in a +separate manual entry. +.PP +Most Tcl applications need not worry about any of the internals of +the Tcl notifier. However, the notifier now has enough flexibility +to be retargeted either for a new platform or to use an external event +loop (such as the Motif event loop, when Tcl is embedded in a Motif +application). The procedures \fBTcl_WaitForEvent\fR and +\fBTcl_SetTimer\fR are normally implemented by Tcl, but may be +replaced with new versions to retarget the notifier (the +\fBTcl_InitNotifier\fR, \fBTcl_AlertNotifier\fR, +\fBTcl_FinalizeNotifier\fR, \fBTcl_Sleep\fR, +\fBTcl_CreateFileHandler\fR, and \fBTcl_DeleteFileHandler\fR must +also be replaced; see CREATING A NEW NOTIFIER below for details). +The procedures \fBTcl_ServiceAll\fR, \fBTcl_ServiceEvent\fR, +\fBTcl_GetServiceMode\fR, and \fBTcl_SetServiceMode\fR are provided +to help connect Tcl's event loop to an external event loop such as +Motif's. +.SH "NOTIFIER BASICS" +.VE +.PP +The easiest way to understand how the notifier works is to consider +what happens when \fBTcl_DoOneEvent\fR is called. +\fBTcl_DoOneEvent\fR is passed a \fIflags\fR argument that indicates +what sort of events it is OK to process and also whether or not to +block if no events are ready. \fBTcl_DoOneEvent\fR does the following +things: +.IP [1] +Check the event queue to see if it contains any events that can +be serviced. If so, service the first possible event, remove it +.VS 8.1 +from the queue, and return. It does this by calling +\fBTcl_ServiceEvent\fR and passing in the \fIflags\fR argument. +.VE +.IP [2] +Prepare to block for an event. To do this, \fBTcl_DoOneEvent\fR +invokes a \fIsetup procedure\fR in each event source. +The event source will perform event-source specific initialization and +.VS 8.1 +possibly call \fBTcl_SetMaxBlockTime\fR to limit how long +.VE +\fBTcl_WaitForEvent\fR will block if no new events occur. +.IP [3] +Call \fBTcl_WaitForEvent\fR. This procedure is implemented differently +on different platforms; it waits for an event to occur, based on the +information provided by the event sources. +It may cause the application to block if \fItimePtr\fR specifies +an interval other than 0. +\fBTcl_WaitForEvent\fR returns when something has happened, +such as a file becoming readable or the interval given by \fItimePtr\fR +expiring. If there are no events for \fBTcl_WaitForEvent\fR to +wait for, so that it would block forever, then it returns immediately +and \fBTcl_DoOneEvent\fR returns 0. +.IP [4] +Call a \fIcheck procedure\fR in each event source. The check +procedure determines whether any events of interest to this source +occurred. If so, the events are added to the event queue. +.IP [5] +Check the event queue to see if it contains any events that can +be serviced. If so, service the first possible event, remove it +from the queue, and return. +.IP [6] +See if there are idle callbacks pending. If so, invoke all of them and +return. +.IP [7] +Either return 0 to indicate that no events were ready, or go back to +step [2] if blocking was requested by the caller. + +.SH "CREATING A NEW EVENT SOURCE" +.PP +An event source consists of three procedures invoked by the notifier, +plus additional C procedures that are invoked by higher-level code +to arrange for event-driven callbacks. The three procedures called +by the notifier consist of the setup and check procedures described +above, plus an additional procedure that is invoked when an event +is removed from the event queue for servicing. +.PP +The procedure \fBTcl_CreateEventSource\fR creates a new event source. +Its arguments specify the setup procedure and check procedure for +the event source. +\fISetupProc\fR should match the following prototype: +.CS +typedef void Tcl_EventSetupProc( + ClientData \fIclientData\fR, + int \fIflags\fR); +.CE +The \fIclientData\fR argument will be the same as the \fIclientData\fR +argument to \fBTcl_CreateEventSource\fR; it is typically used to +point to private information managed by the event source. +The \fIflags\fR argument will be the same as the \fIflags\fR +argument passed to \fBTcl_DoOneEvent\fR except that it will never +be 0 (\fBTcl_DoOneEvent\fR replaces 0 with \fBTCL_ALL_EVENTS\fR). +\fIFlags\fR indicates what kinds of events should be considered; +if the bit corresponding to this event source isn't set, the event +source should return immediately without doing anything. For +example, the file event source checks for the \fBTCL_FILE_EVENTS\fR +bit. +.PP +\fISetupProc\fR's job is to make sure that the application wakes up +when events of the desired type occur. This is typically done in a +platform-dependent fashion. For example, under Unix an event source +might call \fBTcl_CreateFileHandler\fR; under Windows it might +request notification with a Windows event. For timer-driven event +sources such as timer events or any polled event, the event source +can call \fBTcl_SetMaxBlockTime\fR to force the application to wake +up after a specified time even if no events have occurred. +.VS 8.1 +If no event source calls \fBTcl_SetMaxBlockTime\fR +then \fBTcl_WaitForEvent\fR will wait as long as necessary for an +event to occur; otherwise, it will only wait as long as the shortest +interval passed to \fBTcl_SetMaxBlockTime\fR by one of the event +sources. If an event source knows that it already has events ready to +report, it can request a zero maximum block time. For example, the +setup procedure for the X event source looks to see if there are +events already queued. If there are, it calls +\fBTcl_SetMaxBlockTime\fR with a 0 block time so that +\fBTcl_WaitForEvent\fR does not block if there is no new data on the X +connection. +.VE +The \fItimePtr\fR argument to \fBTcl_WaitForEvent\fR points to +a structure that describes a time interval in seconds and +microseconds: +.CS +typedef struct Tcl_Time { + long \fIsec\fR; + long \fIusec\fR; +} Tcl_Time; +.CE +The \fIusec\fR field should be less than 1000000. +.PP +.VS 8.1 +Information provided to \fBTcl_SetMaxBlockTime\fR +is only used for the next call to \fBTcl_WaitForEvent\fR; it is +discarded after \fBTcl_WaitForEvent\fR returns. +.VE +The next time an event wait is done each of the event sources' +setup procedures will be called again, and they can specify new +information for that event wait. +.PP +.VS 8.1 +If the application uses an external event loop rather than +\fBTcl_DoOneEvent\fR, the event sources may need to call +\fBTcl_SetMaxBlockTime\fR at other times. For example, if a new event +handler is registered that needs to poll for events, the event source +may call \fBTcl_SetMaxBlockTime\fR to set the block time to zero to +force the external event loop to call Tcl. In this case, +\fBTcl_SetMaxBlockTime\fR invokes \fBTcl_SetTimer\fR with the shortest +interval seen since the last call to \fBTcl_DoOneEvent\fR or +\fBTcl_ServiceAll\fR. +.PP +In addition to the generic procedure \fBTcl_SetMaxBlockTime\fR, other +platform-specific procedures may also be available for +\fIsetupProc\fR, if there is additional information needed by +\fBTcl_WaitForEvent\fR on that platform. For example, on Unix systems +the \fBTcl_CreateFileHandler\fR interface can be used to wait for file events. +.VE +.PP +The second procedure provided by each event source is its check +procedure, indicated by the \fIcheckProc\fR argument to +\fBTcl_CreateEventSource\fR. \fICheckProc\fR must match the +following prototype: +.CS +typedef void Tcl_EventCheckProc( + ClientData \fIclientData\fR, + int \fIflags\fR); +.CE +The arguments to this procedure are the same as those for \fIsetupProc\fR. +\fBCheckProc\fR is invoked by \fBTcl_DoOneEvent\fR after it has waited +for events. Presumably at least one event source is now prepared to +queue an event. \fBTcl_DoOneEvent\fR calls each of the event sources +in turn, so they all have a chance to queue any events that are ready. +The check procedure does two things. First, it must see if any events +have triggered. Different event sources do this in different ways. +.PP +If an event source's check procedure detects an interesting event, it +must add the event to Tcl's event queue. To do this, the event source +calls \fBTcl_QueueEvent\fR. The \fIevPtr\fR argument is a pointer to +a dynamically allocated structure containing the event (see below for +more information on memory management issues). Each event source can +define its own event structure with whatever information is relevant +to that event source. However, the first element of the structure +must be a structure of type \fBTcl_Event\fR, and the address of this +structure is used when communicating between the event source and the +rest of the notifier. A \fBTcl_Event\fR has the following definition: +.CS +typedef struct { + Tcl_EventProc *\fIproc\fR; + struct Tcl_Event *\fInextPtr\fR; +} Tcl_Event; +.CE +The event source must fill in the \fIproc\fR field of +the event before calling \fBTcl_QueueEvent\fR. +The \fInextPtr\fR is used to link together the events in the queue +and should not be modified by the event source. +.PP +An event may be added to the queue at any of three positions, depending +on the \fIposition\fR argument to \fBTcl_QueueEvent\fR: +.IP \fBTCL_QUEUE_TAIL\fR 24 +Add the event at the back of the queue, so that all other pending +events will be serviced first. This is almost always the right +place for new events. +.IP \fBTCL_QUEUE_HEAD\fR 24 +Add the event at the front of the queue, so that it will be serviced +before all other queued events. +.IP \fBTCL_QUEUE_MARK\fR 24 +Add the event at the front of the queue, unless there are other +events at the front whose position is \fBTCL_QUEUE_MARK\fR; if so, +add the new event just after all other \fBTCL_QUEUE_MARK\fR events. +This value of \fIposition\fR is used to insert an ordered sequence of +events at the front of the queue, such as a series of +Enter and Leave events synthesized during a grab or ungrab operation +in Tk. +.PP +.VS 8.1 +When it is time to handle an event from the queue (steps 1 and 4 +above) \fBTcl_ServiceEvent\fR will invoke the \fIproc\fR specified +.VE +in the first queued \fBTcl_Event\fR structure. +\fIProc\fR must match the following prototype: +.CS +typedef int Tcl_EventProc( + Tcl_Event *\fIevPtr\fR, + int \fIflags\fR); +.CE +The first argument to \fIproc\fR is a pointer to the event, which will +be the same as the first argument to the \fBTcl_QueueEvent\fR call that +added the event to the queue. +The second argument to \fIproc\fR is the \fIflags\fR argument for the +.VS 8.1 +current call to \fBTcl_ServiceEvent\fR; this is used by the event source +.VE +to return immediately if its events are not relevant. +.PP +It is up to \fIproc\fR to handle the event, typically by invoking +one or more Tcl commands or C-level callbacks. +Once the event source has finished handling the event it returns 1 +to indicate that the event can be removed from the queue. +If for some reason the event source decides that the event cannot +be handled at this time, it may return 0 to indicate that the event +.VS 8.1 +should be deferred for processing later; in this case \fBTcl_ServiceEvent\fR +.VE +will go on to the next event in the queue and attempt to service it. +There are several reasons why an event source might defer an event. +One possibility is that events of this type are excluded by the +\fIflags\fR argument. +For example, the file event source will always return 0 if the +\fBTCL_FILE_EVENTS\fR bit isn't set in \fIflags\fR. +Another example of deferring events happens in Tk if +\fBTk_RestrictEvents\fR has been invoked to defer certain kinds +of window events. +.PP +.VS 8.1 +When \fIproc\fR returns 1, \fBTcl_ServiceEvent\fR will remove the +event from the event queue and free its storage. +Note that the storage for an event must be allocated by +the event source (using \fBTcl_Alloc\fR or the Tcl macro \fBckalloc\fR) +before calling \fBTcl_QueueEvent\fR, but it +will be freed by \fBTcl_ServiceEvent\fR, not by the event source. +.PP +Threaded applications work in a +similar manner, except that there is a separate event queue for +each thread containing a Tcl interpreter. +Calling \fBTcl_QueueEvent\fR in a multithreaded application adds +an event to the current thread's queue. +To add an event to another thread's queue, use \fBTcl_ThreadQueueEvent\fR. +\fBTcl_ThreadQueueEvent\fR accepts as an argument a Tcl_ThreadId argument, +which uniquely identifies a thread in a Tcl application. To obtain the +Tcl_ThreadID for the current thread, use the \fBTcl_GetCurrentThread\fR +procedure. (A thread would then need to pass this identifier to other +threads for those threads to be able to add events to its queue.) +After adding an event to another thread's queue, you then typically +need to call \fBTcl_ThreadAlert\fR to "wake up" that thread's notifier to +alert it to the new event. +.PP +\fBTcl_DeleteEvents\fR can be used to explicitly remove one or more +events from the event queue. \fBTcl_DeleteEvents\fR calls \fIproc\fR +for each event in the queue, deleting those for with the procedure +returns 1. Events for which the procedure returns 0 are left in the +queue. \fIProc\fR should match the following prototype: +.CS +typedef int Tcl_EventDeleteProc( + Tcl_Event *\fIevPtr\fR, + ClientData \fIclientData\fR); +.CE +The \fIclientData\fR argument will be the same as the \fIclientData\fR +argument to \fBTcl_DeleteEvents\fR; it is typically used to point to +private information managed by the event source. The \fIevPtr\fR will +point to the next event in the queue. +.PP +\fBTcl_DeleteEventSource\fR deletes an event source. The \fIsetupProc\fR, +\fIcheckProc\fR, and \fIclientData\fR arguments must exactly match those +provided to the \fBTcl_CreateEventSource\fR for the event source to be deleted. +If no such source exists, \fBTcl_DeleteEventSource\fR has no effect. +.VE + +.SH "CREATING A NEW NOTIFIER" +.PP +The notifier consists of all the procedures described in this manual +entry, plus \fBTcl_DoOneEvent\fR and \fBTcl_Sleep\fR, which are +.VS 8.1 +available on all platforms, and \fBTcl_CreateFileHandler\fR and +\fBTcl_DeleteFileHandler\fR, which are Unix-specific. Most of these +procedures are generic, in that they are the same for all notifiers. +However, eight of the procedures are notifier-dependent: +\fBTcl_InitNotifier\fR, \fBTcl_AlertNotifier\fR, \fBTcl_FinalizeNotifier\fR, +\fBTcl_SetTimer\fR, \fBTcl_Sleep\fR, \fBTcl_WaitForEvent\fR, +\fBTcl_CreateFileHandler\fR and \fBTcl_DeleteFileHandler\fR. To +support a new platform or to integrate Tcl with an +application-specific event loop, you must write new versions of these +procedures. +.PP +\fBTcl_InitNotifier\fR initializes the notifier state and returns +a handle to the notifier state. Tcl calls this +procedure when intializing a Tcl interpreter. Similarly, +\fBTcl_FinalizeNotifier\fR shuts down the notifier, and is +called by \fBTcl_Finalize\fR when shutting down a Tcl interpreter. +.PP +\fBTcl_WaitForEvent\fR is the lowest-level procedure in the notifier; +it is responsible for waiting for an ``interesting'' event to occur or +for a given time to elapse. Before \fBTcl_WaitForEvent\fR is invoked, +each of the event sources' setup procedure will have been invoked. +The \fItimePtr\fR argument to +\fBTcl_WaitForEvent\fR gives the maximum time to block for an event, +based on calls to \fBTcl_SetMaxBlockTime\fR made by setup procedures +and on other information (such as the \fBTCL_DONT_WAIT\fR bit in +\fIflags\fR). +.PP +Ideally, \fBTcl_WaitForEvent\fR should only wait for an event +to occur; it should not actually process the event in any way. +Later on, the +event sources will process the raw events and create Tcl_Events on +the event queue in their \fIcheckProc\fR procedures. +However, on some platforms (such as Windows) this isn't possible; +events may be processed in \fBTcl_WaitForEvent\fR, including queuing +Tcl_Events and more (for example, callbacks for native widgets may be +invoked). The return value from \fBTcl_WaitForEvent\fR must be either +0, 1, or \-1. On platforms such as Windows where events get processed in +\fBTcl_WaitForEvent\fR, a return value of 1 means that there may be more +events still pending that haven't been processed. This is a sign to the +caller that it must call \fBTcl_WaitForEvent\fR again if it wants all +pending events to be processed. A 0 return value means that calling +\fBTcl_WaitForEvent\fR again will not have any effect: either this is a +platform where \fBTcl_WaitForEvent\fR only waits without doing any event +processing, or \fBTcl_WaitForEvent\fR knows for sure that there are no +additional events to process (e.g. it returned because the time +elapsed). Finally, a return value of \-1 means that the event loop is +no longer operational and the application should probably unwind and +terminate. Under Windows this happens when a WM_QUIT message is received; +under Unix it happens when \fBTcl_WaitForEvent\fR would have waited +forever because there were no active event sources and the timeout was +infinite. +.PP +\fBTcl_AlertNotifier\fR is used in multithreaded applications to allow +any thread to "wake up" the notifier to alert it to new events on its +queue. \fBTcl_AlertNotifier\fR requires as an argument the notifier +handle returned by \fBTcl_InitNotifier\fR. +.PP +If the notifier will be used with an external event loop, then it must +also support the \fBTcl_SetTimer\fR interface. \fBTcl_SetTimer\fR is +invoked by \fBTcl_SetMaxBlockTime\fR whenever the maximum blocking +time has been reduced. \fBTcl_SetTimer\fR should arrange for the +external event loop to invoke \fBTcl_ServiceAll\fR after the specified +interval even if no events have occurred. This interface is needed +because \fBTcl_WaitForEvent\fR isn't invoked when there is an external +event loop. If the +notifier will only be used from \fBTcl_DoOneEvent\fR, then +\fBTcl_SetTimer\fR need not do anything. +.PP +On Unix systems, the file event source also needs support from the +notifier. The file event source consists of the +\fBTcl_CreateFileHandler\fR and \fBTcl_DeleteFileHandler\fR +procedures, which are described in the \fBTcl_CreateFileHandler\fR +manual page. +.PP +The \fBTcl_Sleep\fR and \fBTcl_DoOneEvent\fR interfaces are described +in their respective manual pages. +.PP +The easiest way to create a new notifier is to look at the code +for an existing notifier, such as the files \fBunix/tclUnixNotfy.c\fR +or \fBwin/tclWinNotify.c\fR in the Tcl source distribution. + +.SH "EXTERNAL EVENT LOOPS" +.PP +The notifier interfaces are designed so that Tcl can be embedded into +applications that have their own private event loops. In this case, +the application does not call \fBTcl_DoOneEvent\fR except in the case +of recursive event loops such as calls to the Tcl commands \fBupdate\fR +or \fBvwait\fR. Most of the time is spent in the external event loop +of the application. In this case the notifier must arrange for the +external event loop to call back into Tcl when something +happens on the various Tcl event sources. These callbacks should +arrange for appropriate Tcl events to be placed on the Tcl event queue. +.PP +Because the external event loop is not calling \fBTcl_DoOneEvent\fR on +a regular basis, it is up to the notifier to arrange for +\fBTcl_ServiceEvent\fR to be called whenever events are pending on the +Tcl event queue. The easiest way to do this is to invoke +\fBTcl_ServiceAll\fR at the end of each callback from the external +event loop. This will ensure that all of the event sources are +polled, any queued events are serviced, and any pending idle handlers +are processed before returning control to the application. In +addition, event sources that need to poll for events can call +\fBTcl_SetMaxBlockTime\fR to force the external event loop to call +Tcl even if no events are available on the system event queue. +.PP +As a side effect of processing events detected in the main external +event loop, Tcl may invoke \fBTcl_DoOneEvent\fR to start a recursive event +loop in commands like \fBvwait\fR. \fBTcl_DoOneEvent\fR will invoke +the external event loop, which will result in callbacks as described +in the preceding paragraph, which will result in calls to +\fBTcl_ServiceAll\fR. However, in these cases it is undesirable to +service events in \fBTcl_ServiceAll\fR. Servicing events there is +unnecessary because control will immediately return to the +external event loop and hence to \fBTcl_DoOneEvent\fR, which can +service the events itself. Furthermore, \fBTcl_DoOneEvent\fR is +supposed to service only a single event, whereas \fBTcl_ServiceAll\fR +normally services all pending events. To handle this situation, +\fBTcl_DoOneEvent\fR sets a flag for \fBTcl_ServiceAll\fR +that causes it to return without servicing any events. +This flag is called the \fIservice mode\fR; +\fBTcl_DoOneEvent\fR restores it to its previous value before it returns. +.PP +In some cases, however, it may be necessary for \fBTcl_ServiceAll\fR +to service events +even when it has been invoked from \fBTcl_DoOneEvent\fR. This happens +when there is yet another recursive event loop invoked via an +event handler called by \fBTcl_DoOneEvent\fR (such as one that is +part of a native widget). In this case, \fBTcl_DoOneEvent\fR may not +have a chance to service events so \fBTcl_ServiceAll\fR must service +them all. Any recursive event loop that calls an external event +loop rather than \fBTcl_DoOneEvent\fR must reset the service mode so +that all events get processed in \fBTcl_ServiceAll\fR. This is done +by invoking the \fBTcl_SetServiceMode\fR procedure. If +\fBTcl_SetServiceMode\fR is passed \fBTCL_SERVICE_NONE\fR, then calls +to \fBTcl_ServiceAll\fR will return immediately without processing any +events. If \fBTcl_SetServiceMode\fR is passed \fBTCL_SERVICE_ALL\fR, +then calls to \fBTcl_ServiceAll\fR will behave normally. +\fBTcl_SetServiceMode\fR returns the previous value of the service +mode, which should be restored when the recursive loop exits. +\fBTcl_GetServiceMode\fR returns the current value of the service +mode. +.VE +.SH "SEE ALSO" +\fBTcl_CreateFileHandler\fR, \fBTcl_DeleteFileHandler\fR, \fBTcl_Sleep\fR, +\fBTcl_DoOneEvent\fR, \fBThread(3)\fR +.SH KEYWORDS +event, notifier, event queue, event sources, file events, timer, idle, service mode, threads diff --git a/mk4/modtcl/tcl8.3.4/doc/Object.3 b/mk4/modtcl/tcl8.3.4/doc/Object.3 new file mode 100644 index 0000000..f91e79b --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/Object.3 @@ -0,0 +1,337 @@ +'\" +'\" Copyright (c) 1996-1997 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: Object.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_Obj 3 8.0 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_NewObj, Tcl_DuplicateObj, Tcl_IncrRefCount, Tcl_DecrRefCount, Tcl_IsShared, Tcl_InvalidateStringRep \- manipulate Tcl objects +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +Tcl_Obj * +\fBTcl_NewObj\fR() +.sp +Tcl_Obj * +\fBTcl_DuplicateObj\fR(\fIobjPtr\fR) +.sp +\fBTcl_IncrRefCount\fR(\fIobjPtr\fR) +.sp +\fBTcl_DecrRefCount\fR(\fIobjPtr\fR) +.sp +int +\fBTcl_IsShared\fR(\fIobjPtr\fR) +.sp +\fBTcl_InvalidateStringRep\fR(\fIobjPtr\fR) +.SH ARGUMENTS +.AS Tcl_Obj *objPtr in +.AP Tcl_Obj *objPtr in +Points to an object; +must have been the result of a previous call to \fBTcl_NewObj\fR. +.BE + +.SH INTRODUCTION +.PP +This man page presents an overview of Tcl objects and how they are used. +It also describes generic procedures for managing Tcl objects. +These procedures are used to create and copy objects, +and increment and decrement the count of references (pointers) to objects. +The procedures are used in conjunction with ones +that operate on specific types of objects such as +\fBTcl_GetIntFromObj\fR and \fBTcl_ListObjAppendElement\fR. +The individual procedures are described along with the data structures +they manipulate. +.PP +Tcl's \fIdual-ported\fR objects provide a general-purpose mechanism +for storing and exchanging Tcl values. +They largely replace the use of strings in Tcl. +For example, they are used to store variable values, +command arguments, command results, and scripts. +Tcl objects behave like strings but also hold an internal representation +that can be manipulated more efficiently. +For example, a Tcl list is now represented as an object +that holds the list's string representation +as well as an array of pointers to the objects for each list element. +Dual-ported objects avoid most runtime type conversions. +They also improve the speed of many operations +since an appropriate representation is immediately available. +The compiler itself uses Tcl objects to +cache the instruction bytecodes resulting from compiling scripts. +.PP +The two representations are a cache of each other and are computed lazily. +That is, each representation is only computed when necessary, +it is computed from the other representation, +and, once computed, it is saved. +In addition, a change in one representation invalidates the other one. +As an example, a Tcl program doing integer calculations can +operate directly on a variable's internal machine integer +representation without having to constantly convert +between integers and strings. +Only when it needs a string representing the variable's value, +say to print it, +will the program regenerate the string representation from the integer. +Although objects contain an internal representation, +their semantics are defined in terms of strings: +an up-to-date string can always be obtained, +and any change to the object will be reflected in that string +when the object's string representation is fetched. +Because of this representation invalidation and regeneration, +it is dangerous for extension writers to access +\fBTcl_Obj\fR fields directly. +It is better to access Tcl_Obj information using +procedures like \fBTcl_GetStringFromObj\fR and \fBTcl_GetString\fR. +.PP +Objects are allocated on the heap +and are referenced using a pointer to their \fBTcl_Obj\fR structure. +Objects are shared as much as possible. +This significantly reduces storage requirements +because some objects such as long lists are very large. +Also, most Tcl values are only read and never modified. +This is especially true for procedure arguments, +which can be shared between the caller and the called procedure. +Assignment and argument binding is done by +simply assigning a pointer to the value. +Reference counting is used to determine when it is safe to +reclaim an object's storage. +.PP +Tcl objects are typed. +An object's internal representation is controlled by its type. +Seven types are predefined in the Tcl core +including integer, double, list, and bytecode. +Extension writers can extend the set of types +by using the procedure \fBTcl_RegisterObjType\fR . + +.SH "THE TCL_OBJ STRUCTURE" +.PP +Each Tcl object is represented by a \fBTcl_Obj\fR structure +which is defined as follows. +.CS +typedef struct Tcl_Obj { + int \fIrefCount\fR; + char *\fIbytes\fR; + int \fIlength\fR; + Tcl_ObjType *\fItypePtr\fR; + union { + long \fIlongValue\fR; + double \fIdoubleValue\fR; + VOID *\fIotherValuePtr\fR; + struct { + VOID *\fIptr1\fR; + VOID *\fIptr2\fR; + } \fItwoPtrValue\fR; + } \fIinternalRep\fR; +} Tcl_Obj; +.CE +The \fIbytes\fR and the \fIlength\fR members together hold +an object's string representation, +which is a \fIcounted\fR or \fIbinary string\fR +that may contain binary data with embedded null bytes. +\fIbytes\fR points to the first byte of the string representation. +The \fIlength\fR member gives the number of bytes. +The byte array must always have a null after the last byte, +at offset \fIlength\fR; +this allows string representations that do not contain nulls +to be treated as conventional null-terminated C strings. +C programs use \fBTcl_GetStringFromObj\fR and \fBTcl_GetString\fR to get +an object's string representation. +If \fIbytes\fR is NULL, +the string representation is invalid. +.PP +An object's type manages its internal representation. +The member \fItypePtr\fR points to the Tcl_ObjType structure +that describes the type. +If \fItypePtr\fR is NULL, +the internal representation is invalid. +.PP +The \fIinternalRep\fR union member holds +an object's internal representation. +This is either a (long) integer, a double-precision floating point number, +a pointer to a value containing additional information +needed by the object's type to represent the object, +or two arbitrary pointers. +.PP +The \fIrefCount\fR member is used to tell when it is safe to free +an object's storage. +It holds the count of active references to the object. +Maintaining the correct reference count is a key responsibility +of extension writers. +Reference counting is discussed below +in the section \fBSTORAGE MANAGEMENT OF OBJECTS\fR. +.PP +Although extension writers can directly access +the members of a Tcl_Obj structure, +it is much better to use the appropriate procedures and macros. +For example, extension writers should never +read or update \fIrefCount\fR directly; +they should use macros such as +\fBTcl_IncrRefCount\fR and \fBTcl_IsShared\fR instead. +.PP +A key property of Tcl objects is that they hold two representations. +An object typically starts out containing only a string representation: +it is untyped and has a NULL \fItypePtr\fR. +An object containing an empty string or a copy of a specified string +is created using \fBTcl_NewObj\fR or \fBTcl_NewStringObj\fR respectively. +An object's string value is gotten with +\fBTcl_GetStringFromObj\fR or \fBTcl_GetString\fR +and changed with \fBTcl_SetStringObj\fR. +If the object is later passed to a procedure like \fBTcl_GetIntFromObj\fR +that requires a specific internal representation, +the procedure will create one and set the object's \fItypePtr\fR. +The internal representation is computed from the string representation. +An object's two representations are duals of each other: +changes made to one are reflected in the other. +For example, \fBTcl_ListObjReplace\fR will modify an object's +internal representation and the next call to \fBTcl_GetStringFromObj\fR +or \fBTcl_GetString\fR will reflect that change. +.PP +Representations are recomputed lazily for efficiency. +A change to one representation made by a procedure +such as \fBTcl_ListObjReplace\fR is not reflected immediately +in the other representation. +Instead, the other representation is marked invalid +so that it is only regenerated if it is needed later. +Most C programmers never have to be concerned with how this is done +and simply use procedures such as \fBTcl_GetBooleanFromObj\fR or +\fBTcl_ListObjIndex\fR. +Programmers that implement their own object types +must check for invalid representations +and mark representations invalid when necessary. +The procedure \fBTcl_InvalidateStringRep\fR is used +to mark an object's string representation invalid and to +free any storage associated with the old string representation. +.PP +Objects usually remain one type over their life, +but occasionally an object must be converted from one type to another. +For example, a C program might build up a string in an object +with repeated calls to \fBTcl_AppendToObj\fR, +and then call \fBTcl_ListObjIndex\fR to extract a list element from +the object. +The same object holding the same string value +can have several different internal representations +at different times. +Extension writers can also force an object to be converted from one type +to another using the \fBTcl_ConvertToType\fR procedure. +Only programmers that create new object types need to be concerned +about how this is done. +A procedure defined as part of the object type's implementation +creates a new internal representation for an object +and changes its \fItypePtr\fR. +See the man page for \fBTcl_RegisterObjType\fR +to see how to create a new object type. + +.SH "EXAMPLE OF THE LIFETIME OF AN OBJECT" +.PP +As an example of the lifetime of an object, +consider the following sequence of commands: +.CS +\fBset x 123\fR +.CE +This assigns to \fIx\fR an untyped object whose +\fIbytes\fR member points to \fB123\fR and \fIlength\fR member contains 3. +The object's \fItypePtr\fR member is NULL. +.CS +\fBputs "x is $x"\fR +.CE +\fIx\fR's string representation is valid (since \fIbytes\fR is non-NULL) +and is fetched for the command. +.CS +\fBincr x\fR +.CE +The \fBincr\fR command first gets an integer from \fIx\fR's object +by calling \fBTcl_GetIntFromObj\fR. +This procedure checks whether the object is already an integer object. +Since it is not, it converts the object +by setting the object's \fIinternalRep.longValue\fR member +to the integer \fB123\fR +and setting the object's \fItypePtr\fR +to point to the integer Tcl_ObjType structure. +Both representations are now valid. +\fBincr\fR increments the object's integer internal representation +then invalidates its string representation +(by calling \fBTcl_InvalidateStringRep\fR) +since the string representation +no longer corresponds to the internal representation. +.CS +\fBputs "x is now $x"\fR +.CE +The string representation of \fIx\fR's object is needed +and is recomputed. +The string representation is now \fB124\fR. +and both representations are again valid. + +.SH "STORAGE MANAGEMENT OF OBJECTS" +.PP +Tcl objects are allocated on the heap and are shared as much as possible +to reduce storage requirements. +Reference counting is used to determine when an object is +no longer needed and can safely be freed. +An object just created by \fBTcl_NewObj\fR or \fBTcl_NewStringObj\fR +has \fIrefCount\fR 0. +The macro \fBTcl_IncrRefCount\fR increments the reference count +when a new reference to the object is created. +The macro \fBTcl_DecrRefCount\fR decrements the count +when a reference is no longer needed and, +if the object's reference count drops to zero, frees its storage. +An object shared by different code or data structures has +\fIrefCount\fR greater than 1. +Incrementing an object's reference count ensures that +it won't be freed too early or have its value change accidently. +.PP +As an example, the bytecode interpreter shares argument objects +between calling and called Tcl procedures to avoid having to copy objects. +It assigns the call's argument objects to the procedure's +formal parameter variables. +In doing so, it calls \fBTcl_IncrRefCount\fR to increment +the reference count of each argument since there is now a new +reference to it from the formal parameter. +When the called procedure returns, +the interpreter calls \fBTcl_DecrRefCount\fR to decrement +each argument's reference count. +When an object's reference count drops less than or equal to zero, +\fBTcl_DecrRefCount\fR reclaims its storage. +Most command procedures do not have to be concerned about +reference counting since they use an object's value immediately +and don't retain a pointer to the object after they return. +However, if they do retain a pointer to an object in a data structure, +they must be careful to increment its reference count +since the retained pointer is a new reference. +.PP +Command procedures that directly modify objects +such as those for \fBlappend\fR and \fBlinsert\fR must be careful to +copy a shared object before changing it. +They must first check whether the object is shared +by calling \fBTcl_IsShared\fR. +If the object is shared they must copy the object +by using \fBTcl_DuplicateObj\fR; +this returns a new duplicate of the original object +that has \fIrefCount\fR 0. +If the object is not shared, +the command procedure "owns" the object and can safely modify it directly. +For example, the following code appears in the command procedure +that implements \fBlinsert\fR. +This procedure modifies the list object passed to it in \fIobjv[1]\fR +by inserting \fIobjc-3\fR new elements before \fIindex\fR. +.CS +listPtr = objv[1]; +if (Tcl_IsShared(listPtr)) { + listPtr = Tcl_DuplicateObj(listPtr); +} +result = Tcl_ListObjReplace(interp, listPtr, index, 0, (objc-3), &(objv[3])); +.CE +As another example, \fBincr\fR's command procedure +must check whether the variable's object is shared before +incrementing the integer in its internal representation. +If it is shared, it needs to duplicate the object +in order to avoid accidently changing values in other data structures. + +.SH "SEE ALSO" +Tcl_ConvertToType, Tcl_GetIntFromObj, Tcl_ListObjAppendElement, Tcl_ListObjIndex, Tcl_ListObjReplace, Tcl_RegisterObjType + +.SH KEYWORDS +internal representation, object, object creation, object type, reference counting, string representation, type conversion diff --git a/mk4/modtcl/tcl8.3.4/doc/ObjectType.3 b/mk4/modtcl/tcl8.3.4/doc/ObjectType.3 new file mode 100644 index 0000000..aa9113a --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/ObjectType.3 @@ -0,0 +1,198 @@ +'\" +'\" Copyright (c) 1996-1997 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: ObjectType.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_ObjType 3 8.0 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_RegisterObjType, Tcl_GetObjType, Tcl_AppendAllObjTypes, Tcl_ConvertToType \- manipulate Tcl object types +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +\fBTcl_RegisterObjType\fR(\fItypePtr\fR) +.sp +Tcl_ObjType * +\fBTcl_GetObjType\fR(\fItypeName\fR) +.sp +int +\fBTcl_AppendAllObjTypes\fR(\fIinterp, objPtr\fR) +.sp +int +\fBTcl_ConvertToType\fR(\fIinterp, objPtr, typePtr\fR) +.SH ARGUMENTS +.AS Tcl_ObjType *typeName in +.AP Tcl_ObjType *typePtr in +Points to the structure containing information about the Tcl object type. +This storage must must live forever, +typically by being statically allocated. +.AP char *typeName in +The name of a Tcl object type that \fBTcl_GetObjType\fR should look up. +.AP Tcl_Interp *interp in +Interpreter to use for error reporting. +.AP Tcl_Obj *objPtr in +For \fBTcl_AppendAllObjTypes\fR, this points to the object onto which +it appends the name of each object type as a list element. +For \fBTcl_ConvertToType\fR, this points to an object that +must have been the result of a previous call to \fBTcl_NewObj\fR. +.BE + +.SH DESCRIPTION +.PP +The procedures in this man page manage Tcl object types. +The are used to register new object types, +look up types, +and force conversions from one type to another. +.PP +\fBTcl_RegisterObjType\fR registers a new Tcl object type +in the table of all object types supported by Tcl. +The argument \fItypePtr\fR points to a Tcl_ObjType structure that +describes the new type by giving its name +and by supplying pointers to four procedures +that implement the type. +If the type table already contains a type +with the same name as in \fItypePtr\fR, +it is replaced with the new type. +The Tcl_ObjType structure is described +in the section \fBTHE TCL_OBJTYPE STRUCTURE\fR below. +.PP +\fBTcl_GetObjType\fR returns a pointer to the Tcl_ObjType +with name \fItypeName\fR. +It returns NULL if no type with that name is registered. +.PP +\fBTcl_AppendAllObjTypes\fR appends the name of each object type +as a list element onto the Tcl object referenced by \fIobjPtr\fR. +The return value is \fBTCL_OK\fR unless there was an error +converting \fIobjPtr\fR to a list object; +in that case \fBTCL_ERROR\fR is returned. +.PP +\fBTcl_ConvertToType\fR converts an object from one type to another +if possible. +It creates a new internal representation for \fIobjPtr\fR +appropriate for the target type \fItypePtr\fR +and sets its \fItypePtr\fR member to that type. +Any internal representation for \fIobjPtr\fR's old type is freed. +If an error occurs during conversion, it returns \fBTCL_ERROR\fR +and leaves an error message in the result object for \fIinterp\fR +unless \fIinterp\fR is NULL. +Otherwise, it returns \fBTCL_OK\fR. +Passing a NULL \fIinterp\fR allows this procedure to be used +as a test whether the conversion can be done (and in fact was done). + +.SH "THE TCL_OBJTYPE STRUCTURE" +.PP +Extension writers can define new object types by defining four +procedures, +initializing a Tcl_ObjType structure to describe the type, +and calling \fBTcl_RegisterObjType\fR. +The \fBTcl_ObjType\fR structure is defined as follows: +.CS +typedef struct Tcl_ObjType { + char *\fIname\fR; + Tcl_FreeInternalRepProc *\fIfreeIntRepProc\fR; + Tcl_DupInternalRepProc *\fIdupIntRepProc\fR; + Tcl_UpdateStringProc *\fIupdateStringProc\fR; + Tcl_SetFromAnyProc *\fIsetFromAnyProc\fR; +} Tcl_ObjType; +.CE +.PP +The \fIname\fR member describes the name of the type, e.g. \fBint\fR. +Extension writers can look up an object type using its name +with the \fBTcl_GetObjType\fR procedure. +The remaining four members are pointers to procedures +called by the generic Tcl object code: +.PP +The \fIsetFromAnyProc\fR member contains the address of a function +called to create a valid internal representation +from an object's string representation. +.CS +typedef int (Tcl_SetFromAnyProc) (Tcl_Interp *\fIinterp\fR, Tcl_Obj *\fIobjPtr\fR); +.CE +If an internal representation can't be created from the string, +it returns \fBTCL_ERROR\fR and puts a message +describing the error in the result object for \fIinterp\fR +unless \fIinterp\fR is NULL. +If \fIsetFromAnyProc\fR is successful, +it stores the new internal representation, +sets \fIobjPtr\fR's \fItypePtr\fR member to point to +\fIsetFromAnyProc\fR's \fBTcl_ObjType\fR, and returns \fBTCL_OK\fR. +Before setting the new internal representation, +the \fIsetFromAnyProc\fR must free any internal representation +of \fIobjPtr\fR's old type; +it does this by calling the old type's \fIfreeIntRepProc\fR +if it is not NULL. +As an example, the \fIsetFromAnyProc\fR for the builtin Tcl integer type +gets an up-to-date string representation for \fIobjPtr\fR +by calling \fBTcl_GetStringFromObj\fR. +It parses the string to obtain an integer and, +if this succeeds, +stores the integer in \fIobjPtr\fR's internal representation +and sets \fIobjPtr\fR's \fItypePtr\fR member to point to the integer type's +Tcl_ObjType structure. +.PP +The \fIupdateStringProc\fR member contains the address of a function +called to create a valid string representation +from an object's internal representation. +.CS +typedef void (Tcl_UpdateStringProc) (Tcl_Obj *\fIobjPtr\fR); +.CE +\fIobjPtr\fR's \fIbytes\fR member is always NULL when it is called. +It must always set \fIbytes\fR non-NULL before returning. +We require the string representation's byte array +to have a null after the last byte, at offset \fIlength\fR; +this allows string representations that do not contain null bytes +to be treated as conventional null character-terminated C strings. +Storage for the byte array must be allocated in the heap by \fBTcl_Alloc\fR. +Note that \fIupdateStringProc\fRs must allocate +enough storage for the string's bytes and the terminating null byte. +The \fIupdateStringProc\fR for Tcl's builtin list type, for example, +builds an array of strings for each element object +and then calls \fBTcl_Merge\fR +to construct a string with proper Tcl list structure. +It stores this string as the list object's string representation. +.PP +The \fIdupIntRepProc\fR member contains the address of a function +called to copy an internal representation from one object to another. +.CS +typedef void (Tcl_DupInternalRepProc) (Tcl_Obj *\fIsrcPtr\fR, Tcl_Obj *\fIdupPtr\fR); +.CE +\fIdupPtr\fR's internal representation is made a copy of \fIsrcPtr\fR's +internal representation. +Before the call, +\fIsrcPtr\fR's internal representation is valid and \fIdupPtr\fR's is not. +\fIsrcPtr\fR's object type determines what +copying its internal representation means. +For example, the \fIdupIntRepProc\fR for the Tcl integer type +simply copies an integer. +The builtin list type's \fIdupIntRepProc\fR +allocates a new array that points at the original element objects; +the elements are shared between the two lists +(and their reference counts are incremented to reflect the new references). +.PP +The \fIfreeIntRepProc\fR member contains the address of a function +that is called when an object is freed. +.CS +typedef void (Tcl_FreeInternalRepProc) (Tcl_Obj *\fIobjPtr\fR); +.CE +The \fIfreeIntRepProc\fR function can deallocate the storage +for the object's internal representation +and do other type-specific processing necessary when an object is freed. +For example, Tcl list objects have an \fIinternalRep.otherValuePtr\fR +that points to an array of pointers to each element in the list. +The list type's \fIfreeIntRepProc\fR decrements +the reference count for each element object +(since the list will no longer refer to those objects), +then deallocates the storage for the array of pointers. +The \fIfreeIntRepProc\fR member can be set to NULL +to indicate that the internal representation does not require freeing. + +.SH "SEE ALSO" +Tcl_NewObj, Tcl_DecrRefCount, Tcl_IncrRefCount + +.SH KEYWORDS +internal representation, object, object type, string representation, type conversion diff --git a/mk4/modtcl/tcl8.3.4/doc/OpenFileChnl.3 b/mk4/modtcl/tcl8.3.4/doc/OpenFileChnl.3 new file mode 100644 index 0000000..5b43067 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/OpenFileChnl.3 @@ -0,0 +1,607 @@ +'\" +'\" Copyright (c) 1996-1997 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: OpenFileChnl.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +.so man.macros +.TH Tcl_OpenFileChannel 3 8.3 Tcl "Tcl Library Procedures" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +Tcl_OpenFileChannel, Tcl_OpenCommandChannel, Tcl_MakeFileChannel, Tcl_GetChannel, Tcl_GetChannelNames, Tcl_GetChannelNamesEx, Tcl_RegisterChannel, Tcl_UnregisterChannel, Tcl_Close, Tcl_ReadChars, Tcl_Read, Tcl_GetsObj, Tcl_Gets, Tcl_WriteObj, Tcl_WriteChars, Tcl_Write, Tcl_Flush, Tcl_Seek, Tcl_Tell, Tcl_GetChannelOption, Tcl_SetChannelOption, Tcl_Eof, Tcl_InputBlocked, Tcl_InputBuffered, Tcl_Ungets \- buffered I/O facilities using channels +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +typedef ... Tcl_Channel; +.sp +Tcl_Channel +\fBTcl_OpenFileChannel\fR(\fIinterp, fileName, mode, permissions\fR) +.sp +Tcl_Channel +\fBTcl_OpenCommandChannel\fR(\fIinterp, argc, argv, flags\fR) +.VS 8.0 +.sp +Tcl_Channel +\fBTcl_MakeFileChannel\fR(\fIhandle, readOrWrite\fR) +.VE +.sp +Tcl_Channel +\fBTcl_GetChannel\fR(\fIinterp, channelName, modePtr\fR) +.VS 8.3 +.sp +int +\fBTcl_GetChannelNames\fR(\fIinterp\fR) +.sp +int +\fBTcl_GetChannelNamesEx\fR(\fIinterp, pattern\fR) +.VE +.sp +void +\fBTcl_RegisterChannel\fR(\fIinterp, channel\fR) +.sp +int +\fBTcl_UnregisterChannel\fR(\fIinterp, channel\fR) +.sp +int +\fBTcl_Close\fR(\fIinterp, channel\fR) +.sp +.VS 8.1 +int +\fBTcl_ReadChars\fR(\fIchannel, readObjPtr, charsToRead, appendFlag\fR) +.sp +int +\fBTcl_Read\fR(\fIchannel, byteBuf, bytesToRead\fR) +.sp +int +\fBTcl_GetsObj\fR(\fIchannel, lineObjPtr\fR) +.sp +int +\fBTcl_Gets\fR(\fIchannel, lineRead\fR) +.sp +int +\fBTcl_Ungets\fR(\fIchannel, input, inputLen, addAtEnd\fR) +.sp +int +\fBTcl_WriteObj\fR(\fIchannel, writeObjPtr\fR) +.sp +int +\fBTcl_WriteChars\fR(\fIchannel, charBuf, bytesToWrite\fR) +.sp +int +\fBTcl_Write\fR(\fIchannel, byteBuf, bytesToWrite\fR) +.VE +.sp +int +\fBTcl_Eof\fR(\fIchannel\fR) +.sp +int +\fBTcl_Flush\fR(\fIchannel\fR) +.sp +int +\fBTcl_InputBlocked\fR(\fIchannel\fR) +.sp +int +\fBTcl_InputBuffered\fR(\fIchannel\fR) +.sp +int +\fBTcl_Seek\fR(\fIchannel, offset, seekMode\fR) +.sp +int +\fBTcl_Tell\fR(\fIchannel\fR) +.sp +int +\fBTcl_GetChannelOption\fR(\fIinterp, channel, optionName, optionValue\fR) +.sp +int +\fBTcl_SetChannelOption\fR(\fIinterp, channel, optionName, newValue\fR) +.sp +.SH ARGUMENTS +.AS Tcl_ChannelType newClientProcPtr in +.AP Tcl_Interp *interp in +Used for error reporting and to look up a channel registered in it. +.AP char *fileName in +The name of a local or network file. +.AP char *mode in +Specifies how the file is to be accessed. May have any of the values +allowed for the \fImode\fR argument to the Tcl \fBopen\fR command. For +\fBTcl_OpenCommandChannel\fR, may be NULL. +.AP int permissions in +POSIX-style permission flags such as 0644. If a new file is created, these +permissions will be set on the created file. +.AP int argc in +The number of elements in \fIargv\fR. +.AP char **argv in +Arguments for constructing a command pipeline. These values have the same +meaning as the non-switch arguments to the Tcl \fBexec\fR command. +.AP int flags in +Specifies the disposition of the stdio handles in pipeline: OR-ed +combination of \fBTCL_STDIN\fR, \fBTCL_STDOUT\fR, \fBTCL_STDERR\fR, and +\fBTCL_ENFORCE_MODE\fR. If \fBTCL_STDIN\fR is set, stdin for the first child +in the pipe is the pipe channel, otherwise it is the same as the standard +input of the invoking process; likewise for \fBTCL_STDOUT\fR and +\fBTCL_STDERR\fR. If \fBTCL_ENFORCE_MODE\fR is not set, then the pipe can +redirect stdio handles to override the stdio handles for which +\fBTCL_STDIN\fR, \fBTCL_STDOUT\fR and \fBTCL_STDERR\fR have been set. If it +is set, then such redirections cause an error. +.VS 8.0 +.AP ClientData handle in +Operating system specific handle for I/O to a file. For Unix this is a +file descriptor, for Windows it is a HANDLE. +.AP int readOrWrite in +OR-ed combination of \fBTCL_READABLE\fR and \fBTCL_WRITABLE\fR to indicate +what operations are valid on \fIhandle\fR. +.AP char *channelName in +The name of the channel. +.VE +.AP int *modePtr out +Points at an integer variable that will receive an OR-ed combination of +\fBTCL_READABLE\fR and \fBTCL_WRITABLE\fR denoting whether the channel is +open for reading and writing. +.AP Tcl_Channel channel in +A Tcl channel for input or output. Must have been the return value +from a procedure such as \fBTcl_OpenFileChannel\fR. +.VS 8.1 br +.AP Tcl_Obj *readObjPtr in/out +A pointer to a Tcl Object in which to store the characters read from the +channel. +.AP int charsToRead in +The number of characters to read from the channel. If the channel's encoding +is \fBbinary\fR, this is equivalent to the number of bytes to read from the +channel. +.AP int appendFlag in +If non-zero, data read from the channel will be appended to the object. +Otherwise, the data will replace the existing contents of the object. +.AP char *readBuf out +A buffer in which to store the bytes read from the channel. +.AP int bytesToRead in +The number of bytes to read from the channel. The buffer \fIreadBuf\fR must +be large enough to hold this many bytes. +.AP Tcl_Obj *lineObjPtr in/out +A pointer to a Tcl object in which to store the line read from the +channel. The line read will be appended to the current value of the +object. +.AP Tcl_DString *lineRead in/out +A pointer to a Tcl dynamic string in which to store the line read from the +channel. Must have been initialized by the caller. The line read will be +appended to any data already in the dynamic string. +.AP Tcl_Obj *writeObjPtr in +A pointer to a Tcl Object whose contents will be output to the channel. +.AP "CONST char" *charBuf in +A buffer containing the characters to output to the channel. +.AP char *byteBuf in +A buffer containing the bytes to output to the channel. +.AP int bytesToWrite in +The number of bytes to consume from \fIcharBuf\fR or \fIbyteBuf\fR and +output to the channel. +.VE +.AP int offset in +How far to move the access point in the channel at which the next input or +output operation will be applied, measured in bytes from the position +given by \fIseekMode\fR. May be either positive or negative. +.AP int seekMode in +Relative to which point to seek; used with \fIoffset\fR to calculate the new +access point for the channel. Legal values are \fBSEEK_SET\fR, +\fBSEEK_CUR\fR, and \fBSEEK_END\fR. +.AP char *optionName in +The name of an option applicable to this channel, such as \fB\-blocking\fR. +May have any of the values accepted by the \fBfconfigure\fR command. +.AP Tcl_DString *optionValue in +Where to store the value of an option or a list of all options and their +values. Must have been initialized by the caller. +.AP char *newValue in +New value for the option given by \fIoptionName\fR. +.VS 8.3 +.AP char *pattern in +The pattern to match on, passed to Tcl_StringMatch, or NULL. +.AP char *input in +The input to add to a channel buffer. +.AP int inputLen in +Length of the input +.AP int addToEnd in +Flag indicating whether the input should be added to the end or +beginning of the channel buffer. +.VE +.BE + +.SH DESCRIPTION +.PP +The Tcl channel mechanism provides a device-independent and +platform-independent mechanism for performing buffered input +and output operations on a variety of file, socket, and device +types. +The channel mechanism is extensible to new channel types, by +providing a low level channel driver for the new type; the channel driver +interface is described in the manual entry for \fBTcl_CreateChannel\fR. The +channel mechanism provides a buffering scheme modeled after +Unix's standard I/O, and it also allows for nonblocking I/O on +channels. +.PP +The procedures described in this manual entry comprise the C APIs of the +generic layer of the channel architecture. For a description of the channel +driver architecture and how to implement channel drivers for new types of +channels, see the manual entry for \fBTcl_CreateChannel\fR. + +.SH TCL_OPENFILECHANNEL +.PP +\fBTcl_OpenFileChannel\fR opens a file specified by \fIfileName\fR and +returns a channel handle that can be used to perform input and output on +the file. This API is modeled after the \fBfopen\fR procedure of +the Unix standard I/O library. +The syntax and meaning of all arguments is similar to those +given in the Tcl \fBopen\fR command when opening a file. +If an error occurs while opening the channel, \fBTcl_OpenFileChannel\fR +returns NULL and records a POSIX error code that can be +retrieved with \fBTcl_GetErrno\fR. +In addition, if \fIinterp\fR is non-NULL, \fBTcl_OpenFileChannel\fR +leaves an error message in \fIinterp\fR's result after any error. +.PP +The newly created channel is not registered in the supplied interpreter; to +register it, use \fBTcl_RegisterChannel\fR, described below. +If one of the standard channels, \fBstdin, stdout\fR or \fBstderr\fR was +previously closed, the act of creating the new channel also assigns it as a +replacement for the standard channel. + +.SH TCL_OPENCOMMANDCHANNEL +.PP +\fBTcl_OpenCommandChannel\fR provides a C-level interface to the +functions of the \fBexec\fR and \fBopen\fR commands. +It creates a sequence of subprocesses specified +by the \fIargv\fR and \fIargc\fR arguments and returns a channel that can +be used to communicate with these subprocesses. +The \fIflags\fR argument indicates what sort of communication will +exist with the command pipeline. +.PP +If the \fBTCL_STDIN\fR flag is set then the standard input for the +first subprocess will be tied to the channel: writing to the channel +will provide input to the subprocess. If \fBTCL_STDIN\fR is not set, +then standard input for the first subprocess will be the same as this +application's standard input. If \fBTCL_STDOUT\fR is set then +standard output from the last subprocess can be read from the channel; +otherwise it goes to this application's standard output. If +\fBTCL_STDERR\fR is set, standard error output for all subprocesses is +returned to the channel and results in an error when the channel is +closed; otherwise it goes to this application's standard error. If +\fBTCL_ENFORCE_MODE\fR is not set, then \fIargc\fR and \fIargv\fR can +redirect the stdio handles to override \fBTCL_STDIN\fR, +\fBTCL_STDOUT\fR, and \fBTCL_STDERR\fR; if it is set, then it is an +error for argc and argv to override stdio channels for which +\fBTCL_STDIN\fR, \fBTCL_STDOUT\fR, and \fBTCL_STDERR\fR have been set. +.PP +If an error occurs while opening the channel, \fBTcl_OpenCommandChannel\fR +returns NULL and records a POSIX error code that can be retrieved with +\fBTcl_GetErrno\fR. +In addition, \fBTcl_OpenCommandChannel\fR leaves an error message in +the interpreter's result if \fIinterp\fR is not NULL. +.PP +The newly created channel is not registered in the supplied interpreter; to +register it, use \fBTcl_RegisterChannel\fR, described below. +If one of the standard channels, \fBstdin, stdout\fR or \fBstderr\fR was +previously closed, the act of creating the new channel also assigns it as a +replacement for the standard channel. + +.SH TCL_MAKEFILECHANNEL +.PP +\fBTcl_MakeFileChannel\fR makes a \fBTcl_Channel\fR from an existing, +platform-specific, file handle. +The newly created channel is not registered in the supplied interpreter; to +register it, use \fBTcl_RegisterChannel\fR, described below. +If one of the standard channels, \fBstdin, stdout\fR or \fBstderr\fR was +previously closed, the act of creating the new channel also assigns it as a +replacement for the standard channel. + +.SH TCL_GETCHANNEL +.PP +\fBTcl_GetChannel\fR returns a channel given the \fIchannelName\fR used to +create it with \fBTcl_CreateChannel\fR and a pointer to a Tcl interpreter in +\fIinterp\fR. If a channel by that name is not registered in that interpreter, +the procedure returns NULL. If the \fImode\fR argument is not NULL, it +points at an integer variable that will receive an OR-ed combination of +\fBTCL_READABLE\fR and \fBTCL_WRITABLE\fR describing whether the channel is +open for reading and writing. +.PP +\fBTcl_GetChannelNames\fR and \fBTcl_GetChannelNamesEx\fR write the +names of the registered channels to the interpreter's result as a +list object. \fBTcl_GetChannelNamesEx\fR will filter these names +according to the \fIpattern\fR. If \fIpattern\fR is NULL, then it +will not do any filtering. The return value is \fBTCL_OK\fR if no +errors occured writing to the result, otherwise it is \fBTCL_ERROR\fR, +and the error message is left in the interpreter's result. + +.SH TCL_REGISTERCHANNEL +.PP +\fBTcl_RegisterChannel\fR adds a channel to the set of channels accessible +in \fIinterp\fR. After this call, Tcl programs executing in that +interpreter can refer to the channel in input or output operations using +the name given in the call to \fBTcl_CreateChannel\fR. After this call, +the channel becomes the property of the interpreter, and the caller should +not call \fBTcl_Close\fR for the channel; the channel will be closed +automatically when it is unregistered from the interpreter. +.PP +Code executing outside of any Tcl interpreter can call +\fBTcl_RegisterChannel\fR with \fIinterp\fR as NULL, to indicate that it +wishes to hold a reference to this channel. Subsequently, the channel can +be registered in a Tcl interpreter and it will only be closed when the +matching number of calls to \fBTcl_UnregisterChannel\fR have been made. +This allows code executing outside of any interpreter to safely hold a +reference to a channel that is also registered in a Tcl interpreter. + +.SH TCL_UNREGISTERCHANNEL +.PP +\fBTcl_UnregisterChannel\fR removes a channel from the set of channels +accessible in \fIinterp\fR. After this call, Tcl programs will no longer be +able to use the channel's name to refer to the channel in that interpreter. +If this operation removed the last registration of the channel in any +interpreter, the channel is also closed and destroyed. +.PP +Code not associated with a Tcl interpreter can call +\fBTcl_UnregisterChannel\fR with \fIinterp\fR as NULL, to indicate to Tcl +that it no longer holds a reference to that channel. If this is the last +reference to the channel, it will now be closed. + +.SH TCL_CLOSE +.PP +\fBTcl_Close\fR destroys the channel \fIchannel\fR, which must denote a +currently open channel. The channel should not be registered in any +interpreter when \fBTcl_Close\fR is called. Buffered output is flushed to +the channel's output device prior to destroying the channel, and any +buffered input is discarded. If this is a blocking channel, the call does +not return until all buffered data is successfully sent to the channel's +output device. If this is a nonblocking channel and there is buffered +output that cannot be written without blocking, the call returns +immediately; output is flushed in the background and the channel will be +closed once all of the buffered data has been output. In this case errors +during flushing are not reported. +.PP +If the channel was closed successfully, \fBTcl_Close\fR returns \fBTCL_OK\fR. +If an error occurs, \fBTcl_Close\fR returns \fBTCL_ERROR\fR and records a +POSIX error code that can be retrieved with \fBTcl_GetErrno\fR. +If the channel is being closed synchronously and an error occurs during +closing of the channel and \fIinterp\fR is not NULL, an error message is +left in the interpreter's result. +.PP +Note: it is not safe to call \fBTcl_Close\fR on a channel that has been +registered using \fBTcl_RegisterChannel\fR; see the documentation for +\fBTcl_RegisterChannel\fR, above, for details. If the channel has ever +been given as the \fBchan\fR argument in a call to +\fBTcl_RegisterChannel\fR, you should instead use +\fBTcl_UnregisterChannel\fR, which will internally call \fBTcl_Close\fR +when all calls to \fBTcl_RegisterChannel\fR have been matched by +corresponding calls to \fBTcl_UnregisterChannel\fR. + +.VS 8.1 br +.SH "TCL_READCHARS AND TCL_READ" +.PP +\fBTcl_ReadChars\fR consumes bytes from \fIchannel\fR, converting the bytes +to UTF-8 based on the channel's encoding and storing the produced data in +\fIreadObjPtr\fR's string representation. The return value of +\fBTcl_ReadChars\fR is the number of characters, up to \fIcharsToRead\fR, +that were stored in \fIobjPtr\fR. If an error occurs while reading, the +return value is \-1 and \fBTcl_ReadChars\fR records a POSIX error code that +can be retrieved with \fBTcl_GetErrno\fR. +.PP +The return value may be smaller than the value to read, indicating that less +data than requested was available. This is called a \fIshort read\fR. In +blocking mode, this can only happen on an end-of-file. In nonblocking mode, +a short read can also occur if there is not enough input currently +available: \fBTcl_ReadChars\fR returns a short count rather than waiting +for more data. +.PP +If the channel is in blocking mode, a return value of zero indicates an +end-of-file condition. If the channel is in nonblocking mode, a return +value of zero indicates either that no input is currently available or an +end-of-file condition. Use \fBTcl_Eof\fR and \fBTcl_InputBlocked\fR to tell +which of these conditions actually occurred. +.PP +\fBTcl_ReadChars\fR translates the various end-of-line representations into +the canonical \fB\en\fR internal representation according to the current +end-of-line recognition mode. End-of-line recognition and the various +platform-specific modes are described in the manual entry for the Tcl +\fBfconfigure\fR command. +.PP +As a performance optimization, when reading from a channel with the encoding +\fBbinary\fR, the bytes are not converted to UTF-8 as they are read. +Instead, they are stored in \fIreadObjPtr\fR's internal representation as a +byte-array object. The string representation of this object will only be +constructed if it is needed (e.g., because of a call to +\fBTcl_GetStringFromObj\fR). In this way, byte-oriented data can be read +from a channel, manipulated by calling \fBTcl_GetByteArrayFromObj\fR and +related functions, and then written to a channel without the expense of ever +converting to or from UTF-8. +.PP +\fBTcl_Read\fR is similar to \fBTcl_ReadChars\fR, except that it doesn't do +encoding conversions, regardless of the channel's encoding. It is deprecated +and exists for backwards compatibility with non-internationalized Tcl +extensions. It consumes bytes from \fIchannel\fR and stores them in +\fIbuf\fR, performing end-of-line translations on the way. The return value +of \fBTcl_Read\fR is the number of bytes, up to \fItoRead\fR, written in +\fIbuf\fR. The buffer produced by \fBTcl_Read\fR is not NULL terminated. +Its contents are valid from the zeroth position up to and excluding the +position indicated by the return value. + +.SH "TCL_GETSOBJ AND TCL_GETS" +.PP +\fBTcl_GetsObj\fR consumes bytes from \fIchannel\fR, converting the bytes to +UTF-8 based on the channel's encoding, until a full line of input has been +seen. If the channel's encoding is \fBbinary\fR, each byte read from the +channel is treated as an individual Unicode character. All of the +characters of the line except for the terminating end-of-line character(s) +are appended to \fIlineObjPtr\fR's string representation. The end-of-line +character(s) are read and discarded. +.PP +If a line was successfully read, the return value is greater than or equal +to zero and indicates the number of bytes stored in \fIlineObjPtr\fR. If an +error occurs, \fBTcl_GetsObj\fR returns \-1 and records a POSIX error code +that can be retrieved with \fBTcl_GetErrno\fR. \fBTcl_GetsObj\fR also +returns \-1 if the end of the file is reached; the \fBTcl_Eof\fR procedure +can be used to distinguish an error from an end-of-file condition. +.PP +If the channel is in nonblocking mode, the return value can also be \-1 if +no data was available or the data that was available did not contain an +end-of-line character. When \-1 is returned, the \fBTcl_InputBlocked\fR +procedure may be invoked to determine if the channel is blocked because +of input unavailability. +.PP +\fBTcl_Gets\fR is the same as \fBTcl_GetsObj\fR except the resulting +characters are appended to the appended to the dynamic string given by +\fIdsPtr\fR rather than a Tcl object. + +.SH "TCL_UNGETS" +.PP +\fBTcl_Ungets\fR is used to add data to the input queue of a channel, +at either the head or tail of the queue. \fIInput\fR is a pointer to +the data that is to be added. \fIInputLen\fR gives the length of the +input to add. \fIAddAtEnd\fR, in non-zero, indicates that the data is +to be added at the end of queue; otherwise it will be added at the +head of the queue. If \fIchannel\fR has a "sticky" EOF set, no data will be +added to the input queue. \fBTcl_Ungets\fR returns \fIinputLen\fR or +-1 if an error occurs. + +.SH "TCL_WRITECHARS, TCL_WRITEOBJ, AND TCL_WRITE" +.PP +\fBTcl_WriteChars\fR accepts \fIbytesToWrite\fR bytes of character data at +\fIcharBuf\fR. The UTF-8 characters in the buffer are converted to the +channel's encoding and queued for output to \fIchannel\fR. If +\fIbytesToWrite\fR is negative, \fBTcl_WriteChars\fR expects \fIcharBuf\fR +to be NULL terminated and it outputs everything up to the NULL. +.PP +Data queued for output may not appear on the output device immediately, due +to internal buffering. If the data should appear immediately, call +\fBTcl_Flush\fR after the call to \fBTcl_WriteChars\fR, or set the +\fB\-buffering\fR option on the channel to \fBnone\fR. If you wish the data +to appear as soon as a complete line is accepted for output, set the +\fB\-buffering\fR option on the channel to \fBline\fR mode. +.PP +The return value of \fBTcl_WriteChars\fR is a count of how many bytes were +accepted for output to the channel. This is either greater than zero to +indicate success or \-1 to indicate that an error occurred. If an error +occurs, \fBTcl_WriteChars\fR records a POSIX error code that may be +retrieved with \fBTcl_GetErrno\fR. +.PP +Newline characters in the output data are translated to platform-specific +end-of-line sequences according to the \fB\-translation\fR option for the +channel. This is done even if the channel has no encoding. +.PP +\fBTcl_WriteObj\fR is similar to \fBTcl_WriteChars\fR except it +accepts a Tcl object whose contents will be output to the channel. The +UTF-8 characters in \fIwriteObjPtr\fR's string representation are converted +to the channel's encoding and queued for output to \fIchannel\fR. +As a performance optimization, when writing to a channel with the encoding +\fBbinary\fR, UTF-8 characters are not converted as they are written. +Instead, the bytes in \fIwriteObjPtr\fR's internal representation as a +byte-array object are written to the channel. The byte-array representation +of the object will be constructed if it is needed. In this way, +byte-oriented data can be read from a channel, manipulated by calling +\fBTcl_GetByteArrayFromObj\fR and related functions, and then written to a +channel without the expense of ever converting to or from UTF-8. +.PP +\fBTcl_Write\fR is similar to \fBTcl_WriteChars\fR except that it doesn't do +encoding conversions, regardless of the channel's encoding. It is +deprecated and exists for backwards compatibility with non-internationalized +Tcl extensions. It accepts \fIbytesToWrite\fR bytes of data at +\fIbyteBuf\fR and queues them for output to \fIchannel\fR. If +\fIbytesToWrite\fR is negative, \fBTcl_Write\fR expects \fIbyteBuf\fR to be +NULL terminated and it outputs everything up to the NULL. +.VE + +.SH TCL_FLUSH +.PP +\fBTcl_Flush\fR causes all of the buffered output data for \fIchannel\fR +to be written to its underlying file or device as soon as possible. +If the channel is in blocking mode, the call does not return until +all the buffered data has been sent to the channel or some error occurred. +The call returns immediately if the channel is nonblocking; it starts +a background flush that will write the buffered data to the channel +eventually, as fast as the channel is able to absorb it. +.PP +The return value is normally \fBTCL_OK\fR. +If an error occurs, \fBTcl_Flush\fR returns \fBTCL_ERROR\fR and +records a POSIX error code that can be retrieved with \fBTcl_GetErrno\fR. + +.SH TCL_SEEK +.PP +\fBTcl_Seek\fR moves the access point in \fIchannel\fR where subsequent +data will be read or written. Buffered output is flushed to the channel and +buffered input is discarded, prior to the seek operation. +.PP +\fBTcl_Seek\fR normally returns the new access point. +If an error occurs, \fBTcl_Seek\fR returns \-1 and records a POSIX error +code that can be retrieved with \fBTcl_GetErrno\fR. +After an error, the access point may or may not have been moved. + +.SH TCL_TELL +.PP +\fBTcl_Tell\fR returns the current access point for a channel. The returned +value is \-1 if the channel does not support seeking. + +.SH TCL_GETCHANNELOPTION +.PP +\fBTcl_GetChannelOption\fR retrieves, in \fIdsPtr\fR, the value of one of +the options currently in effect for a channel, or a list of all options and +their values. The \fIchannel\fR argument identifies the channel for which +to query an option or retrieve all options and their values. +If \fIoptionName\fR is not NULL, it is the name of the +option to query; the option's value is copied to the Tcl dynamic string +denoted by \fIoptionValue\fR. If +\fIoptionName\fR is NULL, the function stores an alternating list of option +names and their values in \fIoptionValue\fR, using a series of calls to +\fBTcl_DStringAppendElement\fR. The various preexisting options and +their possible values are described in the manual entry for the Tcl +\fBfconfigure\fR command. Other options can be added by each channel type. +These channel type specific options are described in the manual entry for +the Tcl command that creates a channel of that type; for example, the +additional options for TCP based channels are described in the manual entry +for the Tcl \fBsocket\fR command. +The procedure normally returns \fBTCL_OK\fR. If an error occurs, it returns +\fBTCL_ERROR\fR and calls \fBTcl_SetErrno\fR to store an appropriate POSIX +error code. + +.SH TCL_SETCHANNELOPTION +.PP +\fBTcl_SetChannelOption\fR sets a new value for an option on \fIchannel\fR. +\fIOptionName\fR is the option to set and \fInewValue\fR is the value to +set. +The procedure normally returns \fBTCL_OK\fR. If an error occurs, +it returns \fBTCL_ERROR\fR; in addition, if \fIinterp\fR is non-NULL, +\fBTcl_SetChannelOption\fR leaves an error message in the interpreter's result. + +.SH TCL_EOF +.PP +\fBTcl_Eof\fR returns a nonzero value if \fIchannel\fR encountered +an end of file during the last input operation. + +.SH TCL_INPUTBLOCKED +.PP +\fBTcl_InputBlocked\fR returns a nonzero value if \fIchannel\fR is in +nonblocking mode and the last input operation returned less data than +requested because there was insufficient data available. +The call always returns zero if the channel is in blocking mode. + +.SH TCL_INPUTBUFFERED +.PP +\fBTcl_InputBuffered\fR returns the number of bytes of input currently +buffered in the internal buffers for a channel. If the channel is not open +for reading, this function always returns zero. + +.VS 8.0 +.SH "PLATFORM ISSUES" +.PP +The handles returned from \fBTcl_GetChannelHandle\fR depend on the +platform and the channel type. On Unix platforms, the handle is +always a Unix file descriptor as returned from the \fBopen\fR system +call. On Windows platforms, the handle is a file \fBHANDLE\fR when +the channel was created with \fBTcl_OpenFileChannel\fR, +\fBTcl_OpenCommandChannel\fR, or \fBTcl_MakeFileChannel\fR. Other +channel types may return a different type of handle on Windows +platforms. On the Macintosh platform, the handle is a file reference +number as returned from \fBHOpenDF\fR. +.VE + +.SH "SEE ALSO" +DString(3), fconfigure(n), filename(n), fopen(2), Tcl_CreateChannel(3) + +.SH KEYWORDS +access point, blocking, buffered I/O, channel, channel driver, end of file, +flush, input, nonblocking, output, read, seek, write diff --git a/mk4/modtcl/tcl8.3.4/doc/OpenTcp.3 b/mk4/modtcl/tcl8.3.4/doc/OpenTcp.3 new file mode 100644 index 0000000..03c2977 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/OpenTcp.3 @@ -0,0 +1,179 @@ +'\" +'\" Copyright (c) 1996-7 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: OpenTcp.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +.so man.macros +.TH Tcl_OpenTcpClient 3 8.0 Tcl "Tcl Library Procedures" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +Tcl_OpenTcpClient, Tcl_MakeTcpClientChannel, Tcl_OpenTcpServer \- procedures to open channels using TCP sockets +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +Tcl_Channel +\fBTcl_OpenTcpClient\fR(\fIinterp, port, host, myaddr, myport, async\fR) +.sp +Tcl_Channel +\fBTcl_MakeTcpClientChannel\fR(\fIsock\fR) +.sp +Tcl_Channel +\fBTcl_OpenTcpServer\fR(\fIinterp, port, myaddr, proc, clientData\fR) +.sp +.SH ARGUMENTS +.AS Tcl_ChannelType newClientProcPtr in +.AP Tcl_Interp *interp in +Tcl interpreter to use for error reporting. If non-NULL and an +error occurs, an error message is left in the interpreter's result. +.AP int port in +A port number to connect to as a client or to listen on as a server. +.AP char *host in +A string specifying a host name or address for the remote end of the connection. +.AP int myport in +A port number for the client's end of the socket. If 0, a port number +is allocated at random. +.AP char *myaddr in +A string specifying the host name or address for network interface to use +for the local end of the connection. If NULL, a default interface is +chosen. +.AP int async in +If nonzero, the client socket is connected asynchronously to the server. +.AP ClientData sock in +Platform-specific handle for client TCP socket. +.AP Tcl_TcpAcceptProc *proc in +Pointer to a procedure to invoke each time a new connection is +accepted via the socket. +.AP ClientData clientData in +Arbitrary one-word value to pass to \fIproc\fR. +.BE + +.SH DESCRIPTION +.PP +These functions are convenience procedures for creating +channels that communicate over TCP sockets. +The operations on a channel +are described in the manual entry for \fBTcl_OpenFileChannel\fR. + +.SH TCL_OPENTCPCLIENT +.PP +\fBTcl_OpenTcpClient\fR opens a client TCP socket connected to a \fIport\fR +on a specific \fIhost\fR, and returns a channel that can be used to +communicate with the server. The host to connect to can be specified either +as a domain name style name (e.g. \fBwww.sunlabs.com\fR), or as a string +containing the alphanumeric representation of its four-byte address (e.g. +\fB127.0.0.1\fR). Use the string \fBlocalhost\fR to connect to a TCP socket on +the host on which the function is invoked. +.PP +The \fImyaddr\fR and \fImyport\fR arguments allow a client to specify an +address for the local end of the connection. If \fImyaddr\fR is NULL, then +an interface is chosen automatically by the operating system. +If \fImyport\fR is 0, then a port number is chosen at random by +the operating system. +.PP +If \fIasync\fR is zero, the call to \fBTcl_OpenTcpClient\fR returns only +after the client socket has either successfully connected to the server, or +the attempted connection has failed. +If \fIasync\fR is nonzero the socket is connected asynchronously and the +returned channel may not yet be connected to the server when the call to +\fBTcl_OpenTcpClient\fR returns. If the channel is in blocking mode and an +input or output operation is done on the channel before the connection is +completed or fails, that operation will wait until the connection either +completes successfully or fails. If the channel is in nonblocking mode, the +input or output operation will return immediately and a subsequent call to +\fBTcl_InputBlocked\fR on the channel will return nonzero. +.PP +The returned channel is opened for reading and writing. +If an error occurs in opening the socket, \fBTcl_OpenTcpClient\fR returns +NULL and records a POSIX error code that can be retrieved +with \fBTcl_GetErrno\fR. +In addition, if \fIinterp\fR is non-NULL, an error message +is left in the interpreter's result. +.PP +The newly created channel is not registered in the supplied interpreter; to +register it, use \fBTcl_RegisterChannel\fR. +If one of the standard channels, \fBstdin, stdout\fR or \fBstderr\fR was +previously closed, the act of creating the new channel also assigns it as a +replacement for the standard channel. + +.SH TCL_MAKETCPCLIENTCHANNEL +.PP +\fBTcl_MakeTcpClientChannel\fR creates a \fBTcl_Channel\fR around an +existing, platform specific, handle for a client TCP socket. +.PP +The newly created channel is not registered in the supplied interpreter; to +register it, use \fBTcl_RegisterChannel\fR. +If one of the standard channels, \fBstdin, stdout\fR or \fBstderr\fR was +previously closed, the act of creating the new channel also assigns it as a +replacement for the standard channel. + +.SH TCL_OPENTCPSERVER +.PP +\fBTcl_OpenTcpServer\fR opens a TCP socket on the local host on a specified +\fIport\fR and uses the Tcl event mechanism to accept requests from clients +to connect to it. The \fImyaddr\fP argument specifies the network interface. +If \fImyaddr\fP is NULL the special address INADDR_ANY should be used to +allow connections from any network interface. +Each time a client connects to this socket, Tcl creates a channel +for the new connection and invokes \fIproc\fR with information about +the channel. \fIProc\fR must match the following prototype: +.CS +typedef void Tcl_TcpAcceptProc( + ClientData \fIclientData\fR, + Tcl_Channel \fIchannel\fR, + char *\fIhostName\fR, + int \fIport\fP); +.CE +.PP +The \fIclientData\fR argument will be the same as the \fIclientData\fR +argument to \fBTcl_OpenTcpServer\fR, \fIchannel\fR will be the handle +for the new channel, \fIhostName\fR points to a string containing +the name of the client host making the connection, and \fIport\fP +will contain the client's port number. +The new channel +is opened for both input and output. +If \fIproc\fR raises an error, the connection is closed automatically. +\fIProc\fR has no return value, but if it wishes to reject the +connection it can close \fIchannel\fR. +.PP +\fBTcl_OpenTcpServer\fR normally returns a pointer to a channel +representing the server socket. +If an error occurs, \fBTcl_OpenTcpServer\fR returns NULL and +records a POSIX error code that can be retrieved with \fBTcl_GetErrno\fR. +In addition, if the interpreter is non-NULL, an error message +is left in the interpreter's result. +.PP +The channel returned by \fBTcl_OpenTcpServer\fR cannot be used for +either input or output. +It is simply a handle for the socket used to accept connections. +The caller can close the channel to shut down the server and disallow +further connections from new clients. +.PP +TCP server channels operate correctly only in applications that dispatch +events through \fBTcl_DoOneEvent\fR or through Tcl commands such as +\fBvwait\fR; otherwise Tcl will never notice that a connection request from +a remote client is pending. +.PP +The newly created channel is not registered in the supplied interpreter; to +register it, use \fBTcl_RegisterChannel\fR. +If one of the standard channels, \fBstdin, stdout\fR or \fBstderr\fR was +previously closed, the act of creating the new channel also assigns it as a +replacement for the standard channel. + +.VS +.SH "PLATFORM ISSUES" +.PP +On Unix platforms, the socket handle is a Unix file descriptor as +returned by the \fBsocket\fR system call. On the Windows platform, the +socket handle is a \fBSOCKET\fR as defined in the WinSock API. On the +Macintosh platform, the socket handle is a \fBStreamPtr\fR. +.VE + +.SH "SEE ALSO" +Tcl_OpenFileChannel(3), Tcl_RegisterChannel(3), vwait(n) + +.SH KEYWORDS +client, server, TCP diff --git a/mk4/modtcl/tcl8.3.4/doc/ParseCmd.3 b/mk4/modtcl/tcl8.3.4/doc/ParseCmd.3 new file mode 100644 index 0000000..bc4d3b6 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/ParseCmd.3 @@ -0,0 +1,438 @@ +'\" +'\" Copyright (c) 1997 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: ParseCmd.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_ParseCommand 3 8.3 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_ParseCommand, Tcl_ParseExpr, Tcl_ParseBraces, Tcl_ParseQuotedString, Tcl_ParseVarName, Tcl_ParseVar, Tcl_FreeParse, Tcl_EvalTokens \- parse Tcl scripts and expressions +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +int +\fBTcl_ParseCommand\fR(\fIinterp, string, numBytes, nested, parsePtr\fR) +.sp +int +\fBTcl_ParseExpr\fR(\fIinterp, string, numBytes, parsePtr\fR) +.sp +int +\fBTcl_ParseBraces\fR(\fIinterp, string, numBytes, parsePtr, append, termPtr\fR) +.sp +int +\fBTcl_ParseQuotedString\fR(\fIinterp, string, numBytes, parsePtr, append, termPtr\fR) +.sp +int +\fBTcl_ParseVarName\fR(\fIinterp, string, numBytes, parsePtr, append\fR) +.sp +char * +\fBTcl_ParseVar\fR(\fIinterp, string, termPtr\fR) +.sp +\fBTcl_FreeParse\fR(\fIusedParsePtr\fR) +.sp +Tcl_Obj * +\fBTcl_EvalTokens\fR(\fIinterp, tokenPtr, numTokens\fR) +.SH ARGUMENTS +.AS Tcl_Interp *usedParsePtr +.AP Tcl_Interp *interp out +For procedures other than \fBTcl_FreeParse\fR and \fBTcl_EvalTokens\fR, +used only for error reporting; +if NULL, then no error messages are left after errors. +For \fBTcl_EvalTokens\fR, determines the context for evaluating the +script and also is used for error reporting; must not be NULL. +.AP char *string in +Pointer to first character in string to parse. +.AP int numBytes in +Number of bytes in \fIstring\fR, not including any terminating null +character. If less than 0 then the script consists of all characters +in \fIstring\fR up to the first null character. +.AP int nested in +Non-zero means that the script is part of a command substitution so an +unquoted close bracket should be treated as a command terminator. If zero, +close brackets have no special meaning. +.AP int append in +Non-zero means that \fI*parsePtr\fR already contains valid tokens; the new +tokens should be appended to those already present. Zero means that +\fI*parsePtr\fR is uninitialized; any information in it is ignored. +This argument is normally 0. +.AP Tcl_Parse *parsePtr out +Points to structure to fill in with information about the parsed +command, expression, variable name, etc. +Any previous information in this structure +is ignored, unless \fIappend\fR is non-zero in a call to +\fBTcl_ParseBraces\fR, \fBTcl_ParseQuotedString\fR, +or \fBTcl_ParseVarName\fR. +.AP char **termPtr out +If not NULL, points to a location where +\fBTcl_ParseBraces\fR, \fBTcl_ParseQuotedString\fR, and +\fBTcl_ParseVar\fR will store a pointer to the character +just after the terminating character (the close-brace, the last +character of the variable name, or the close-quote (respectively)) +if the parse was successful. +.AP Tcl_Parse *usedParsePtr in +Points to structure that was filled in by a previous call to +\fBTcl_ParseCommand\fR, \fBTcl_ParseExpr\fR, \fBTcl_ParseVarName\fR, etc. +.BE + +.SH DESCRIPTION +.PP +These procedures parse Tcl commands or portions of Tcl commands such as +expressions or references to variables. +Each procedure takes a pointer to a script (or portion thereof) +and fills in the structure pointed to by \fIparsePtr\fR +with a collection of tokens describing the information that was parsed. +The procedures normally return \fBTCL_OK\fR. +However, if an error occurs then they return \fBTCL_ERROR\fR, +leave an error message in \fIinterp's\fR result +(if \fIinterp\fR is not NULL), +and leave nothing in \fIparsePtr\fR. +.PP +\fBTcl_ParseCommand\fR is a procedure that parses Tcl +scripts. Given a pointer to a script, it +parses the first command from the script. If the command was parsed +successfully, \fBTcl_ParseCommand\fR returns \fBTCL_OK\fR and fills in the +structure pointed to by \fIparsePtr\fR with information about the +structure of the command (see below for details). +If an error occurred in parsing the command then +\fBTCL_ERROR\fR is returned, an error message is left in \fIinterp\fR's +result, and no information is left at \fI*parsePtr\fR. +.PP +\fBTcl_ParseExpr\fR parses Tcl expressions. +Given a pointer to a script containing an expression, +\fBTcl_ParseCommand\fR parses the expression. +If the expression was parsed successfully, +\fBTcl_ParseExpr\fR returns \fBTCL_OK\fR and fills in the +structure pointed to by \fIparsePtr\fR with information about the +structure of the expression (see below for details). +If an error occurred in parsing the command then +\fBTCL_ERROR\fR is returned, an error message is left in \fIinterp\fR's +result, and no information is left at \fI*parsePtr\fR. +.PP +\fBTcl_ParseBraces\fR parses a string or command argument +enclosed in braces such as +\fB{hello}\fR or \fB{string \\t with \\t tabs}\fR +from the beginning of its argument \fIstring\fR. +The first character of \fIstring\fR must be \fB{\fR. +If the braced string was parsed successfully, +\fBTcl_ParseBraces\fR returns \fBTCL_OK\fR, +fills in the structure pointed to by \fIparsePtr\fR +with information about the structure of the string +(see below for details), +and stores a pointer to the character just after the terminating \fB}\fR +in the location given by \fI*termPtr\fR. +If an error occurrs while parsing the string +then \fBTCL_ERROR\fR is returned, +an error message is left in \fIinterp\fR's result, +and no information is left at \fI*parsePtr\fR or \fI*termPtr\fR. +.PP +\fBTcl_ParseQuotedString\fR parses a double-quoted string such as +\fB"sum is [expr $a+$b]"\fR +from the beginning of the argument \fIstring\fR. +The first character of \fIstring\fR must be \fB"\fR. +If the double-quoted string was parsed successfully, +\fBTcl_ParseQuotedString\fR returns \fBTCL_OK\fR, +fills in the structure pointed to by \fIparsePtr\fR +with information about the structure of the string +(see below for details), +and stores a pointer to the character just after the terminating \fB"\fR +in the location given by \fI*termPtr\fR. +If an error occurrs while parsing the string +then \fBTCL_ERROR\fR is returned, +an error message is left in \fIinterp\fR's result, +and no information is left at \fI*parsePtr\fR or \fI*termPtr\fR. +.PP +\fBTcl_ParseVarName\fR parses a Tcl variable reference such as +\fB$abc\fR or \fB$x([expr $index + 1])\fR from the beginning of its +\fIstring\fR argument. +The first character of \fIstring\fR must be \fB$\fR. +If a variable name was parsed successfully, \fBTcl_ParseVarName\fR +returns \fBTCL_OK\fR and fills in the structure pointed to by +\fIparsePtr\fR with information about the structure of the variable name +(see below for details). If an error +occurrs while parsing the command then \fBTCL_ERROR\fR is returned, an +error message is left in \fIinterp\fR's result (if \fIinterp\fR isn't +NULL), and no information is left at \fI*parsePtr\fR. +.PP +\fBTcl_ParseVar\fR parse a Tcl variable reference such as \fB$abc\fR +or \fB$x([expr $index + 1])\fR from the beginning of its \fIstring\fR +argument. The first character of \fIstring\fR must be \fB$\fR. If +the variable name is parsed successfully, \fBTcl_ParseVar\fR returns a +pointer to the string value of the variable. If an error occurs while +parsing, then NULL is returned and an error message is left in +\fIinterp\fR's result. +.PP +The information left at \fI*parsePtr\fR +by \fBTcl_ParseCommand\fR, \fBTcl_ParseExpr\fR, \fBTcl_ParseBraces\fR, +\fBTcl_ParseQuotedString\fR, and \fBTcl_ParseVarName\fR +may include dynamically allocated memory. +If these five parsing procedures return \fBTCL_OK\fR +then the caller must invoke \fBTcl_FreeParse\fR to release +the storage at \fI*parsePtr\fR. +These procedures ignore any existing information in +\fI*parsePtr\fR (unless \fIappend\fR is non-zero), +so if repeated calls are being made to any of them +then \fBTcl_FreeParse\fR must be invoked once after each call. +.PP +\fBTcl_EvalTokens\fR evaluates a sequence of parse tokens from a Tcl_Parse +structure. The tokens typically consist +of all the tokens in a word or all the tokens that make up the index for +a reference to an array variable. \fBTcl_EvalTokens\fR performs the +substitutions requested by the tokens, concatenates the +resulting values, and returns the result in a new Tcl_Obj. The +reference count of the object returned as result has been +incremented, so the caller must +invoke \fBTcl_DecrRefCount\fR when it is finished with the object. +If an error occurs while evaluating the tokens (such as a reference to +a non-existent variable) then the return value is NULL and an error +message is left in \fIinterp\fR's result. + +.SH "TCL_PARSE STRUCTURE" +.PP +\fBTcl_ParseCommand\fR, \fBTcl_ParseExpr\fR, \fBTcl_ParseBraces\fR, +\fBTcl_ParseQuotedString\fR, and \fBTcl_ParseVarName\fR +return parse information in two data structures, Tcl_Parse and Tcl_Token: +.CS +typedef struct Tcl_Parse { + char *\fIcommentStart\fR; + int \fIcommentSize\fR; + char *\fIcommandStart\fR; + int \fIcommandSize\fR; + int \fInumWords\fR; + Tcl_Token *\fItokenPtr\fR; + int \fInumTokens\fR; + ... +} Tcl_Parse; + +typedef struct Tcl_Token { + int \fItype\fR; + char *\fIstart\fR; + int \fIsize\fR; + int \fInumComponents\fR; +} Tcl_Token; +.CE +.PP +The first five fields of a Tcl_Parse structure +are filled in only by \fBTcl_ParseCommand\fR. +These fields are not used by the other parsing procedures. +.PP +\fBTcl_ParseCommand\fR fills in a Tcl_Parse structure +with information that describes one Tcl command and any comments that +precede the command. +If there are comments, +the \fIcommentStart\fR field points to the \fB#\fR character that begins +the first comment and \fIcommentSize\fR indicates the number of bytes +in all of the comments preceding the command, including the newline +character that terminates the last comment. +If the command is not preceded by any comments, \fIcommentSize\fR is 0. +\fBTcl_ParseCommand\fR also sets the \fIcommandStart\fR field +to point to the first character of the first +word in the command (skipping any comments and leading space) and +\fIcommandSize\fR gives the total number of bytes in the command, +including the character pointed to by \fIcommandStart\fR up to and +including the newline, close bracket, or semicolon character that +terminates the command. The \fInumWords\fR field gives the +total number of words in the command. +.PP +All parsing procedures set the remaining fields, +\fItokenPtr\fR and \fInumTokens\fR. +The \fItokenPtr\fR field points to the first in an array of Tcl_Token +structures that describe the components of the entity being parsed. +The \fInumTokens\fR field gives the total number of tokens +present in the array. +Each token contains four fields. +The \fItype\fR field selects one of several token types +that are described below. The \fIstart\fR field +points to the first character in the token and the \fIsize\fR field +gives the total number of characters in the token. Some token types, +such as \fBTCL_TOKEN_WORD\fR and \fBTCL_TOKEN_VARIABLE\fR, consist of +several component tokens, which immediately follow the parent token; +the \fInumComponents\fR field describes how many of these there are. +The \fItype\fR field has one of the following values: +.TP 20 +\fBTCL_TOKEN_WORD\fR +This token ordinarily describes one word of a command +but it may also describe a quoted or braced string in an expression. +The token describes a component of the script that is +the result of concatenating together a sequence of subcomponents, +each described by a separate subtoken. +The token starts with the first non-blank +character of the component (which may be a double-quote or open brace) +and includes all characters in the component up to but not including the +space, semicolon, close bracket, close quote, or close brace that +terminates the component. The \fInumComponents\fR field counts the total +number of sub-tokens that make up the word, including sub-tokens +of \fBTCL_TOKEN_VARIABLE\fR and \fBTCL_TOKEN_BS\fR tokens. +.TP +\fBTCL_TOKEN_SIMPLE_WORD\fR +This token has the same meaning as \fBTCL_TOKEN_WORD\fR, except that +the word is guaranteed to consist of a single \fBTCL_TOKEN_TEXT\fR +sub-token. The \fInumComponents\fR field is always 1. +.TP +\fBTCL_TOKEN_TEXT\fR +The token describes a range of literal text that is part of a word. +The \fInumComponents\fR field is always 0. +.TP +\fBTCL_TOKEN_BS\fR +The token describes a backslash sequence such as \fB\en\fR or \fB\e0xa3\fR. +The \fInumComponents\fR field is always 0. +.TP +\fBTCL_TOKEN_COMMAND\fR +The token describes a command whose result result must be substituted into +the word. The token includes the square brackets that surround the +command. The \fInumComponents\fR field is always 0 (the nested command +is not parsed; call \fBTcl_ParseCommand\fR recursively if you want to +see its tokens). +.TP +\fBTCL_TOKEN_VARIABLE\fR +The token describes a variable substitution, including the +\fB$\fR, variable name, and array index (if there is one) up through the +close parenthesis that terminates the index. This token is followed +by one or more additional tokens that describe the variable name and +array index. If \fInumComponents\fR is 1 then the variable is a +scalar and the next token is a \fBTCL_TOKEN_TEXT\fR token that gives the +variable name. If \fInumComponents\fR is greater than 1 then the +variable is an array: the first sub-token is a \fBTCL_TOKEN_TEXT\fR +token giving the array name and the remaining sub-tokens are +\fBTCL_TOKEN_TEXT\fR, \fBTCL_TOKEN_BS\fR, \fBTCL_TOKEN_COMMAND\fR, and +\fBTCL_TOKEN_VARIABLE\fR tokens that must be concatenated to produce the +array index. The \fInumComponents\fR field includes nested sub-tokens +that are part of \fBTCL_TOKEN_VARIABLE\fR tokens in the array index. +.TP +\fBTCL_TOKEN_SUB_EXPR\fR +The token describes one subexpression of an expression +(or an entire expression). +A subexpression may consist of a value +such as an integer literal, variable substitution, +or parenthesized subexpression; +it may also consist of an operator and its operands. +The token starts with the first non-blank character of the subexpression +up to but not including the space, brace, close-paren, or bracket +that terminates the subexpression. +This token is followed by one or more additional tokens +that describe the subexpression. +If the first sub-token after the \fBTCL_TOKEN_SUB_EXPR\fR token +is a \fBTCL_TOKEN_OPERATOR\fR token, +the subexpression consists of an operator and its token operands. +If the operator has no operands, the subexpression consists of +just the \fBTCL_TOKEN_OPERATOR\fR token. +Each operand is described by a \fBTCL_TOKEN_SUB_EXPR\fR token. +Otherwise, the subexpression is a value described by +one of the token types \fBTCL_TOKEN_WORD\fR, \fBTCL_TOKEN_TEXT\fR, +\fBTCL_TOKEN_BS\fR, \fBTCL_TOKEN_COMMAND\fR, +\fBTCL_TOKEN_VARIABLE\fR, and \fBTCL_TOKEN_SUB_EXPR\fR. +The \fInumComponents\fR field +counts the total number of sub-tokens that make up the subexpression; +this includes the sub-tokens for any nested \fBTCL_TOKEN_SUB_EXPR\fR tokens. +.TP +\fBTCL_TOKEN_OPERATOR\fR +The token describes one operator of an expression +such as \fB&&\fR or \fBhypot\fR. +An \fBTCL_TOKEN_OPERATOR\fR token is always preceeded by a +\fBTCL_TOKEN_SUB_EXPR\fR token +that describes the operator and its operands; +the \fBTCL_TOKEN_SUB_EXPR\fR token's \fInumComponents\fR field +can be used to determine the number of operands. +A binary operator such as \fB*\fR +is followed by two \fBTCL_TOKEN_SUB_EXPR\fR tokens +that describe its operands. +A unary operator like \fB-\fR +is followed by a single \fBTCL_TOKEN_SUB_EXPR\fR token +for its operand. +If the operator is a math function such as \fBlog10\fR, +the \fBTCL_TOKEN_OPERATOR\fR token will give its name and +the following \fBTCL_TOKEN_SUB_EXPR\fR tokens will describe +its operands; +if there are no operands (as with \fBrand\fR), +no \fBTCL_TOKEN_SUB_EXPR\fR tokens follow. +There is one trinary operator, \fB?\fR, +that appears in if-then-else subexpressions +such as \fIx\fB?\fIy\fB:\fIz\fR; +in this case, the \fB?\fR \fBTCL_TOKEN_OPERATOR\fR token +is followed by three \fBTCL_TOKEN_SUB_EXPR\fR tokens for the operands +\fIx\fR, \fIy\fR, and \fIz\fR. +The \fInumComponents\fR field for a \fBTCL_TOKEN_OPERATOR\fR token +is always 0. +.PP +After \fBTcl_ParseCommand\fR returns, the first token pointed to by +the \fItokenPtr\fR field of the +Tcl_Parse structure always has type \fBTCL_TOKEN_WORD\fR or +\fBTCL_TOKEN_SIMPLE_WORD\fR. It is followed by the sub-tokens +that must be concatenated to produce the value of that word. +The next token is the \fBTCL_TOKEN_WORD\fR or \fBTCL_TOKEN_SIMPLE_WORD\fR +token for the second word, followed by sub-tokens for that +word, and so on until all \fInumWords\fR have been accounted +for. +.PP +After \fBTcl_ParseExpr\fR returns, the first token pointed to by +the \fItokenPtr\fR field of the +Tcl_Parse structure always has type \fBTCL_TOKEN_SUB_EXPR\fR. +It is followed by the sub-tokens that must be evaluated +to produce the value of the expression. +Only the token information in the Tcl_Parse structure +is modified: the \fIcommentStart\fR, \fIcommentSize\fR, +\fIcommandStart\fR, and \fIcommandSize\fR fields are not modified +by \fBTcl_ParseExpr\fR. +.PP +After \fBTcl_ParseBraces\fR returns, +the array of tokens pointed to by the \fItokenPtr\fR field of the +Tcl_Parse structure will contain a single \fBTCL_TOKEN_TEXT\fR token +if the braced string does not contain any backslash-newlines. +If the string does contain backslash-newlines, +the array of tokens will contain one or more +\fBTCL_TOKEN_TEXT\fR or \fBTCL_TOKEN_BS\fR sub-tokens +that must be concatenated to produce the value of the string. +If the braced string was just \fB{}\fR +(that is, the string was empty), +the single \fBTCL_TOKEN_TEXT\fR token will have a \fIsize\fR field +containing zero; +this ensures that at least one token appears +to describe the braced string. +Only the token information in the Tcl_Parse structure +is modified: the \fIcommentStart\fR, \fIcommentSize\fR, +\fIcommandStart\fR, and \fIcommandSize\fR fields are not modified +by \fBTcl_ParseBraces\fR. +.PP +After \fBTcl_ParseQuotedString\fR returns, +the array of tokens pointed to by the \fItokenPtr\fR field of the +Tcl_Parse structure depends on the contents of the quoted string. +It will consist of one or more \fBTCL_TOKEN_TEXT\fR, \fBTCL_TOKEN_BS\fR, +\fBTCL_TOKEN_COMMAND\fR, and \fBTCL_TOKEN_VARIABLE\fR sub-tokens. +The array always contains at least one token; +for example, if the argument \fIstring\fR is empty, +the array returned consists of a single \fBTCL_TOKEN_TEXT\fR token +with a zero \fIsize\fR field. +Only the token information in the Tcl_Parse structure +is modified: the \fIcommentStart\fR, \fIcommentSize\fR, +\fIcommandStart\fR, and \fIcommandSize\fR fields are not modified. +.PP +After \fBTcl_ParseVarName\fR returns, the first token pointed to by +the \fItokenPtr\fR field of the +Tcl_Parse structure always has type \fBTCL_TOKEN_VARIABLE\fR. It +is followed by the sub-tokens that make up the variable name as +described above. The total length of the variable name is +contained in the \fIsize\fR field of the first token. +As in \fBTcl_ParseExpr\fR, +only the token information in the Tcl_Parse structure +is modified by \fBTcl_ParseVarName\fR: +the \fIcommentStart\fR, \fIcommentSize\fR, +\fIcommandStart\fR, and \fIcommandSize\fR fields are not modified. +.PP +All of the character pointers in the +Tcl_Parse and Tcl_Token structures refer +to characters in the \fIstring\fR argument passed to +\fBTcl_ParseCommand\fR, \fBTcl_ParseExpr\fR, \fBTcl_ParseBraces\fR, +\fBTcl_ParseQuotedString\fR, and \fBTcl_ParseVarName\fR. +.PP +There are additional fields in the Tcl_Parse structure after the +\fInumTokens\fR field, but these are for the private use of +\fBTcl_ParseCommand\fR, \fBTcl_ParseExpr\fR, \fBTcl_ParseBraces\fR, +\fBTcl_ParseQuotedString\fR, and \fBTcl_ParseVarName\fR; they should not be +referenced by code outside of these procedures. + +.SH KEYWORDS +backslash substitution, braces, command, expression, parse, token, variable substitution diff --git a/mk4/modtcl/tcl8.3.4/doc/PkgRequire.3 b/mk4/modtcl/tcl8.3.4/doc/PkgRequire.3 new file mode 100644 index 0000000..f0a8306 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/PkgRequire.3 @@ -0,0 +1,87 @@ +'\" +'\" Copyright (c) 1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: PkgRequire.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_PkgRequire 3 7.5 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_PkgRequire, Tcl_PkgRequireEx, Tcl_PkgPresent, Tcl_PkgPresentEx, Tcl_PkgProvide, Tcl_PkgProvideEx \- package version control +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +char * +\fBTcl_PkgRequire\fR(\fIinterp, name, version, exact\fR) +.sp +char * +\fBTcl_PkgRequireEx\fR(\fIinterp, name, version, exact, clientDataPtr\fR) +.sp +char * +\fBTcl_PkgPresent\fR(\fIinterp, name, version, exact\fR) +.sp +char * +\fBTcl_PkgPresentEx\fR(\fIinterp, name, version, exact, clientDataPtr\fR) +.sp +int +\fBTcl_PkgProvide\fR(\fIinterp, name, version\fR) +.sp +int +\fBTcl_PkgProvideEx\fR(\fIinterp, name, version, clientData\fR) +.SH ARGUMENTS +.AS Tcl_FreeProc clientDataPtr +.AP Tcl_Interp *interp in +Interpreter where package is needed or available. +.AP char *name in +Name of package. +.AP char *version in +A version string consisting of one or more decimal numbers +separated by dots. +.AP int exact in +Non-zero means that only the particular version specified by +\fIversion\fR is acceptable. +Zero means that newer versions than \fIversion\fR are also +acceptable as long as they have the same major version number +as \fIversion\fR. +.AP ClientData clientData in +Arbitrary value to be associated with the package. +.AP ClientData *clientDataPtr out +Pointer to place to store the value associated with the matching +package. It is only changed if the pointer is not NULL and the +function completed successfully. +.BE + +.SH DESCRIPTION +.PP +These procedures provide C-level interfaces to Tcl's package and +version management facilities. +.PP +\fBTcl_PkgRequire\fR is equivalent to the \fBpackage require\fR +command, \fBTcl_PkgPresent\fR is equivalent to the \fBpackage present\fR +command, and \fBTcl_PkgProvide\fR is equivalent to the +\fBpackage provide\fR command. +.PP +See the documentation for the Tcl commands for details on what these +procedures do. +.PP +If \fBTcl_PkgPresent\fR or \fBTcl_PkgRequire\fR complete successfully +they return a pointer to the version string for the version of the package +that is provided in the interpreter (which may be different than +\fIversion\fR); if an error occurs they return NULL and leave an error +message in the interpreter's result. +.PP +\fBTcl_PkgProvide\fR returns TCL_OK if it completes successfully; +if an error occurs it returns TCL_ERROR and leaves an error message +in the interpreter's result. +.PP +\fBTcl_PkgProvideEx\fR, \fBTcl_PkgPresentEx\fR and \fBTcl_PkgRequireEx\fR +allow the setting and retrieving of the client data associated with +the package. In all other respects they are equivalent to the matching +functions. + +.SH KEYWORDS +package, present, provide, require, version diff --git a/mk4/modtcl/tcl8.3.4/doc/Preserve.3 b/mk4/modtcl/tcl8.3.4/doc/Preserve.3 new file mode 100644 index 0000000..8836c48 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/Preserve.3 @@ -0,0 +1,103 @@ +'\" +'\" Copyright (c) 1990 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: Preserve.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_Preserve 3 7.5 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_Preserve, Tcl_Release, Tcl_EventuallyFree \- avoid freeing storage while it's being used +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +\fBTcl_Preserve\fR(\fIclientData\fR) +.sp +\fBTcl_Release\fR(\fIclientData\fR) +.sp +\fBTcl_EventuallyFree\fR(\fIclientData, freeProc\fR) +.SH ARGUMENTS +.AS Tcl_FreeProc clientData +.AP ClientData clientData in +Token describing structure to be freed or reallocated. Usually a pointer +to memory for structure. +.AP Tcl_FreeProc *freeProc in +Procedure to invoke to free \fIclientData\fR. +.BE + +.SH DESCRIPTION +.PP +These three procedures help implement a simple reference count mechanism +for managing storage. They are designed to solve a problem +having to do with widget deletion, but are also useful in many other +situations. When a widget is deleted, its +widget record (the structure holding information specific to the +widget) must be returned to the storage allocator. +However, it's possible that the widget record is in active use +by one of the procedures on the stack at the time of the deletion. +This can happen, for example, if the command associated with a button +widget causes the button to be destroyed: an X event causes an +event-handling C procedure in the button to be invoked, which in +turn causes the button's associated Tcl command to be executed, +which in turn causes the button to be deleted, which in turn causes +the button's widget record to be de-allocated. +Unfortunately, when the Tcl command returns, the button's +event-handling procedure will need to reference the +button's widget record. +Because of this, the widget record must not be freed as part of the +deletion, but must be retained until the event-handling procedure has +finished with it. +In other situations where the widget is deleted, it may be possible +to free the widget record immediately. +.PP +\fBTcl_Preserve\fR and \fBTcl_Release\fR +implement short-term reference counts for their \fIclientData\fR +argument. +The \fIclientData\fR argument identifies an object and usually +consists of the address of a structure. +The reference counts guarantee that an object will not be freed +until each call to \fBTcl_Preserve\fR for the object has been +matched by calls to \fBTcl_Release\fR. +There may be any number of unmatched \fBTcl_Preserve\fR calls +in effect at once. +.PP +\fBTcl_EventuallyFree\fR is invoked to free up its \fIclientData\fR +argument. +It checks to see if there are unmatched \fBTcl_Preserve\fR calls +for the object. +If not, then \fBTcl_EventuallyFree\fR calls \fIfreeProc\fR immediately. +Otherwise \fBTcl_EventuallyFree\fR records the fact that \fIclientData\fR +needs eventually to be freed. +When all calls to \fBTcl_Preserve\fR have been matched with +calls to \fBTcl_Release\fR then \fIfreeProc\fR will be called by +\fBTcl_Release\fR to do the cleanup. +.PP +All the work of freeing the object is carried out by \fIfreeProc\fR. +\fIFreeProc\fR must have arguments and result that match the +type \fBTcl_FreeProc\fR: +.CS +typedef void Tcl_FreeProc(char *\fIblockPtr\fR); +.CE +The \fIblockPtr\fR argument to \fIfreeProc\fR will be the +same as the \fIclientData\fR argument to \fBTcl_EventuallyFree\fR. +The type of \fIblockPtr\fR (\fBchar *\fR) is different than the type of the +\fIclientData\fR argument to \fBTcl_EventuallyFree\fR for historical +reasons, but the value is the same. +.PP +This mechanism can be used to solve the problem described above +by placing \fBTcl_Preserve\fR and \fBTcl_Release\fR calls around +actions that may cause undesired storage re-allocation. The +mechanism is intended only for short-term use (i.e. while procedures +are pending on the stack); it will not work efficiently as a +mechanism for long-term reference counts. +The implementation does not depend in any way on the internal +structure of the objects being freed; it keeps the reference +counts in a separate structure. + +.SH KEYWORDS +free, reference count, storage diff --git a/mk4/modtcl/tcl8.3.4/doc/PrintDbl.3 b/mk4/modtcl/tcl8.3.4/doc/PrintDbl.3 new file mode 100644 index 0000000..d26b1e5 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/PrintDbl.3 @@ -0,0 +1,47 @@ +'\" +'\" Copyright (c) 1989-1993 The Regents of the University of California. +'\" Copyright (c) 1994-1997 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: PrintDbl.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_PrintDouble 3 8.0 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_PrintDouble \- Convert floating value to string +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +\fBTcl_PrintDouble\fR(\fIinterp, value, dst\fR) +.SH ARGUMENTS +.AS Tcl_Interp *interp +.AP Tcl_Interp *interp in +.VS +Before Tcl 8.0, the \fBtcl_precision\fR variable in this interpreter +controlled the conversion. As of Tcl 8.0, this argument is ignored and +the conversion is controlled by the \fBtcl_precision\fR variable +that is now shared by all interpreters. +.VE +.AP double value in +Floating-point value to be converted. +.AP char *dst out +Where to store string representing \fIvalue\fR. Must have at +least TCL_DOUBLE_SPACE characters of storage. +.BE + +.SH DESCRIPTION +.PP +\fBTcl_PrintDouble\fR generates a string that represents the value +of \fIvalue\fR and stores it in memory at the location given by +\fIdst\fR. It uses \fB%g\fR format to generate the string, with one +special twist: the string is guaranteed to contain either +a ``.'' or an ``e'' so that it doesn't look like an integer. Where +\fB%g\fR would generate an integer with no decimal point, \fBTcl_PrintDouble\fR +adds ``.0''. + +.SH KEYWORDS +conversion, double-precision, floating-point, string diff --git a/mk4/modtcl/tcl8.3.4/doc/RecEvalObj.3 b/mk4/modtcl/tcl8.3.4/doc/RecEvalObj.3 new file mode 100644 index 0000000..a70c6b3 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/RecEvalObj.3 @@ -0,0 +1,55 @@ +'\" +'\" Copyright (c) 1997 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: RecEvalObj.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_RecordAndEvalObj 3 8.0 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_RecordAndEvalObj \- save command on history list before evaluating +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +int +\fBTcl_RecordAndEvalObj\fR(\fIinterp, cmdPtr, flags\fR) +.SH ARGUMENTS +.AS Tcl_Interp *interp; +.AP Tcl_Interp *interp in +Tcl interpreter in which to evaluate command. +.AP Tcl_Obj *cmdPtr in +Points to a Tcl object containing a command (or sequence of commands) +to execute. +.AP int flags in +An OR'ed combination of flag bits. TCL_NO_EVAL means record the +command but don't evaluate it. TCL_EVAL_GLOBAL means evaluate +the command at global level instead of the current stack level. +.BE + +.SH DESCRIPTION +.PP +\fBTcl_RecordAndEvalObj\fR is invoked to record a command as an event +on the history list and then execute it using \fBTcl_EvalObjEx\fR +(or \fBTcl_GlobalEvalObj\fR if the TCL_EVAL_GLOBAL bit is set +in \fIflags\fR). +It returns a completion code such as TCL_OK just like \fBTcl_EvalObjEx\fR, +as well as a result object containing additional information +(a result value or error message) +that can be retrieved using \fBTcl_GetObjResult\fR. +If you don't want the command recorded on the history list then +you should invoke \fBTcl_EvalObjEx\fR instead of \fBTcl_RecordAndEvalObj\fR. +Normally \fBTcl_RecordAndEvalObj\fR is only called with top-level +commands typed by the user, since the purpose of history is to +allow the user to re-issue recently-invoked commands. +If the \fIflags\fR argument contains the TCL_NO_EVAL bit then +the command is recorded without being evaluated. + +.SH "SEE ALSO" +Tcl_EvalObjEx, Tcl_GetObjResult + +.SH KEYWORDS +command, event, execute, history, interpreter, object, record diff --git a/mk4/modtcl/tcl8.3.4/doc/RecordEval.3 b/mk4/modtcl/tcl8.3.4/doc/RecordEval.3 new file mode 100644 index 0000000..d1fb1ea --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/RecordEval.3 @@ -0,0 +1,57 @@ +'\" +'\" Copyright (c) 1989-1993 The Regents of the University of California. +'\" Copyright (c) 1994-1997 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: RecordEval.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_RecordAndEval 3 7.4 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_RecordAndEval \- save command on history list before evaluating +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +int +\fBTcl_RecordAndEval\fR(\fIinterp, cmd, flags\fR) +.SH ARGUMENTS +.AS Tcl_Interp *interp; +.AP Tcl_Interp *interp in +Tcl interpreter in which to evaluate command. +.AP char *cmd in +Command (or sequence of commands) to execute. +.AP int flags in +An OR'ed combination of flag bits. TCL_NO_EVAL means record the +command but don't evaluate it. TCL_EVAL_GLOBAL means evaluate +the command at global level instead of the current stack level. +.BE + +.SH DESCRIPTION +.PP +\fBTcl_RecordAndEval\fR is invoked to record a command as an event +on the history list and then execute it using \fBTcl_Eval\fR +(or \fBTcl_GlobalEval\fR if the TCL_EVAL_GLOBAL bit is set in \fIflags\fR). +It returns a completion code such as TCL_OK just like \fBTcl_Eval\fR +and it leaves information in the interpreter's result. +If you don't want the command recorded on the history list then +you should invoke \fBTcl_Eval\fR instead of \fBTcl_RecordAndEval\fR. +Normally \fBTcl_RecordAndEval\fR is only called with top-level +commands typed by the user, since the purpose of history is to +allow the user to re-issue recently-invoked commands. +If the \fIflags\fR argument contains the TCL_NO_EVAL bit then +the command is recorded without being evaluated. +.PP +Note that \fBTcl_RecordAndEval\fR has been largely replaced by the +object-based procedure \fBTcl_RecordAndEvalObj\fR. +That object-based procedure records and optionally executes +a command held in a Tcl object instead of a string. + +.SH "SEE ALSO" +Tcl_RecordAndEvalObj + +.SH KEYWORDS +command, event, execute, history, interpreter, record diff --git a/mk4/modtcl/tcl8.3.4/doc/RegExp.3 b/mk4/modtcl/tcl8.3.4/doc/RegExp.3 new file mode 100644 index 0000000..64493a4 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/RegExp.3 @@ -0,0 +1,346 @@ +'\" +'\" Copyright (c) 1994 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" Copyright (c) 1998-1999 Scriptics Corportation +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: RegExp.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_RegExpMatch 3 8.1 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_RegExpMatch, Tcl_RegExpCompile, Tcl_RegExpExec, Tcl_RegExpRange, Tcl_GetRegExpFromObj, Tcl_RegExpMatchObj, Tcl_RegExpExecObj, Tcl_RegExpGetInfo \- Pattern matching with regular expressions +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +int +\fBTcl_RegExpMatchObj\fR(\fIinterp\fR, \fIstrObj\fR, \fIpatObj\fR) +.sp +int +\fBTcl_RegExpMatch\fR(\fIinterp\fR, \fIstring\fR, \fIpattern\fR) +.sp +Tcl_RegExp +\fBTcl_RegExpCompile\fR(\fIinterp\fR, \fIpattern\fR) +.sp +int +\fBTcl_RegExpExec\fR(\fIinterp\fR, \fIregexp\fR, \fIstring\fR, \fIstart\fR) +.sp +\fBTcl_RegExpRange\fR(\fIregexp\fR, \fIindex\fR, \fIstartPtr\fR, \fIendPtr\fR) +.VS 8.1 +.sp +Tcl_RegExp +\fBTcl_GetRegExpFromObj\fR(\fIinterp\fR, \fIpatObj\fR, \fIcflags\fR) +.sp +int +\fBTcl_RegExpExecObj\fR(\fIinterp\fR, \fIregexp\fR, \fIobjPtr\fR, \fIoffset\fR, \fInmatches\fR, \fIeflags\fR) +.sp +\fBTcl_RegExpGetInfo\fR(\fIregexp\fR, \fIinfoPtr\fR) +.VE 8.1 + +.SH ARGUMENTS +.AS Tcl_Interp *interp +.AP Tcl_Interp *interp in +Tcl interpreter to use for error reporting. The interpreter may be +NULL if no error reporting is desired. +.VS 8.1 +.AP Tcl_Obj *strObj in/out +Refers to the object from which to get the string to search. The +internal representation of the object may be converted to a form that +can be efficiently searched. +.AP Tcl_Obj *patObj in/out +Refers to the object from which to get a regular expression. The +compiled regular expression is cached in the object. +.VE 8.1 +.AP char *string in +String to check for a match with a regular expression. +.AP char *pattern in +String in the form of a regular expression pattern. +.AP Tcl_RegExp regexp in +Compiled regular expression. Must have been returned previously +by \fBTcl_GetRegExpFromObj\fR or \fBTcl_RegExpCompile\fR. +.AP char *start in +If \fIstring\fR is just a portion of some other string, this argument +identifies the beginning of the larger string. +If it isn't the same as \fIstring\fR, then no \fB^\fR matches +will be allowed. +.AP int index in +Specifies which range is desired: 0 means the range of the entire +match, 1 or greater means the range that matched a parenthesized +sub-expression. +.AP char **startPtr out +The address of the first character in the range is stored here, or +NULL if there is no such range. +.AP char **endPtr out +The address of the character just after the last one in the range +is stored here, or NULL if there is no such range. +.VS 8.1 +.AP int cflags in +OR-ed combination of compilation flags. See below for more information. +.AP Tcl_Obj *objPtr in/out +An object which contains the string to check for a match with a +regular expression. +.AP int offset in +The character offset into the string where matching should begin. +The value of the offset has no impact on \fB^\fR matches. This +behavior is controlled by \fIeflags\fR. +.AP int nmatches in +The number of matching subexpressions that should be remembered for +later use. If this value is 0, then no subexpression match +information will be computed. If the value is -1, then +all of the matching subexpressions will be remembered. Any other +value will be taken as the maximum number of subexpressions to +remember. +.AP int eflags in +OR-ed combination of the values TCL_REG_NOTBOL and TCL_REG_NOTEOL. +See below for more information. +.AP Tcl_RegExpInfo *infoPtr out +The address of the location where information about a previous match +should be stored by \fBTcl_RegExpGetInfo\fR. +.VE 8.1 +.BE + +.SH DESCRIPTION +.PP +\fBTcl_RegExpMatch\fR determines whether its \fIpattern\fR argument +matches \fIregexp\fR, where \fIregexp\fR is interpreted +as a regular expression using the rules in the \fBre_syntax\fR +reference page. +If there is a match then \fBTcl_RegExpMatch\fR returns 1. +If there is no match then \fBTcl_RegExpMatch\fR returns 0. +If an error occurs in the matching process (e.g. \fIpattern\fR +is not a valid regular expression) then \fBTcl_RegExpMatch\fR +returns \-1 and leaves an error message in the interpreter result. +.VS 8.1.2 +\fBTcl_RegExpMatchObj\fR is similar to \fBTcl_RegExpMatch\fR except it +operates on the Tcl objects \fIstrObj\fR and \fIpatObj\fR instead of +UTF strings. +\fBTcl_RegExpMatchObj\fR is generally more efficient than +\fBTcl_RegExpMatch\fR, so it is the preferred interface. +.VE 8.1.2 +.PP +\fBTcl_RegExpCompile\fR, \fBTcl_RegExpExec\fR, and \fBTcl_RegExpRange\fR +provide lower-level access to the regular expression pattern matcher. +\fBTcl_RegExpCompile\fR compiles a regular expression string into +the internal form used for efficient pattern matching. +The return value is a token for this compiled form, which can be +used in subsequent calls to \fBTcl_RegExpExec\fR or \fBTcl_RegExpRange\fR. +If an error occurs while compiling the regular expression then +\fBTcl_RegExpCompile\fR returns NULL and leaves an error message +in the interpreter result. +Note: the return value from \fBTcl_RegExpCompile\fR is only valid +up to the next call to \fBTcl_RegExpCompile\fR; it is not safe to +retain these values for long periods of time. +.PP +\fBTcl_RegExpExec\fR executes the regular expression pattern matcher. +It returns 1 if \fIstring\fR contains a range of characters that +match \fIregexp\fR, 0 if no match is found, and +\-1 if an error occurs. +In the case of an error, \fBTcl_RegExpExec\fR leaves an error +message in the interpreter result. +When searching a string for multiple matches of a pattern, +it is important to distinguish between the start of the original +string and the start of the current search. +For example, when searching for the second occurrence of a +match, the \fIstring\fR argument might point to the character +just after the first match; however, it is important for the +pattern matcher to know that this is not the start of the entire string, +so that it doesn't allow \fB^\fR atoms in the pattern to match. +The \fIstart\fR argument provides this information by pointing +to the start of the overall string containing \fIstring\fR. +\fIStart\fR will be less than or equal to \fIstring\fR; if it +is less than \fIstring\fR then no \fB^\fR matches will be allowed. +.PP +\fBTcl_RegExpRange\fR may be invoked after \fBTcl_RegExpExec\fR +returns; it provides detailed information about what ranges of +the string matched what parts of the pattern. +\fBTcl_RegExpRange\fR returns a pair of pointers in \fI*startPtr\fR +and \fI*endPtr\fR that identify a range of characters in +the source string for the most recent call to \fBTcl_RegExpExec\fR. +\fIIndex\fR indicates which of several ranges is desired: +if \fIindex\fR is 0, information is returned about the overall range +of characters that matched the entire pattern; otherwise, +information is returned about the range of characters that matched the +\fIindex\fR'th parenthesized subexpression within the pattern. +If there is no range corresponding to \fIindex\fR then NULL +is stored in \fI*startPtr\fR and \fI*endPtr\fR. +.PP +.VS 8.1 +\fBTcl_GetRegExpFromObj\fR, \fBTcl_RegExpExecObj\fR, and +\fBTcl_RegExpGetInfo\fR are object interfaces that provide the most +direct control of Henry Spencer's regular expression library. For +users that need to modify compilation and execution options directly, +it is recommended that you use these interfaces instead of calling the +internal regexp functions. These interfaces handle the details of UTF +to Unicode translations as well as providing improved performance +through caching in the pattern and string objects. +.PP +\fBTcl_GetRegExpFromObj\fR attepts to return a compiled regular +expression from the \fIpatObj\fR. If the object does not already +contain a compiled regular expression it will attempt to create one +from the string in the object and assign it to the internal +representation of the \fIpatObj\fR. The return value of this function +is of type \fBTcl_RegExp\fR. The return value is a token for this +compiled form, which can be used in subsequent calls to +\fBTcl_RegExpExecObj\fR or \fBTcl_RegExpGetInfo\fR. If an error +occurs while compiling the regular expression then +\fBTcl_GetRegExpFromObj\fR returns NULL and leaves an error message in +the interpreter result. The regular expression token can be used as +long as the internal representation of \fIpatObj\fR refers to the +compiled form. The \fIeflags\fR argument is a bitwise OR of +zero or more of the following flags that control the compilation of +\fIpatObj\fR: +.RS 2 +.TP +\fBTCL_REG_ADVANCED\fR +Compile advanced regular expressions (`AREs'). This mode corresponds to +the normal regular expression syntax accepted by the Tcl regexp and +regsub commands. +.TP +\fBTCL_REG_EXTENDED\fR +Compile extended regular expressions (`EREs'). This mode corresponds +to the regular expression syntax recognized by Tcl 8.0 and earlier +versions. +.TP +\fBTCL_REG_BASIC\fR +Compile basic regular expressions (`BREs'). This mode corresponds +to the regular expression syntax recognized by common Unix utilities +like \fBsed\fR and \fBgrep\fR. This is the default if no flags are +specified. +.TP +\fBTCL_REG_EXPANDED\fR +Compile the regular expression (basic, extended, or advanced) using an +expanded syntax that allows comments and whitespace. This mode causes +non-backslashed non-bracket-expression white +space and #-to-end-of-line comments to be ignored. +.TP +\fBTCL_REG_QUOTE\fR +Compile a literal string, with all characters treated as ordinary characters. +.TP +\fBTCL_REG_NOCASE\fR +Compile for matching that ignores upper/lower case distinctions. +.TP +\fBTCL_REG_NEWLINE\fR +Compile for newline-sensitive matching. By default, newline is a +completely ordinary character with no special meaning in either +regular expressions or strings. With this flag, `[^' bracket +expressions and `.' never match newline, `^' matches an empty string +after any newline in addition to its normal function, and `$' matches +an empty string before any newline in addition to its normal function. +\fBREG_NEWLINE\fR is the bitwise OR of \fBREG_NLSTOP\fR and +\fBREG_NLANCH\fR. +.TP +\fBTCL_REG_NLSTOP\fR +Compile for partial newline-sensitive matching, +with the behavior of +`[^' bracket expressions and `.' affected, +but not the behavior of `^' and `$'. In this mode, `[^' bracket +expressions and `.' never match newline. +.TP +\fBTCL_REG_NLANCH\fR +Compile for inverse partial newline-sensitive matching, +with the behavior of +of `^' and `$' (the ``anchors'') affected, but not the behavior of +`[^' bracket expressions and `.'. In this mode `^' matches an empty string +after any newline in addition to its normal function, and `$' matches +an empty string before any newline in addition to its normal function. +.TP +\fBTCL_REG_NOSUB\fR +Compile for matching that reports only success or failure, +not what was matched. This reduces compile overhead and may improve +performance. Subsequent calls to \fBTcl_RegExpGetInfo\fR or +\fBTcl_RegExpRange\fR will not report any match information. +.TP +\fBTCL_REG_CANMATCH\fR +Compile for matching that reports the potential to complete a partial +match given more text (see below). +.RE +.PP +Only one of +\fBTCL_REG_EXTENDED\fR, +\fBTCL_REG_ADVANCED\fR, +\fBTCL_REG_BASIC\fR, and +\fBTCL_REG_QUOTE\fR may be specified. +.PP +\fBTcl_RegExpExecObj\fR executes the regular expression pattern +matcher. It returns 1 if \fIobjPtr\fR contains a range of characters +that match \fIregexp\fR, 0 if no match is found, and \-1 if an error +occurs. In the case of an error, \fBTcl_RegExpExecObj\fR leaves an +error message in the interpreter result. The \fInmatches\fR value +indicates to the matcher how many subexpressions are of interest. If +\fInmatches\fR is 0, then no subexpression match information is +recorded, which may allow the matcher to make various optimizations. +If the value is -1, then all of the subexpressions in the pattern are +remembered. If the value is a positive integer, then only that number +of subexpressions will be remembered. Matching begins at the +specified Unicode character index given by \fIoffset\fR. Unlike +\fBTcl_RegExpExec\fR, the behavior of anchors is not affected by the +offset value. Instead the behavior of the anchors is explicitly +controlled by the \fIeflags\fR argument, which is a bitwise OR of +zero or more of the following flags: +.RS 2 +.TP +\fBTCL_REG_NOTBOL\fR +The starting character will not be treated as the beginning of a +line or the beginning of the string, so `^' will not match there. +Note that this flag has no effect on how `\fB\eA\fR' matches. +.TP +\fBTCL_REG_NOTEOL\fR +The last character in the string will not be treated as the end of a +line or the end of the string, so '$' will not match there. +Note that this flag has no effect on how `\fB\eZ\fR' matches. +.RE +.PP +\fBTcl_RegExpGetInfo\fR retrieves information about the last match +performed with a given regular expression \fIregexp\fR. The +\fIinfoPtr\fR argument contains a pointer to a structure that is +defined as follows: +.PP +.CS +typedef struct Tcl_RegExpInfo { + int \fInsubs\fR; + Tcl_RegExpIndices *\fImatches\fR; + long \fIextendStart\fR; +} Tcl_RegExpInfo; +.CE +.PP +The \fInsubs\fR field contains a count of the number of parenthesized +subexpressions within the regular expression. If the \fBTCL_REG_NOSUB\fR +was used, then this value will be zero. The \fImatches\fR field +points to an array of \fInsubs\fR values that indicate the bounds of each +subexpression matched. The first element in the array refers to the +range matched by the entire regular expression, and subsequent elements +refer to the parenthesized subexpressions in the order that they +appear in the pattern. Each element is a structure that is defined as +follows: +.PP +.CS +typedef struct Tcl_RegExpIndices { + long \fIstart\fR; + long \fIend\fR; +} Tcl_RegExpIndices; +.CE +.PP +The \fIstart\fR and \fIend\fR values are Unicode character indices +relative to the offset location within \fIobjPtr\fR where matching began. +The \fIstart\fR index identifies the first character of the matched +subexpression. The \fIend\fR index identifies the first character +after the matched subexpression. If the subexpression matched the +empty string, then \fIstart\fR and \fIend\fR will be equal. If the +subexpression did not participate in the match, then \fIstart\fR and +\fIend\fR will be set to -1. +.PP +The \fIextendStart\fR field in \fBTcl_RegExpInfo\fR is only set if the +\fBTCL_REG_CANMATCH\fR flag was used. It indicates the first +character in the string where a match could occur. If a match was +found, this will be the same as the beginning of the current match. +If no match was found, then it indicates the earliest point at which a +match might occur if additional text is appended to the string. +.VE 8.1 +.SH "SEE ALSO" +re_syntax(n) +.SH KEYWORDS +match, pattern, regular expression, string, subexpression, Tcl_RegExpIndices, Tcl_RegExpInfo diff --git a/mk4/modtcl/tcl8.3.4/doc/SaveResult.3 b/mk4/modtcl/tcl8.3.4/doc/SaveResult.3 new file mode 100644 index 0000000..b9291a0 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/SaveResult.3 @@ -0,0 +1,65 @@ +'\" +'\" Copyright (c) 1997 by Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: SaveResult.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_SaveResult 3 8.1 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_SaveResult, Tcl_RestoreResult, Tcl_DiscardResult \- save and restore an interpreter's result +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +\fBTcl_SaveResult(\fIinterp, statePtr\fB)\fR +.sp +\fBTcl_RestoreResult(\fIinterp, statePtr\fB)\fR +.sp +\fBTcl_DiscardResult(\fIstatePtr\fB)\fR +.SH ARGUMENTS +.AS Tcl_SavedResult statePtr +.AP Tcl_Interp *interp in +Interpreter for which state should be saved. +.AP Tcl_SavedResult *statePtr in +Pointer to location where interpreter result should be saved or restored. +.BE + +.SH DESCRIPTION +.PP +These routines allows a C procedure to take a snapshot of the current +interpreter result so that it can be restored after a call +to \fBTcl_Eval\fR or some other routine that modifies the interpreter +result. These routines are passed a pointer to a structure that is +used to store enough information to restore the interpreter result +state. This structure can be allocated on the stack of the calling +procedure. These routines do not save the state of any error +information in the interpreter (e.g. the \fBerrorCode\fR or +\fBerrorInfo\fR variables). +.PP +\fBTcl_SaveResult\fR moves the string and object results +of \fIinterp\fR into the location specified by \fIstatePtr\fR. +\fBTcl_SaveResult\fR clears the result for \fIinterp\fR and +leaves the result in its normal empty initialized state. +.PP +\fBTcl_RestoreResult\fR moves the string and object results from +\fIstatePtr\fR back into \fIinterp\fR. Any result or error that was +already in the interpreter will be cleared. The \fIstatePtr\fR is left +in an uninitialized state and cannot be used until another call to +\fBTcl_SaveResult\fR. +.PP +\fBTcl_DiscardResult\fR releases the saved interpreter state +stored at \fBstatePtr\fR. The state structure is left in an +uninitialized state and cannot be used until another call to +\fBTcl_SaveResult\fR. +.PP +Once \fBTcl_SaveResult\fR is called to save the interpreter +result, either \fBTcl_RestoreResult\fR or +\fBTcl_DiscardResult\fR must be called to properly clean up the +memory associated with the saved state. + +.SH KEYWORDS +result, state, interp diff --git a/mk4/modtcl/tcl8.3.4/doc/SetErrno.3 b/mk4/modtcl/tcl8.3.4/doc/SetErrno.3 new file mode 100644 index 0000000..946d1c6 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/SetErrno.3 @@ -0,0 +1,61 @@ +'\" +'\" Copyright (c) 1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: SetErrno.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +.so man.macros +.TH Tcl_SetErrno 3 8.3 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_SetErrno, Tcl_GetErrno, Tcl_ErrnoId, Tcl_ErrnoMsg \- manipulate errno to store and retrieve error codes +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +void +\fBTcl_SetErrno\fR(\fIerrorCode\fR) +.sp +int +\fBTcl_GetErrno\fR() +.sp +char * +\fBTcl_ErrnoId\fR() +.sp +char * +\fBTcl_ErrnoMsg\fR() +.sp +.SH ARGUMENTS +.AS Tcl_Interp *errorCode in +.AP int errorCode in +A POSIX error code such as \fBENOENT\fR. +.BE + +.SH DESCRIPTION +.PP +\fBTcl_SetErrno\fR and \fBTcl_GetErrno\fR provide portable access +to the \fBerrno\fR variable, which is used to record a POSIX error +code after system calls and other operations such as \fBTcl_Gets\fR. +These procedures are necessary because global variable accesses cannot +be made across module boundaries on some platforms. +.PP +\fBTcl_SetErrno\fR sets the \fBerrno\fR variable to the value of the +\fIerrorCode\fR argument +C procedures that wish to return error information to their callers +via \fBerrno\fR should call \fBTcl_SetErrno\fR rather than setting +\fBerrno\fR directly. +.PP +\fBTcl_GetErrno\fR returns the current value of \fBerrno\fR. +Procedures wishing to access \fBerrno\fR should call this procedure +instead of accessing \fBerrno\fR directly. +.PP +\fBTcl_ErrnoId\fR and \fBTcl_ErrnoMsg\fR return a string +representation of the current \fBerrno\fR value. \fBTcl_ErrnoId\fR +returns a machine-readable textual identifier such as +"EACCES". \fBTcl_ErrnoMsg\fR returns a human-readable string such as +"permission denied". The strings returned by these functions are +statically allocated and the caller must not free or modify them. + +.SH KEYWORDS +errno, error code, global variables diff --git a/mk4/modtcl/tcl8.3.4/doc/SetRecLmt.3 b/mk4/modtcl/tcl8.3.4/doc/SetRecLmt.3 new file mode 100644 index 0000000..0b20d90 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/SetRecLmt.3 @@ -0,0 +1,55 @@ +'\" +'\" Copyright (c) 1989-1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: SetRecLmt.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_SetRecursionLimit 3 7.0 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_SetRecursionLimit \- set maximum allowable nesting depth in interpreter +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +int +\fBTcl_SetRecursionLimit\fR(\fIinterp, depth\fR) +.SH ARGUMENTS +.AS Tcl_Interp *interp +.AP Tcl_Interp *interp in +Interpreter whose recursion limit is to be set. +Must be greater than zero. +.AP int depth in +New limit for nested calls to \fBTcl_Eval\fR for \fIinterp\fR. +.BE + +.SH DESCRIPTION +.PP +At any given time Tcl enforces a limit on the number of recursive +calls that may be active for \fBTcl_Eval\fR and related procedures +such as \fBTcl_GlobalEval\fR. +Any call to \fBTcl_Eval\fR that exceeds this depth is aborted with +an error. +By default the recursion limit is 1000. +.PP +\fBTcl_SetRecursionLimit\fR may be used to change the maximum +allowable nesting depth for an interpreter. +The \fIdepth\fR argument specifies a new limit for \fIinterp\fR, +and \fBTcl_SetRecursionLimit\fR returns the old limit. +To read out the old limit without modifying it, invoke +\fBTcl_SetRecursionLimit\fR with \fIdepth\fR equal to 0. +.PP +The \fBTcl_SetRecursionLimit\fR only sets the size of the Tcl +call stack: it cannot by itself prevent stack overflows on the +C stack being used by the application. If your machine has a +limit on the size of the C stack, you may get stack overflows +before reaching the limit set by \fBTcl_SetRecursionLimit\fR. +If this happens, see if there is a mechanism in your system for +increasing the maximum size of the C stack. + +.SH KEYWORDS +nesting depth, recursion diff --git a/mk4/modtcl/tcl8.3.4/doc/SetResult.3 b/mk4/modtcl/tcl8.3.4/doc/SetResult.3 new file mode 100644 index 0000000..e1a0ee4 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/SetResult.3 @@ -0,0 +1,225 @@ +'\" +'\" Copyright (c) 1989-1993 The Regents of the University of California. +'\" Copyright (c) 1994-1997 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: SetResult.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_SetResult 3 8.0 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_SetObjResult, Tcl_GetObjResult, Tcl_SetResult, Tcl_GetStringResult, Tcl_AppendResult, Tcl_AppendResultVA, Tcl_AppendElement, Tcl_ResetResult, Tcl_FreeResult \- manipulate Tcl result +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +\fBTcl_SetObjResult\fR(\fIinterp, objPtr\fR) +.sp +Tcl_Obj * +\fBTcl_GetObjResult\fR(\fIinterp\fR) +.sp +\fBTcl_SetResult\fR(\fIinterp, string, freeProc\fR) +.sp +char * +\fBTcl_GetStringResult\fR(\fIinterp\fR) +.sp +\fBTcl_AppendResult\fR(\fIinterp, string, string, ... , \fB(char *) NULL\fR) +.sp +\fBTcl_AppendResultVA\fR(\fIinterp, argList\fR) +.sp +\fBTcl_AppendElement\fR(\fIinterp, string\fR) +.sp +\fBTcl_ResetResult\fR(\fIinterp\fR) +.sp +\fBTcl_FreeResult\fR(\fIinterp\fR) +.SH ARGUMENTS +.AS Tcl_FreeProc freeProc +.AP Tcl_Interp *interp out +Interpreter whose result is to be modified or read. +.AP Tcl_Obj *objPtr in +Object value to become result for \fIinterp\fR. +.AP char *string in +String value to become result for \fIinterp\fR or to be +appended to the existing result. +.AP Tcl_FreeProc *freeProc in +Address of procedure to call to release storage at +\fIstring\fR, or \fBTCL_STATIC\fR, \fBTCL_DYNAMIC\fR, or +\fBTCL_VOLATILE\fR. +.AP va_list argList in +An argument list which must have been initialised using +\fBTCL_VARARGS_START\fR, and cleared using \fBva_end\fR. +.BE + +.SH DESCRIPTION +.PP +The procedures described here are utilities for manipulating the +result value in a Tcl interpreter. +The interpreter result may be either a Tcl object or a string. +For example, \fBTcl_SetObjResult\fR and \fBTcl_SetResult\fR +set the interpreter result to, respectively, an object and a string. +Similarly, \fBTcl_GetObjResult\fR and \fBTcl_GetStringResult\fR +return the interpreter result as an object and as a string. +The procedures always keep the string and object forms +of the interpreter result consistent. +For example, if \fBTcl_SetObjResult\fR is called to set +the result to an object, +then \fBTcl_GetStringResult\fR is called, +it will return the object's string value. +.PP +\fBTcl_SetObjResult\fR +arranges for \fIobjPtr\fR to be the result for \fIinterp\fR, +replacing any existing result. +The result is left pointing to the object +referenced by \fIobjPtr\fR. +\fIobjPtr\fR's reference count is incremented +since there is now a new reference to it from \fIinterp\fR. +The reference count for any old result object +is decremented and the old result object is freed if no +references to it remain. +.PP +\fBTcl_GetObjResult\fR returns the result for \fIinterp\fR as an object. +The object's reference count is not incremented; +if the caller needs to retain a long-term pointer to the object +they should use \fBTcl_IncrRefCount\fR to increment its reference count +in order to keep it from being freed too early or accidently changed. +.PP +\fBTcl_SetResult\fR +arranges for \fIstring\fR to be the result for the current Tcl +command in \fIinterp\fR, replacing any existing result. +The \fIfreeProc\fR argument specifies how to manage the storage +for the \fIstring\fR argument; +it is discussed in the section +\fBTHE TCL_FREEPROC ARGUMENT TO TCL_SETRESULT\fR below. +If \fIstring\fR is \fBNULL\fR, then \fIfreeProc\fR is ignored +and \fBTcl_SetResult\fR +re-initializes \fIinterp\fR's result to point to an empty string. +.PP +\fBTcl_GetStringResult\fR returns the result for \fIinterp\fR as an string. +If the result was set to an object by a \fBTcl_SetObjResult\fR call, +the object form will be converted to a string and returned. +If the object's string representation contains null bytes, +this conversion will lose information. +For this reason, programmers are encouraged to +write their code to use the new object API procedures +and to call \fBTcl_GetObjResult\fR instead. +.PP +\fBTcl_ResetResult\fR clears the result for \fIinterp\fR +and leaves the result in its normal empty initialized state. +If the result is an object, +its reference count is decremented and the result is left +pointing to an unshared object representing an empty string. +If the result is a dynamically allocated string, its memory is free*d +and the result is left as a empty string. +\fBTcl_ResetResult\fR also clears the error state managed by +\fBTcl_AddErrorInfo\fR, \fBTcl_AddObjErrorInfo\fR, +and \fBTcl_SetErrorCode\fR. + +.SH "OLD STRING PROCEDURES" +.PP +Use of the following procedures is deprecated +since they manipulate the Tcl result as a string. +Procedures such as \fBTcl_SetObjResult\fR +that manipulate the result as an object +can be significantly more efficient. +.PP +\fBTcl_AppendResult\fR makes it easy to build up Tcl results in pieces. +It takes each of its \fIstring\fR arguments and appends them in order +to the current result associated with \fIinterp\fR. +If the result is in its initialized empty state (e.g. a command procedure +was just invoked or \fBTcl_ResetResult\fR was just called), +then \fBTcl_AppendResult\fR sets the result to the concatenation of +its \fIstring\fR arguments. +\fBTcl_AppendResult\fR may be called repeatedly as additional pieces +of the result are produced. +\fBTcl_AppendResult\fR takes care of all the +storage management issues associated with managing \fIinterp\fR's +result, such as allocating a larger result area if necessary. +It also converts the current interpreter result from an object +to a string, if necessary, before appending the argument strings. +Any number of \fIstring\fR arguments may be passed in a single +call; the last argument in the list must be a NULL pointer. +.PP +\fBTcl_AppendResultVA\fR is the same as \fBTcl_AppendResult\fR except that +instead of taking a variable number of arguments it takes an argument list. +.PP +\fBTcl_AppendElement\fR is similar to \fBTcl_AppendResult\fR in +that it allows results to be built up in pieces. +However, \fBTcl_AppendElement\fR takes only a single \fIstring\fR +argument and it appends that argument to the current result +as a proper Tcl list element. +\fBTcl_AppendElement\fR adds backslashes or braces if necessary +to ensure that \fIinterp\fR's result can be parsed as a list and that +\fIstring\fR will be extracted as a single element. +Under normal conditions, \fBTcl_AppendElement\fR will add a space +character to \fIinterp\fR's result just before adding the new +list element, so that the list elements in the result are properly +separated. +However if the new list element is the first in a list or sub-list +(i.e. \fIinterp\fR's current result is empty, or consists of the +single character ``{'', or ends in the characters `` {'') then no +space is added. +.PP +\fBTcl_FreeResult\fR performs part of the work +of \fBTcl_ResetResult\fR. +It frees up the memory associated with \fIinterp\fR's result. +It also sets \fIinterp->freeProc\fR to zero, but doesn't +change \fIinterp->result\fR or clear error state. +\fBTcl_FreeResult\fR is most commonly used when a procedure +is about to replace one result value with another. + +.SH "DIRECT ACCESS TO INTERP->RESULT IS DEPRECATED" +.PP +It used to be legal for programs to +directly read and write \fIinterp->result\fR +to manipulate the interpreter result. +Direct access to \fIinterp->result\fR is now strongly deprecated +because it can make the result's string and object forms inconsistent. +Programs should always read the result +using the procedures \fBTcl_GetObjResult\fR or \fBTcl_GetStringResult\fR, +and write the result using \fBTcl_SetObjResult\fR or \fBTcl_SetResult\fR. + +.SH "THE TCL_FREEPROC ARGUMENT TO TCL_SETRESULT" +.PP +\fBTcl_SetResult\fR's \fIfreeProc\fR argument specifies how +the Tcl system is to manage the storage for the \fIstring\fR argument. +If \fBTcl_SetResult\fR or \fBTcl_SetObjResult\fR are called +at a time when \fIinterp\fR holds a string result, +they do whatever is necessary to dispose of the old string result +(see the \fBTcl_Interp\fR manual entry for details on this). +.PP +If \fIfreeProc\fR is \fBTCL_STATIC\fR it means that \fIstring\fR +refers to an area of static storage that is guaranteed not to be +modified until at least the next call to \fBTcl_Eval\fR. +If \fIfreeProc\fR +is \fBTCL_DYNAMIC\fR it means that \fIstring\fR was allocated with a call +to \fBTcl_Alloc\fR and is now the property of the Tcl system. +\fBTcl_SetResult\fR will arrange for the string's storage to be +released by calling \fBTcl_Free\fR when it is no longer needed. +If \fIfreeProc\fR is \fBTCL_VOLATILE\fR it means that \fIstring\fR +points to an area of memory that is likely to be overwritten when +\fBTcl_SetResult\fR returns (e.g. it points to something in a stack frame). +In this case \fBTcl_SetResult\fR will make a copy of the string in +dynamically allocated storage and arrange for the copy to be the +result for the current Tcl command. +.PP +If \fIfreeProc\fR isn't one of the values \fBTCL_STATIC\fR, +\fBTCL_DYNAMIC\fR, and \fBTCL_VOLATILE\fR, then it is the address +of a procedure that Tcl should call to free the string. +This allows applications to use non-standard storage allocators. +When Tcl no longer needs the storage for the string, it will +call \fIfreeProc\fR. \fIFreeProc\fR should have arguments and +result that match the type \fBTcl_FreeProc\fR: +.CS +typedef void Tcl_FreeProc(char *\fIblockPtr\fR); +.CE +When \fIfreeProc\fR is called, its \fIblockPtr\fR will be set to +the value of \fIstring\fR passed to \fBTcl_SetResult\fR. + +.SH "SEE ALSO" +Tcl_AddErrorInfo, Tcl_CreateObjCommand, Tcl_SetErrorCode, Tcl_Interp + +.SH KEYWORDS +append, command, element, list, object, result, return value, interpreter diff --git a/mk4/modtcl/tcl8.3.4/doc/SetVar.3 b/mk4/modtcl/tcl8.3.4/doc/SetVar.3 new file mode 100644 index 0000000..2253fc5 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/SetVar.3 @@ -0,0 +1,261 @@ +'\" +'\" Copyright (c) 1989-1993 The Regents of the University of California. +'\" Copyright (c) 1994-1997 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: SetVar.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_SetVar 3 8.1 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_SetVar2Ex, Tcl_SetVar, Tcl_SetVar2, Tcl_ObjSetVar2, Tcl_GetVar2Ex, Tcl_GetVar, Tcl_GetVar2, Tcl_ObjGetVar2, Tcl_UnsetVar, Tcl_UnsetVar2 \- manipulate Tcl variables +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +.VS 8.1 +Tcl_Obj * +\fBTcl_SetVar2Ex\fR(\fIinterp, name1, name2, newValuePtr, flags\fR) +.VE +.sp +char * +\fBTcl_SetVar\fR(\fIinterp, varName, newValue, flags\fR) +.sp +char * +\fBTcl_SetVar2\fR(\fIinterp, name1, name2, newValue, flags\fR) +.sp +Tcl_Obj * +\fBTcl_ObjSetVar2\fR(\fIinterp, part1Ptr, part2Ptr, newValuePtr, flags\fR) +.sp +.VS 8.1 +Tcl_Obj * +\fBTcl_GetVar2Ex\fR(\fIinterp, name1, name2, flags\fR) +.VE +.sp +char * +\fBTcl_GetVar\fR(\fIinterp, varName, flags\fR) +.sp +char * +\fBTcl_GetVar2\fR(\fIinterp, name1, name2, flags\fR) +.sp +Tcl_Obj * +\fBTcl_ObjGetVar2\fR(\fIinterp, part1Ptr, part2Ptr, flags\fR) +.sp +int +\fBTcl_UnsetVar\fR(\fIinterp, varName, flags\fR) +.sp +int +\fBTcl_UnsetVar2\fR(\fIinterp, name1, name2, flags\fR) +.SH ARGUMENTS +.AS Tcl_Interp *newValuePtr +.AP Tcl_Interp *interp in +Interpreter containing variable. +.AP char *name1 in +Contains the name of an array variable (if \fIname2\fR is non-NULL) +or (if \fIname2\fR is NULL) either the name of a scalar variable +or a complete name including both variable name and index. +May include \fB::\fR namespace qualifiers +to specify a variable in a particular namespace. +.AP char *name2 in +If non-NULL, gives name of element within array; in this +case \fIname1\fR must refer to an array variable. +.AP Tcl_Obj *newValuePtr in +.VS 8.1 +Points to a Tcl object containing the new value for the variable. +.VE +.AP int flags in +OR-ed combination of bits providing additional information. See below +for valid values. +.AP char *varName in +Name of variable. +May include \fB::\fR namespace qualifiers +to specify a variable in a particular namespace. +May refer to a scalar variable or an element of +an array. +If the name references an element of an array, then the name +must be in writable memory: Tcl will make temporary modifications +to it while looking up the name. +.AP char *newValue in +New value for variable, specified as a NULL-terminated string. +A copy of this value is stored in the variable. +.AP Tcl_Obj *part1Ptr in +Points to a Tcl object containing the variable's name. +The name may include a series of \fB::\fR namespace qualifiers +to specify a variable in a particular namespace. +May refer to a scalar variable or an element of an array variable. +.AP Tcl_Obj *part2Ptr in +If non-NULL, points to an object containing the name of an element +within an array and \fIpart1Ptr\fR must refer to an array variable. +.BE + +.SH DESCRIPTION +.PP +These procedures are used to create, modify, read, and delete +Tcl variables from C code. +.PP +.VS 8.1 +\fBTcl_SetVar2Ex\fR, \fBTcl_SetVar\fR, \fBTcl_SetVar2\fR, and +\fBTcl_ObjSetVar2\fR +will create a new variable or modify an existing one. +These procedures set the given variable to the value +given by \fInewValuePtr\fR or \fInewValue\fR and return a +pointer to the variable's new value, which is stored in Tcl's +variable structure. +\fBTcl_SetVar2Ex\fR and \fBTcl_ObjSetVar2\fR take the new value as a +Tcl_Obj and return +a pointer to a Tcl_Obj. \fBTcl_SetVar\fR and \fBTcl_SetVar2\fR +take the new value as a string and return a string; they are +usually less efficient than \fBTcl_ObjSetVar2\fR. Note that the +return value may be different than the \fInewValuePtr\fR or +.VE +\fInewValue\fR argument, due to modifications made by write traces. +If an error occurs in setting the variable (e.g. an array +variable is referenced without giving an index into the array) +NULL is returned and an error message is left in \fIinterp\fR's +result if the \fBTCL_LEAVE_ERR_MSG\fR \fIflag\fR bit is set. +.PP +.VS 8.1 +\fBTcl_GetVar2Ex\fR, \fBTcl_GetVar\fR, \fBTcl_GetVar2\fR, and +\fBTcl_ObjGetVar2\fR +return the current value of a variable. +The arguments to these procedures are treated in the same way +as the arguments to the procedures described above. +Under normal circumstances, the return value is a pointer +to the variable's value. For \fBTcl_GetVar2Ex\fR and +\fBTcl_ObjGetVar2\fR the value is +returned as a pointer to a Tcl_Obj. For \fBTcl_GetVar\fR and +\fBTcl_GetVar2\fR the value is returned as a string; this is +usually less efficient, so \fBTcl_GetVar2Ex\fR or \fBTcl_ObjGetVar2\fR +are preferred. +.VE +If an error occurs while reading the variable (e.g. the variable +doesn't exist or an array element is specified for a scalar +variable), then NULL is returned and an error message is left +in \fIinterp\fR's result if the \fBTCL_LEAVE_ERR_MSG\fR \fIflag\fR +bit is set. +.PP +\fBTcl_UnsetVar\fR and \fBTcl_UnsetVar2\fR may be used to remove +a variable, so that future attempts to read the variable will return +an error. +The arguments to these procedures are treated in the same way +as the arguments to the procedures above. +If the variable is successfully removed then TCL_OK is returned. +If the variable cannot be removed because it doesn't exist then +TCL_ERROR is returned and an error message is left +in \fIinterp\fR's result if the \fBTCL_LEAVE_ERR_MSG\fR \fIflag\fR +bit is set. +If an array element is specified, the given element is removed +but the array remains. +If an array name is specified without an index, then the entire +array is removed. +.PP +The name of a variable may be specified to these procedures in +four ways: +.IP [1] +If \fBTcl_SetVar\fR, \fBTcl_GetVar\fR, or \fBTcl_UnsetVar\fR +is invoked, the variable name is given as +a single string, \fIvarName\fR. +If \fIvarName\fR contains an open parenthesis and ends with a +close parenthesis, then the value between the parentheses is +treated as an index (which can have any string value) and +the characters before the first open +parenthesis are treated as the name of an array variable. +If \fIvarName\fR doesn't have parentheses as described above, then +the entire string is treated as the name of a scalar variable. +.IP [2] +If the \fIname1\fR and \fIname2\fR arguments are provided and +\fIname2\fR is non-NULL, then an array element is specified and +the array name and index have +already been separated by the caller: \fIname1\fR contains the +name and \fIname2\fR contains the index. +.VS 8.1 +An error is generated +if \fIname1\fR contains an open parenthesis and ends with a +close parenthesis (array element) and \fIname2\fR is non-NULL. +.IP [3] +If \fIname2\fR is NULL, \fIname1\fR is treated just like +\fIvarName\fR in case [1] above (it can be either a scalar or an array +element variable name). +.VE +.PP +The \fIflags\fR argument may be used to specify any of several +options to the procedures. +It consists of an OR-ed combination of the following bits. +.TP +\fBTCL_GLOBAL_ONLY\fR +Under normal circumstances the procedures look up variables as follows. +If a procedure call is active in \fIinterp\fR, +the variable is looked up at the current level of procedure call. +Otherwise, the variable is looked up first in the current namespace, +then in the global namespace. +However, if this bit is set in \fIflags\fR then the variable +is looked up only in the global namespace +even if there is a procedure call active. +If both \fBTCL_GLOBAL_ONLY\fR and \fBTCL_NAMESPACE_ONLY\fR are given, +\fBTCL_GLOBAL_ONLY\fR is ignored. +.TP +\fBTCL_NAMESPACE_ONLY\fR +If this bit is set in \fIflags\fR then the variable +is looked up only in the current namespace; if a procedure is active +its variables are ignored, and the global namespace is also ignored unless +it is the current namespace. +.TP +\fBTCL_LEAVE_ERR_MSG\fR +If an error is returned and this bit is set in \fIflags\fR, then +an error message will be left in the interpreter's result, +where it can be retrieved with \fBTcl_GetObjResult\fR +or \fBTcl_GetStringResult\fR. +If this flag bit isn't set then no error message is left +and the interpreter's result will not be modified. +.TP +\fBTCL_APPEND_VALUE\fR +If this bit is set then \fInewValuePtr\fR or \fInewValue\fR is +appended to the current value instead of replacing it. +If the variable is currently undefined, then the bit is ignored. +This bit is only used by the \fBTcl_Set*\fR procedures. +.TP +\fBTCL_LIST_ELEMENT\fR +If this bit is set, then \fInewValue\fR is converted to a valid +Tcl list element before setting (or appending to) the variable. +A separator space is appended before the new list element unless +the list element is going to be the first element in a list or +sublist (i.e. the variable's current value is empty, or contains +the single character ``{'', or ends in `` }''). +.PP +\fBTcl_GetVar\fR and \fBTcl_GetVar2\fR +return the current value of a variable. +The arguments to these procedures are treated in the same way +as the arguments to \fBTcl_SetVar\fR and \fBTcl_SetVar2\fR. +Under normal circumstances, the return value is a pointer +to the variable's value (which is stored in Tcl's variable +structure and will not change before the next call to \fBTcl_SetVar\fR +or \fBTcl_SetVar2\fR). +\fBTcl_GetVar\fR and \fBTcl_GetVar2\fR use the flag bits TCL_GLOBAL_ONLY +and TCL_LEAVE_ERR_MSG, both of +which have +the same meaning as for \fBTcl_SetVar\fR. +If an error occurs in reading the variable (e.g. the variable +doesn't exist or an array element is specified for a scalar +variable), then NULL is returned. +.PP +\fBTcl_UnsetVar\fR and \fBTcl_UnsetVar2\fR may be used to remove +a variable, so that future calls to \fBTcl_GetVar\fR or \fBTcl_GetVar2\fR +for the variable will return an error. +The arguments to these procedures are treated in the same way +as the arguments to \fBTcl_GetVar\fR and \fBTcl_GetVar2\fR. +If the variable is successfully removed then TCL_OK is returned. +If the variable cannot be removed because it doesn't exist then +TCL_ERROR is returned. +If an array element is specified, the given element is removed +but the array remains. +If an array name is specified without an index, then the entire +array is removed. + +.SH "SEE ALSO" +Tcl_GetObjResult, Tcl_GetStringResult, Tcl_TraceVar + +.SH KEYWORDS +array, get variable, interpreter, object, scalar, set, unset, variable diff --git a/mk4/modtcl/tcl8.3.4/doc/Sleep.3 b/mk4/modtcl/tcl8.3.4/doc/Sleep.3 new file mode 100644 index 0000000..48ea6ad --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/Sleep.3 @@ -0,0 +1,37 @@ +'\" +'\" Copyright (c) 1990 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: Sleep.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_Sleep 3 7.5 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_Sleep \- delay execution for a given number of milliseconds +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +\fBTcl_Sleep\fR(\fIms\fR) +.SH ARGUMENTS +.AP int ms in +Number of milliseconds to sleep. +.BE + +.SH DESCRIPTION +.PP +This procedure delays the calling process by the number of +milliseconds given by the \fIms\fR parameter and returns +after that time has elapsed. It is typically used for things +like flashing a button, where the delay is short and the +application needn't do anything while it waits. For longer +delays where the application needs to respond to other events +during the delay, the procedure \fBTcl_CreateTimerHandler\fR +should be used instead of \fBTcl_Sleep\fR. + +.SH KEYWORDS +sleep, time, wait diff --git a/mk4/modtcl/tcl8.3.4/doc/SourceRCFile.3 b/mk4/modtcl/tcl8.3.4/doc/SourceRCFile.3 new file mode 100644 index 0000000..9c6e374 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/SourceRCFile.3 @@ -0,0 +1,38 @@ +'\" +'\" Copyright (c) 1998-2000 by Scriptics Corporation. +'\" All rights reserved. +'\" +'\" RCS: @(#) $Id: SourceRCFile.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +'\" +.so man.macros +.TH Tcl_SourceRCFile 3 8.3 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_SourceRCFile \- source the Tcl rc file +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +void +\fBTcl_SourceRCFile\fR(\fIinterp\fR) +.SH ARGUMENTS +.AP Tcl_Interp *interp in +Tcl interpreter to source rc file into. +.BE + +.SH DESCRIPTION +.PP +\fBTcl_SourceRCFile\fR is used to source the Tcl rc file at startup. +It is typically invoked by Tcl_Main or Tk_Main. The name of the file +sourced is obtained from the global variable \fBtcl_rcFileName\fR in +the interpreter given by \fIinterp\fR. If this variable is not +defined, or if the file it indicates cannot be found, no action is +taken. +.PP +On the Macintosh, after sourcing the rc file, this function will +additionally source the TEXT resource indicated by the global variable +\fBtcl_rcRsrcName\fR in \fIinterp\fR. + +.SH KEYWORDS +application-specific initialization, main program, rc file diff --git a/mk4/modtcl/tcl8.3.4/doc/SplitList.3 b/mk4/modtcl/tcl8.3.4/doc/SplitList.3 new file mode 100644 index 0000000..45488f1 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/SplitList.3 @@ -0,0 +1,175 @@ +'\" +'\" Copyright (c) 1989-1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: SplitList.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_SplitList 3 8.0 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_SplitList, Tcl_Merge, Tcl_ScanElement, Tcl_ConvertElement, Tcl_ScanCountedElement, Tcl_ConvertCountedElement \- manipulate Tcl lists +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +int +\fBTcl_SplitList\fR(\fIinterp, list, argcPtr, argvPtr\fR) +.sp +char * +\fBTcl_Merge\fR(\fIargc, argv\fR) +.sp +int +\fBTcl_ScanElement\fR(\fIsrc, flagsPtr\fR) +.sp +int +\fBTcl_ScanCountedElement\fR(\fIsrc, length, flagsPtr\fR) +.sp +int +\fBTcl_ConvertElement\fR(\fIsrc, dst, flags\fR) +.sp +int +\fBTcl_ConvertCountedElement\fR(\fIsrc, length, dst, flags\fR) +.SH ARGUMENTS +.AS Tcl_Interp ***argvPtr +.AP Tcl_Interp *interp out +Interpreter to use for error reporting. If NULL, then no error message +is left. +.AP char *list in +Pointer to a string with proper list structure. +.AP int *argcPtr out +Filled in with number of elements in \fIlist\fR. +.AP char ***argvPtr out +\fI*argvPtr\fR will be filled in with the address of an array of +pointers to the strings that are the extracted elements of \fIlist\fR. +There will be \fI*argcPtr\fR valid entries in the array, followed by +a NULL entry. +.AP int argc in +Number of elements in \fIargv\fR. +.AP char **argv in +Array of strings to merge together into a single list. +Each string will become a separate element of the list. +.AP char *src in +String that is to become an element of a list. +.AP int *flagsPtr in +Pointer to word to fill in with information about \fIsrc\fR. +The value of *\fIflagsPtr\fR must be passed to \fBTcl_ConvertElement\fR. +.AP int length in +Number of bytes in string \fIsrc\fR. +.AP char *dst in +Place to copy converted list element. Must contain enough characters +to hold converted string. +.AP int flags in +Information about \fIsrc\fR. Must be value returned by previous +call to \fBTcl_ScanElement\fR, possibly OR-ed +with \fBTCL_DONT_USE_BRACES\fR. +.BE + +.SH DESCRIPTION +.PP +These procedures may be used to disassemble and reassemble Tcl lists. +\fBTcl_SplitList\fR breaks a list up into its constituent elements, +returning an array of pointers to the elements using +\fIargcPtr\fR and \fIargvPtr\fR. +While extracting the arguments, \fBTcl_SplitList\fR obeys the usual +rules for backslash substitutions and braces. The area of +memory pointed to by \fI*argvPtr\fR is dynamically allocated; in +addition to the array of pointers, it +also holds copies of all the list elements. It is the caller's +responsibility to free up all of this storage. +For example, suppose that you have called \fBTcl_SplitList\fR with +the following code: +.CS +int argc, code; +char *string; +char **argv; +\&... +code = Tcl_SplitList(interp, string, &argc, &argv); +.CE +Then you should eventually free the storage with a call like the +following: +.CS +Tcl_Free((char *) argv); +.CE +.PP +\fBTcl_SplitList\fR normally returns \fBTCL_OK\fR, which means the list was +successfully parsed. +If there was a syntax error in \fIlist\fR, then \fBTCL_ERROR\fR is returned +and the interpreter's result will point to an error message describing the +problem (if \fIinterp\fR was not NULL). +If \fBTCL_ERROR\fR is returned then no memory is allocated and \fI*argvPtr\fR +is not modified. +.PP +\fBTcl_Merge\fR is the inverse of \fBTcl_SplitList\fR: it +takes a collection of strings given by \fIargc\fR +and \fIargv\fR and generates a result string +that has proper list structure. +This means that commands like \fBindex\fR may be used to +extract the original elements again. +In addition, if the result of \fBTcl_Merge\fR is passed to \fBTcl_Eval\fR, +it will be parsed into \fIargc\fR words whose values will +be the same as the \fIargv\fR strings passed to \fBTcl_Merge\fR. +\fBTcl_Merge\fR will modify the list elements with braces and/or +backslashes in order to produce proper Tcl list structure. +The result string is dynamically allocated +using \fBTcl_Alloc\fR; the caller must eventually release the space +using \fBTcl_Free\fR. +.PP +If the result of \fBTcl_Merge\fR is passed to \fBTcl_SplitList\fR, +the elements returned by \fBTcl_SplitList\fR will be identical to +those passed into \fBTcl_Merge\fR. +However, the converse is not true: if \fBTcl_SplitList\fR +is passed a given string, and the resulting \fIargc\fR and +\fIargv\fR are passed to \fBTcl_Merge\fR, the resulting string +may not be the same as the original string passed to \fBTcl_SplitList\fR. +This is because \fBTcl_Merge\fR may use backslashes and braces +differently than the original string. +.PP +\fBTcl_ScanElement\fR and \fBTcl_ConvertElement\fR are the +procedures that do all of the real work of \fBTcl_Merge\fR. +\fBTcl_ScanElement\fR scans its \fIsrc\fR argument +and determines how to use backslashes and braces +when converting it to a list element. +It returns an overestimate of the number of characters +required to represent \fIsrc\fR as a list element, and +it stores information in \fI*flagsPtr\fR that is needed +by \fBTcl_ConvertElement\fR. +.PP +\fBTcl_ConvertElement\fR is a companion procedure to \fBTcl_ScanElement\fR. +It does the actual work of converting a string to a list element. +Its \fIflags\fR argument must be the same as the value returned +by \fBTcl_ScanElement\fR. +\fBTcl_ConvertElement\fR writes a proper list element to memory +starting at *\fIdst\fR and returns a count of the total number +of characters written, which will be no more than the result +returned by \fBTcl_ScanElement\fR. +\fBTcl_ConvertElement\fR writes out only the actual list element +without any leading or trailing spaces: it is up to the caller to +include spaces between adjacent list elements. +.PP +\fBTcl_ConvertElement\fR uses one of two different approaches to +handle the special characters in \fIsrc\fR. Wherever possible, it +handles special characters by surrounding the string with braces. +This produces clean-looking output, but can't be used in some situations, +such as when \fIsrc\fR contains unmatched braces. +In these situations, \fBTcl_ConvertElement\fR handles special +characters by generating backslash sequences for them. +The caller may insist on the second approach by OR-ing the +flag value returned by \fBTcl_ScanElement\fR with +\fBTCL_DONT_USE_BRACES\fR. +Although this will produce an uglier result, it is useful in some +special situations, such as when \fBTcl_ConvertElement\fR is being +used to generate a portion of an argument for a Tcl command. +In this case, surrounding \fIsrc\fR with curly braces would cause +the command not to be parsed correctly. +.PP +\fBTcl_ScanCountedElement\fR and \fBTcl_ConvertCountedElement\fR are +the same as \fBTcl_ScanElement\fR and \fBTcl_ConvertElement\fR, except +the length of string \fIsrc\fR is specified by the \fIlength\fR +argument, and the string may contain embedded nulls. + +.SH KEYWORDS +backslash, convert, element, list, merge, split, strings diff --git a/mk4/modtcl/tcl8.3.4/doc/SplitPath.3 b/mk4/modtcl/tcl8.3.4/doc/SplitPath.3 new file mode 100644 index 0000000..e14e7bc --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/SplitPath.3 @@ -0,0 +1,93 @@ +'\" +'\" Copyright (c) 1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: SplitPath.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_SplitPath 3 7.5 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_SplitPath, Tcl_JoinPath, Tcl_GetPathType \- manipulate platform-dependent file paths +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +\fBTcl_SplitPath\fR(\fIpath, argcPtr, argvPtr\fR) +.sp +char * +\fBTcl_JoinPath\fR(\fIargc, argv, resultPtr\fR) +.sp +Tcl_PathType +\fBTcl_GetPathType\fR(\fIpath\fR) +.SH ARGUMENTS +.AS Tcl_DString ***argvPtr +.AP char *path in +File path in a form appropriate for the current platform (see the +\fBfilename\fR manual entry for acceptable forms for path names). +.AP int *argcPtr out +Filled in with number of path elements in \fIpath\fR. +.AP char ***argvPtr out +\fI*argvPtr\fR will be filled in with the address of an array of +pointers to the strings that are the extracted elements of \fIpath\fR. +There will be \fI*argcPtr\fR valid entries in the array, followed by +a NULL entry. +.AP int argc in +Number of elements in \fIargv\fR. +.AP char **argv in +Array of path elements to merge together into a single path. +.AP Tcl_DString *resultPtr in/out +A pointer to an initialized \fBTcl_DString\fR to which the result of +\fBTcl_JoinPath\fR will be appended. +.BE + +.SH DESCRIPTION +.PP +These procedures may be used to disassemble and reassemble file +paths in a platform independent manner: they provide C-level access to +the same functionality as the \fBfile split\fR, \fBfile join\fR, and +\fBfile pathtype\fR commands. +.PP +\fBTcl_SplitPath\fR breaks a path into its constituent elements, +returning an array of pointers to the elements using \fIargcPtr\fR and +\fIargvPtr\fR. The area of memory pointed to by \fI*argvPtr\fR is +dynamically allocated; in addition to the array of pointers, it also +holds copies of all the path elements. It is the caller's +responsibility to free all of this storage. +For example, suppose that you have called \fBTcl_SplitPath\fR with the +following code: +.CS +int argc; +char *path; +char **argv; +\&... +Tcl_SplitPath(string, &argc, &argv); +.CE +Then you should eventually free the storage with a call like the +following: +.CS +Tcl_Free((char *) argv); +.CE +.PP +\fBTcl_JoinPath\fR is the inverse of \fBTcl_SplitPath\fR: it takes a +collection of path elements given by \fIargc\fR and \fIargv\fR and +generates a result string that is a properly constructed path. The +result string is appended to \fIresultPtr\fR. \fIResultPtr\fR must +refer to an initialized \fBTcl_DString\fR. +.PP +If the result of \fBTcl_SplitPath\fR is passed to \fBTcl_JoinPath\fR, +the result will refer to the same location, but may not be in the same +form. This is because \fBTcl_SplitPath\fR and \fBTcl_JoinPath\fR +eliminate duplicate path separators and return a normalized form for +each platform. +.PP +\fBTcl_GetPathType\fR returns the type of the specified \fIpath\fR, +where \fBTcl_PathType\fR is one of \fBTCL_PATH_ABSOLUTE\fR, +\fBTCL_PATH_RELATIVE\fR, or \fBTCL_PATH_VOLUME_RELATIVE\fR. See the +\fBfilename\fR manual entry for a description of the path types for +each platform. + +.SH KEYWORDS +file, filename, join, path, split, type diff --git a/mk4/modtcl/tcl8.3.4/doc/StaticPkg.3 b/mk4/modtcl/tcl8.3.4/doc/StaticPkg.3 new file mode 100644 index 0000000..8e45f9c --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/StaticPkg.3 @@ -0,0 +1,69 @@ +'\" +'\" Copyright (c) 1995-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: StaticPkg.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_StaticPackage 3 7.5 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_StaticPackage \- make a statically linked package available via the \fBload\fR command +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +\fBTcl_StaticPackage\fR(\fIinterp, pkgName, initProc, safeInitProc\fR) +.SH ARGUMENTS +.AS Tcl_PackageInitProc *safeInitProc +.AP Tcl_Interp *interp in +If not NULL, points to an interpreter into which the package has +already been loaded (i.e., the caller has already invoked the +appropriate initialization procedure). NULL means the package +hasn't yet been incorporated into any interpreter. +.AP char *pkgName in +Name of the package; should be properly capitalized (first letter +upper-case, all others lower-case). +.AP Tcl_PackageInitProc *initProc in +Procedure to invoke to incorporate this package into a trusted +interpreter. +.AP Tcl_PackageInitProc *safeInitProc in +Procedure to call to incorporate this package into a safe interpreter +(one that will execute untrusted scripts). NULL means the package +can't be used in safe interpreters. +.BE + +.SH DESCRIPTION +.PP +This procedure may be invoked to announce that a package has been +linked statically with a Tcl application and, optionally, that it +has already been loaded into an interpreter. +Once \fBTcl_StaticPackage\fR has been invoked for a package, it +may be loaded into interpreters using the \fBload\fR command. +\fBTcl_StaticPackage\fR is normally invoked only by the \fBTcl_AppInit\fR +procedure for the application, not by packages for themselves +(\fBTcl_StaticPackage\fR should only be invoked for statically +loaded packages, and code in the package itself should not need +to know whether the package is dynamically or statically loaded). +.PP +When the \fBload\fR command is used later to load the package into +an interpreter, one of \fIinitProc\fR and \fIsafeInitProc\fR will +be invoked, depending on whether the target interpreter is safe +or not. +\fIinitProc\fR and \fIsafeInitProc\fR must both match the +following prototype: +.CS +typedef int Tcl_PackageInitProc(Tcl_Interp *\fIinterp\fR); +.CE +The \fIinterp\fR argument identifies the interpreter in which the package +is to be loaded. The initialization procedure must return \fBTCL_OK\fR or +\fBTCL_ERROR\fR to indicate whether or not it completed successfully; in +the event of an error it should set the interpreter's result to point to an +error message. The result or error from the initialization procedure will +be returned as the result of the \fBload\fR command that caused the +initialization procedure to be invoked. + +.SH KEYWORDS +initialization procedure, package, static linking diff --git a/mk4/modtcl/tcl8.3.4/doc/StrMatch.3 b/mk4/modtcl/tcl8.3.4/doc/StrMatch.3 new file mode 100644 index 0000000..a53d8d6 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/StrMatch.3 @@ -0,0 +1,52 @@ +'\" +'\" Copyright (c) 1989-1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: StrMatch.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_StringMatch 3 8.1 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_StringMatch, Tcl_StringCaseMatch \- test whether a string matches a pattern +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +int +\fBTcl_StringMatch\fR(\fIstring\fR, \fIpattern\fR) +.sp +int +\fBTcl_StringCaseMatch\fR(\fIstring\fR, \fIpattern\fR, \fInocase\fR) +.SH ARGUMENTS +.AP char *string in +String to test. +.AP char *pattern in +Pattern to match against string. May contain special +characters from the set *?\e[]. +.AP int nocase in +Specifies whether the match should be done case-sensitive (0) or +case-insensitive (1). +.BE + +.SH DESCRIPTION +.PP +This utility procedure determines whether a string matches +a given pattern. If it does, then \fBTcl_StringMatch\fR returns +1. Otherwise \fBTcl_StringMatch\fR returns 0. The algorithm +used for matching is the same algorithm used in the ``string match'' +Tcl command and is similar to the algorithm used by the C-shell +for file name matching; see the Tcl manual entry for details. +.VS 8.1 +.PP +In \fBTcl_StringCaseMatch\fR, the algorithm is the same, but you have +the option to make the matching case-insensitive. If you choose this +(by passing \fBnocase\fR as 1), then the string and pattern are +essentially matched in the lower case. +.VE 8.1 + +.SH KEYWORDS +match, pattern, string diff --git a/mk4/modtcl/tcl8.3.4/doc/StringObj.3 b/mk4/modtcl/tcl8.3.4/doc/StringObj.3 new file mode 100644 index 0000000..6797d8f --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/StringObj.3 @@ -0,0 +1,246 @@ +'\" +'\" Copyright (c) 1994-1997 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: StringObj.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_StringObj 3 8.1 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_NewStringObj, Tcl_NewUnicodeObj, Tcl_SetStringObj, Tcl_SetUnicodeObj, Tcl_GetStringFromObj, Tcl_GetString, Tcl_GetUnicode, Tcl_GetUniChar, Tcl_GetCharLength, Tcl_GetRange, Tcl_AppendToObj, Tcl_AppendUnicodeToObj, Tcl_AppendStringsToObj, Tcl_AppendStringsToObjVA, Tcl_AppendObjToObj, Tcl_SetObjLength, Tcl_ConcatObj \- manipulate Tcl objects as strings +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +Tcl_Obj * +\fBTcl_NewStringObj\fR(\fIbytes, length\fR) +.VS 8.1.2 +.sp +Tcl_Obj * +\fBTcl_NewUnicodeObj\fR(\fIunicode, numChars\fR) +.VE +.sp +void +\fBTcl_SetStringObj\fR(\fIobjPtr, bytes, length\fR) +.VS 8.1.2 +.sp +void +\fBTcl_SetUnicodeObj\fR(\fIobjPtr, unicode, numChars\fR) +.VE +.sp +char * +\fBTcl_GetStringFromObj\fR(\fIobjPtr, lengthPtr\fR) +.sp +char * +\fBTcl_GetString\fR(\fIobjPtr\fR) +.VS 8.1.2 +.sp +Tcl_UniChar * +\fBTcl_GetUnicode\fR(\fIobjPtr\fR) +.sp +Tcl_UniChar +\fBTcl_GetUniChar\fR(\fIobjPtr, index\fR) +.sp +int +\fBTcl_GetCharLength\fR(\fIobjPtr\fR) +.sp +Tcl_Obj * +\fBTcl_GetRange\fR(\fIobjPtr, first, last\fR) +.VE +.sp +void +\fBTcl_AppendToObj\fR(\fIobjPtr, bytes, length\fR) +.VS 8.1.2 +.sp +void +\fBTcl_AppendUnicodeToObj\fR(\fIobjPtr, unicode, numChars\fR) +.VE +.sp +void +\fBTcl_AppendObjToObj\fR(\fIobjPtr, appendObjPtr\fR) +.sp +void +\fBTcl_AppendStringsToObj\fR(\fIobjPtr, string, string, ... \fB(char *) NULL\fR) +.sp +void +\fBTcl_AppendStringsToObjVA\fR(\fIobjPtr, argList\fR) +.sp +void +\fBTcl_SetObjLength\fR(\fIobjPtr, newLength\fR) +.sp +Tcl_Obj * +\fBTcl_ConcatObj\fR(\fIobjc, objv\fR) +.SH ARGUMENTS +.AS Tcl_Interp *appendObjPtr in/out +.AP char *bytes in +Points to the first byte of an array of bytes +used to set or append to a string object. +This byte array may contain embedded null bytes +unless \fIlength\fR is negative. +.AP int length in +The number of bytes to copy from \fIbytes\fR when +initializing, setting, or appending to a string object. +If negative, all bytes up to the first null are used. +.AP Tcl_UniChar *unicode in +Points to the first byte of an array of Unicode characters +used to set or append to a string object. +This byte array may contain embedded null characters +unless \fInumChars\fR is negative. +.VS 8.1.2 +.AP int numChars in +The number of Unicode characters to copy from \fIunicode\fR when +initializing, setting, or appending to a string object. +If negative, all characters up to the first null character are used. +.AP int index in +The index of the Unicode character to return. +.AP int first in +The index of the first Unicode character in the Unicode range to be +returned as a new object. +.AP int last in +The index of the last Unicode character in the Unicode range to be +returned as a new object. +.VE +.AP Tcl_Obj *objPtr in/out +Points to an object to manipulate. +.AP Tcl_Obj *appendObjPtr in +The object to append to \fIobjPtr\fR in \fBTcl_AppendObjToObj\fR. +.AP int *lengthPtr out +If non-NULL, the location where \fBTcl_GetStringFromObj\fR will store +the the length of an object's string representation. +.AP char *string in +Null-terminated string value to append to \fIobjPtr\fR. +.AP va_list argList in +An argument list which must have been initialised using +\fBTCL_VARARGS_START\fR, and cleared using \fBva_end\fR. +.AP int newLength in +New length for the string value of \fIobjPtr\fR, not including the +final NULL character. +.AP int objc in +The number of elements to concatenate. +.AP Tcl_Obj *objv[] in +The array of objects to concatenate. +.BE + +.SH DESCRIPTION +.PP +The procedures described in this manual entry allow Tcl objects to +be manipulated as string values. They use the internal representation +of the object to store additional information to make the string +manipulations more efficient. In particular, they make a series of +append operations efficient by allocating extra storage space for the +string so that it doesn't have to be copied for each append. +.VS 8.1.2 +Also, indexing and length computations are optimized because the +Unicode string representation is calculated and cached as needed. +.VE +.PP +.VS 8.1.2 +\fBTcl_NewStringObj\fR and \fBTcl_SetStringObj\fR create a new object +or modify an existing object to hold a copy of the string given by +\fIbytes\fR and \fIlength\fR. \fBTcl_NewUnicodeObj\fR and +\fBTcl_SetUnicodeObj\fR create a new object or modify an existing +object to hold a copy of the Unicode string given by \fIunicode\fR and +\fInumChars\fR. \fBTcl_NewStringObj\fR and \fBTcl_NewUnicodeObj\fR +return a pointer to a newly created object with reference count zero. +All four procedures set the object to hold a copy of the specified +string. \fBTcl_SetStringObj\fR and \fBTcl_SetUnicodeObj\fR free any +old string representation as well as any old internal representation +of the object. +.VE +.PP +\fBTcl_GetStringFromObj\fR and \fBTcl_GetString\fR return an object's +string representation. This is given by the returned byte pointer and +(for \fBTcl_GetStringFromObj\fR) length, which is stored in +\fIlengthPtr\fR if it is non-NULL. If the object's UTF string +representation is invalid (its byte pointer is NULL), the string +representation is regenerated from the object's internal +representation. The storage referenced by the returned byte pointer +is owned by the object manager and should not be modified by the +caller. The procedure \fBTcl_GetString\fR is used in the common case +where the caller does not need the length of the string +representation. +.PP +.VS 8.1.2 +\fBTcl_GetUnicode\fR returns an object's value as a Unicode string. +\fBTcl_GetUniChar\fR returns the \fIindex\fR'th character in the +object's Unicode representation. +.PP +\fBTcl_GetRange\fR returns a newly created object comprised of the +characters between \fIfirst\fR and \fIlast\fR (inclusive) in the +object's Unicode representation. If the object's Unicode +representation is invalid, the Unicode representation is regenerated +from the object's string representation. +.PP +\fBTcl_GetCharLength\fR returns the number of characters (as opposed +to bytes) in the string object. +.PP +\fBTcl_AppendToObj\fR appends the data given by \fIbytes\fR and +\fIlength\fR to the string representation of the object specified by +\fIobjPtr\fR. If the object has an invalid string representation, +then an attempt is made to convert \fIbytes\fR is to the Unicode +format. If the conversion is successful, then the converted form of +\fIbytes\fR is appended to the object's Unicode representation. +Otherwise, the object's Unicode representation is invalidated and +converted to the UTF format, and \fIbytes\fR is appended to the +object's new string representation. +.PP +\fBTcl_AppendUnicodeToObj\fR appends the Unicode string given by +\fIunicode\fR and \fInumChars\fR to the object specified by +\fIobjPtr\fR. If the object has an invalid Unicode representation, +then \fIunicode\fR is converted to the UTF format and appended to the +object's string representation. Appends are optimized to handle +repeated appends relatively efficiently (it overallocates the string +or Unicode space to avoid repeated reallocations and copies of +object's string value). +.PP +\fBTcl_AppendObjToObj\fR is similar to \fBTcl_AppendToObj\fR, but it +appends the string or Unicode value (whichever exists and is best +suited to be appended to \fIobjPtr\fR) of \fIappendObjPtr\fR to +\fIobjPtr\fR. +.VE +.PP +\fBTcl_AppendStringsToObj\fR is similar to \fBTcl_AppendToObj\fR +except that it can be passed more than one value to append and +each value must be a null-terminated string (i.e. none of the +values may contain internal null characters). Any number of +\fIstring\fR arguments may be provided, but the last argument +must be a NULL pointer to indicate the end of the list. +.PP +\fBTcl_AppendStringsToObjVA\fR is the same as \fBTcl_AppendStringsToObj\fR +except that instead of taking a variable number of arguments it takes an +argument list. +.PP +The \fBTcl_SetObjLength\fR procedure changes the length of the +string value of its \fIobjPtr\fR argument. If the \fInewLength\fR +argument is greater than the space allocated for the object's +string, then the string space is reallocated and the old value +is copied to the new space; the bytes between the old length of +the string and the new length may have arbitrary values. +If the \fInewLength\fR argument is less than the current length +of the object's string, with \fIobjPtr->length\fR is reduced without +reallocating the string space; the original allocated size for the +string is recorded in the object, so that the string length can be +enlarged in a subsequent call to \fBTcl_SetObjLength\fR without +reallocating storage. In all cases \fBTcl_SetObjLength\fR leaves +a null character at \fIobjPtr->bytes[newLength]\fR. +.PP +The \fBTcl_ConcatObj\fR function returns a new string object whose +value is the space-separated concatenation of the string +representations of all of the objects in the \fIobjv\fR +array. \fBTcl_ConcatObj\fR eliminates leading and trailing white space +as it copies the string representations of the \fIobjv\fR array to the +result. If an element of the \fIobjv\fR array consists of nothing but +white space, then that object is ignored entirely. This white-space +removal was added to make the output of the \fBconcat\fR command +cleaner-looking. \fBTcl_ConcatObj\fR returns a pointer to a +newly-created object whose ref count is zero. + +.SH "SEE ALSO" +Tcl_NewObj, Tcl_IncrRefCount, Tcl_DecrRefCount + +.SH KEYWORDS +append, internal representation, object, object type, string object, +string type, string representation, concat, concatenate, unicode diff --git a/mk4/modtcl/tcl8.3.4/doc/TCL_MEM_DEBUG.3 b/mk4/modtcl/tcl8.3.4/doc/TCL_MEM_DEBUG.3 new file mode 100644 index 0000000..8d891fb --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/TCL_MEM_DEBUG.3 @@ -0,0 +1,82 @@ +'\" +'\" Copyright (c) 1992-1999 Karl Lehenbauer and Mark Diekhans. +'\" Copyright (c) 2000 by Scriptics Corporation. +'\" All rights reserved. +'\" +'\" RCS: @(#) $Id: TCL_MEM_DEBUG.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH TCL_MEM_DEBUG 3 8.1 Tcl "Tcl Library Procedures" +.BS +.SH NAME +TCL_MEM_DEBUG \- Compile-time flag to enable Tcl memory debugging. + +.SH DESCRIPTION +When Tcl is compiled with \fBTCL_MEM_DEBUG\fR defined, a powerful set +of memory debugging aids are included in the compiled binary. This +includes C and Tcl functions which can aid with debugging +memory leaks, memory allocation overruns, and other memory related +errors. + +.SH ENABLING MEMORY DEBUGGING +.PP +To enable memory debugging, Tcl should be recompiled from scratch with +\fBTCL_MEM_DEBUG\fR defined. This will also compile in a non-stub +version of \fBTcl_InitMemory\fR to add the \fBmemory\fR command to Tcl. +.PP +\fBTCL_MEM_DEBUG\fR must be either left defined for all modules or undefined +for all modules that are going to be linked together. If they are not, link +errors will occur, with either \fBTclDbCkfree\fR and \fBTcl_DbCkalloc\fR or +\fBTcl_Ckalloc\fR and \fBTcl_Ckfree\fR being undefined. +.PP +Once memory debugging support has been compiled into Tcl, the C +functions \fBTcl_ValidateAllMemory\fR, and \fBTcl_DumpActiveMemory\fR, +and the Tcl \fBmemory\fR command can be used to validate and examine +memory usage. + +.SH GUARD ZONES +.PP +When memory debugging is enabled, whenever a call to \fBckalloc\fR is +made, slightly more memory than requested is allocated so the memory debugging +code can keep track of the allocated memory, and eight-byte ``guard +zones'' are placed in front of and behind the space that will be +returned to the caller. (The sizes of the guard zones are defined by the +C #define \fBLOW_GUARD_SIZE\fR and #define \fBHIGH_GUARD_SIZE\fR +in the file \fIgeneric/tclCkalloc.c\fR -- it can +be extended if you suspect large overwrite problems, at some cost in +performance.) A known pattern is written into the guard zones and, on +a call to \fBckfree\fR, the guard zones of the space being freed are +checked to see if either zone has been modified in any way. If one +has been, the guard bytes and their new contents are identified, and a +``low guard failed'' or ``high guard failed'' message is issued. The +``guard failed'' message includes the address of the memory packet and +the file name and line number of the code that called \fBckfree\fR. +This allows you to detect the common sorts of one-off problems, where +not enough space was allocated to contain the data written, for +example. + +.SH DEBUGGING DIFFICULT MEMORY CORRUPTION PROBLEMS +.PP +Normally, Tcl compiled with memory debugging enabled will make it easy +to isolate a corruption problem. Turning on memory validation with +the memory command can help isolate difficult problems. If you +suspect (or know) that corruption is occurring before the Tcl +interpreter comes up far enough for you to issue commands, you can set +\fBMEM_VALIDATE\fR define, recompile tclCkalloc.c and rebuild Tcl. +This will enable memory validation from the first call to +\fBckalloc\fR, again, at a large performance impact. +.PP +If you are desperate and validating memory on every call to +\fBckalloc\fR and \fBckfree\fR isn't enough, you can explicitly call +\fBTcl_ValidateAllMemory\fR directly at any point. It takes a \fIchar +*\fR and an \fIint\fR which are normally the filename and line number +of the caller, but they can actually be anything you want. Remember +to remove the calls after you find the problem. + +.SH "SEE ALSO" +memory, Tcl_ValidateAllMemory, Tcl_DumpActiveMemory + +.SH KEYWORDS +memory, debug + + diff --git a/mk4/modtcl/tcl8.3.4/doc/Tcl.n b/mk4/modtcl/tcl8.3.4/doc/Tcl.n new file mode 100644 index 0000000..8f3534a --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/Tcl.n @@ -0,0 +1,195 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: Tcl.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl n "8.1" Tcl "Tcl Built-In Commands" +.BS +.SH NAME +Tcl \- Summary of Tcl language syntax. +.BE + +.SH DESCRIPTION +.PP +The following rules define the syntax and semantics of the Tcl language: +.IP [1] +A Tcl script is a string containing one or more commands. +Semi-colons and newlines are command separators unless quoted as +described below. +Close brackets are command terminators during command substitution +(see below) unless quoted. +.IP [2] +A command is evaluated in two steps. +First, the Tcl interpreter breaks the command into \fIwords\fR +and performs substitutions as described below. +These substitutions are performed in the same way for all +commands. +The first word is used to locate a command procedure to +carry out the command, then all of the words of the command are +passed to the command procedure. +The command procedure is free to interpret each of its words +in any way it likes, such as an integer, variable name, list, +or Tcl script. +Different commands interpret their words differently. +.IP [3] +Words of a command are separated by white space (except for +newlines, which are command separators). +.IP [4] +If the first character of a word is double-quote (``"'') then +the word is terminated by the next double-quote character. +If semi-colons, close brackets, or white space characters +(including newlines) appear between the quotes then they are treated +as ordinary characters and included in the word. +Command substitution, variable substitution, and backslash substitution +are performed on the characters between the quotes as described below. +The double-quotes are not retained as part of the word. +.IP [5] +If the first character of a word is an open brace (``{'') then +the word is terminated by the matching close brace (``}''). +Braces nest within the word: for each additional open +brace there must be an additional close brace (however, +if an open brace or close brace within the word is +quoted with a backslash then it is not counted in locating the +matching close brace). +No substitutions are performed on the characters between the +braces except for backslash-newline substitutions described +below, nor do semi-colons, newlines, close brackets, +or white space receive any special interpretation. +The word will consist of exactly the characters between the +outer braces, not including the braces themselves. +.IP [6] +If a word contains an open bracket (``['') then Tcl performs +\fIcommand substitution\fR. +To do this it invokes the Tcl interpreter recursively to process +the characters following the open bracket as a Tcl script. +The script may contain any number of commands and must be terminated +by a close bracket (``]''). +The result of the script (i.e. the result of its last command) is +substituted into the word in place of the brackets and all of the +characters between them. +There may be any number of command substitutions in a single word. +Command substitution is not performed on words enclosed in braces. +.IP [7] +If a word contains a dollar-sign (``$'') then Tcl performs \fIvariable +substitution\fR: the dollar-sign and the following characters are +replaced in the word by the value of a variable. +Variable substitution may take any of the following forms: +.RS +.TP 15 +\fB$\fIname\fR +\fIName\fR is the name of a scalar variable; the name is terminated +by any character that isn't a letter, digit, or underscore. +.TP 15 +\fB$\fIname\fB(\fIindex\fB)\fR +\fIName\fR gives the name of an array variable and \fIindex\fR gives +the name of an element within that array. +\fIName\fR must contain only letters, digits, and underscores. +Command substitutions, variable substitutions, and backslash +substitutions are performed on the characters of \fIindex\fR. +.TP 15 +\fB${\fIname\fB}\fR +\fIName\fR is the name of a scalar variable. It may contain any +characters whatsoever except for close braces. +.LP +There may be any number of variable substitutions in a single word. +Variable substitution is not performed on words enclosed in braces. +.RE +.IP [8] +If a backslash (``\e'') appears within a word then +\fIbackslash substitution\fR occurs. +In all cases but those described below the backslash is dropped and +the following character is treated as an ordinary +character and included in the word. +This allows characters such as double quotes, close brackets, +and dollar signs to be included in words without triggering +special processing. +The following table lists the backslash sequences that are +handled specially, along with the value that replaces each sequence. +.RS +.TP 7 +\e\fBa\fR +Audible alert (bell) (0x7). +.TP 7 +\e\fBb\fR +Backspace (0x8). +.TP 7 +\e\fBf\fR +Form feed (0xc). +.TP 7 +\e\fBn\fR +Newline (0xa). +.TP 7 +\e\fBr\fR +Carriage-return (0xd). +.TP 7 +\e\fBt\fR +Tab (0x9). +.TP 7 +\e\fBv\fR +Vertical tab (0xb). +.TP 7 +\e\fB\fIwhiteSpace\fR +. +A single space character replaces the backslash, newline, and all spaces +and tabs after the newline. This backslash sequence is unique in that it +is replaced in a separate pre-pass before the command is actually parsed. +This means that it will be replaced even when it occurs between braces, +and the resulting space will be treated as a word separator if it isn't +in braces or quotes. +.TP 7 +\e\e +Backslash (``\e''). +.VS 8.1 br +.TP 7 +\e\fIooo\fR +. +The digits \fIooo\fR (one, two, or three of them) give an eight-bit octal +value for the Unicode character that will be inserted. The upper bits of the +Unicode character will be 0. +.TP 7 +\e\fBx\fIhh\fR +. +The hexadecimal digits \fIhh\fR give an eight-bit hexadecimal value for the +Unicode character that will be inserted. Any number of hexadecimal digits +may be present; however, all but the last two are ignored (the result is +always a one-byte quantity). The upper bits of the Unicode character will +be 0. +.TP 7 +\e\fBu\fIhhhh\fR +. +The hexadecimal digits \fIhhhh\fR (one, two, three, or four of them) give a +sixteen-bit hexadecimal value for the Unicode character that will be +inserted. +.VE +.LP +Backslash substitution is not performed on words enclosed in braces, +except for backslash-newline as described above. +.RE +.IP [9] +If a hash character (``#'') appears at a point where Tcl is +expecting the first character of the first word of a command, +then the hash character and the characters that follow it, up +through the next newline, are treated as a comment and ignored. +The comment character only has significance when it appears +at the beginning of a command. +.IP [10] +Each character is processed exactly once by the Tcl interpreter +as part of creating the words of a command. +For example, if variable substitution occurs then no further +substitutions are performed on the value of the variable; the +value is inserted into the word verbatim. +If command substitution occurs then the nested command is +processed entirely by the recursive call to the Tcl interpreter; +no substitutions are performed before making the recursive +call and no additional substitutions are performed on the result +of the nested script. +.IP [11] +Substitutions do not affect the word boundaries of a command. +For example, during variable substitution the entire value of +the variable becomes part of a single word, even if the variable's +value contains spaces. diff --git a/mk4/modtcl/tcl8.3.4/doc/Tcl_Main.3 b/mk4/modtcl/tcl8.3.4/doc/Tcl_Main.3 new file mode 100644 index 0000000..a52bf6e --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/Tcl_Main.3 @@ -0,0 +1,81 @@ +'\" +'\" Copyright (c) 1994 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" Copyright (c) 2000 Ajuba Solutions. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: Tcl_Main.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_Main 3 8.3.4 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_Main, Tcl_SetMainLoop \- main program and event loop definition for Tcl-based applications +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +\fBTcl_Main\fR(\fIargc, argv, appInitProc\fR) +.sp +\fBTcl_SetMainLoop\fR(\fImainLoopProc\fR) +.SH ARGUMENTS +.AS Tcl_AppInitProc *appInitProc +.AP int argc in +Number of elements in \fIargv\fR. +.AP char *argv[] in +Array of strings containing command-line arguments. +.AP Tcl_AppInitProc *appInitProc in +Address of an application-specific initialization procedure. +The value for this argument is usually \fBTcl_AppInit\fR. +.AP Tcl_MainLoopProc *mainLoopProc in +Address of an application-specific event loop procedure. +.BE + +.SH DESCRIPTION +.PP +\fBTcl_Main\fR acts as the main program for most Tcl-based applications. +Starting with Tcl 7.4 it is not called \fBmain\fR anymore because it +is part of the Tcl library and having a function \fBmain\fR +in a library (particularly a shared library) causes problems on many +systems. +Having \fBmain\fR in the Tcl library would also make it hard to use +Tcl in C++ programs, since C++ programs must have special C++ +\fBmain\fR functions. +.PP +Normally each application contains a small \fBmain\fR function that does +nothing but invoke \fBTcl_Main\fR. +\fBTcl_Main\fR then does all the work of creating and running a +\fBtclsh\fR-like application. +.PP +When it is has finished its own initialization, but before +it processes commands, \fBTcl_Main\fR calls the procedure given by +the \fIappInitProc\fR argument. This procedure provides a ``hook'' +for the application to perform its own initialization, such as defining +application-specific commands. The procedure must have an interface +that matches the type \fBTcl_AppInitProc\fR: +.CS +typedef int Tcl_AppInitProc(Tcl_Interp *\fIinterp\fR); +.CE + +\fIAppInitProc\fR is almost always a pointer to \fBTcl_AppInit\fR; for more +details on this procedure, see the documentation for \fBTcl_AppInit\fR. +When the \fIappInitProc\fR is finished, the startup script will be +evaluated. If none exists, then an interactive prompt is provided. +.PP +.VS 8.3.4 +\fBTcl_SetMainLoop\fR allows setting an event loop procedure to be run. +This allows, for example, Tk to be dynamically loaded and set its event +loop. The event loop will run following the startup script. If you +are in interactive mode, setting the main loop procedure will cause the +prompt to become fileevent based and then the loop procedure is called. +The main loop procedure must have an interface that matches the type +\fBTcl_MainLoopProc\fR: +.CS +typedef void Tcl_MainLoopProc(void); +.CE +.VE 8.3.4 + +.SH KEYWORDS +application-specific initialization, command-line arguments, main program diff --git a/mk4/modtcl/tcl8.3.4/doc/Thread.3 b/mk4/modtcl/tcl8.3.4/doc/Thread.3 new file mode 100644 index 0000000..4f676fb --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/Thread.3 @@ -0,0 +1,194 @@ +'\" +'\" Copyright (c) 1999 Scriptics Corporation +'\" Copyright (c) 1998 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: Thread.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Threads 3 "8.1" Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_ConditionNotify, Tcl_ConditionWait, Tcl_ConditionFinalize, Tcl_GetThreadData, Tcl_MutexLock, Tcl_MutexUnlock, Tcl_MutexFinalize, Tcl_CreateThread \- Tcl thread support. +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +void +\fBTcl_ConditionNotify\fR(\fIcondPtr\fR) +.sp +void +\fBTcl_ConditionWait\fR(\fIcondPtr, mutexPtr, timePtr\fR) +.sp +void +\fBTcl_ConditionFinalize\fR(\fIcondPtr\fR) +.sp +Void * +\fBTcl_GetThreadData\fR(\fIkeyPtr, size\fR) +.sp +void +\fBTcl_MutexLock\fR(\fImutexPtr\fR) +.sp +void +\fBTcl_MutexUnlock\fR(\fImutexPtr\fR) +.sp +void +\fBTcl_MutexFinalize\fR(\fImutexPtr\fR) +.sp +int +\fBTcl_CreateThread\fR(\fIidPtr, threadProc, clientData, stackSize, flags\fR) +.SH ARGUMENTS +.AS Tcl_ThreadDataKey *keyPtr +.AP Tcl_Condition *condPtr in +A condition variable, which must be associated with a mutex lock. +.AP Tcl_Condition *mutexPtr in +A mutex lock. +.AP Tcl_Time *timePtr in +A time limit on the condition wait. NULL to wait forever. +Note that a polling value of 0 seconds doesn't make much sense. +.AP Tcl_ThreadDataKey *keyPtr in +This identifies a block of thread local storage. The key should be +static and process-wide, yet each thread will end up associating +a different block of storage with this key. +.AP int *size in +The size of the thread local storage block. This amount of data +is allocated and initialized to zero the first time each thread +calls \fBTcl_GetThreadData\fR. +.AP Tcl_ThreadId *idPtr out +The refered storage will contain the id of the newly created thread as +returned by the operating system. +.AP Tcl_ThreadId id in +Id of the thread waited upon. +.AP Tcl_ThreadCreateProc threadProc in +This procedure will act as the \fBmain()\fR of the newly created +thread. The specified \fIclientData\fR will be its sole argument. +.AP ClientData clientData in +Arbitrary information. Passed as sole argument to the \fIthreadProc\fR. +.AP int stackSize in +The size of the stack given to the new thread. +.AP int flags in +Bitmask containing flags allowing the caller to modify behaviour of +the new thread. +.AP int *result out +The refered storage is used to place the exit code of the thread +waited upon into it. +.BE +.SH INTRODUCTION +Beginning with the 8.1 release, the Tcl core is thread safe, which +allows you to incorporate Tcl into multithreaded applications without +customizing the Tcl core. To enable Tcl multithreading support, +you must include the \fB--enable-threads\fR option to \fBconfigure\fR +when you configure and compile your Tcl core. +.PP +An important contstraint of the Tcl threads implementation is that +\fIonly the thread that created a Tcl interpreter can use that +interpreter\fR. In other words, multiple threads can not access +the same Tcl interpreter. (However, as was the case in previous +releases, a single thread can safely create and use multiple +interpreters.) +.PP +.VS 8.3.1 +Tcl does provide \fBTcl_CreateThread\fR for creating threads. The +caller can determine the size of the stack given to the new thread and +modify the behaviour through the supplied \fIflags\fR. The value +\fBTCL_THREAD_STACK_DEFAULT\fR for the \fIstackSize\fR indicates that +the default size as specified by the operating system is to be used +for the new thread. As for the flags, currently are only the values +\fBTCL_THREAD_NOFLAGS\fR and \fBTCL_THREAD_JOINABLE\fR defined. The +first of them invokes the default behaviour with no +specialities. Using the second value marks the new thread as +\fIjoinable\fR. This means that another thread can wait for the such +marked thread to exit and join it. +.PP +Restrictions: On some unix systems the pthread-library does not +contain the functionality to specify the stacksize of a thread. The +specified value for the stacksize is ignored on these systems. Both +Windows and Macintosh currently do not support joinable threads. This +flag value is therefore ignored on these platforms. +.VE +.PP +Tcl does provide \fBTcl_ExitThread\fR and \fBTcl_FinalizeThread\fR +for terminating threads and invoking optional per-thread exit +handlers. See the \fBTcl_Exit\fR page for more information on these +procedures. +.PP +Tcl provides \fBTcl_ThreadQueueEvent\fR and \fBTcl_ThreadAlert\fR +for handling event queueing in multithreaded applications. See +the \fBNotifier\fR manual page for more information on these procedures. +.PP +In this release, the Tcl language itself provides no support for +creating multithreaded scripts (for example, scripts that could spawn +a Tcl interpreter in a separate thread). If you need to add this +feature at this time, see the \fItclThreadTest.c\fR +file in the Tcl source distribution for an experimental implementation +of a Tcl "Thread" package implementing thread creation and management +commands at the script level. + +.SH DESCRIPTION +A mutex is a lock that is used to serialize all threads through a piece +of code by calling \fBTcl_MutexLock\fR and \fBTcl_MutexUnlock\fR. +If one thread holds a mutex, any other thread calling \fBTcl_MutexLock\fR will +block until \fBTcl_MutexUnlock\fR is called. +.VS +A mutex can be destroyed after its use by calling \fBTcl_MutexFinalize\fR. +The result of locking a mutex twice from the same thread is undefined. +On some platforms it will result in a deadlock. +.VE +The \fBTcl_MutexLock\fR, \fBTcl_MutexUnlock\fR and \fBTcl_MutexFinalize\fR +procedures are defined as empty macros if not compiling with threads enabled. +.PP +A condition variable is used as a signaling mechanism: +a thread can lock a mutex and then wait on a condition variable +with \fBTcl_ConditionWait\fR. This atomically releases the mutex lock +and blocks the waiting thread until another thread calls +\fBTcl_ConditionNotify\fR. The caller of \fBTcl_ConditionNotify\fR should +have the associated mutex held by previously calling \fBTcl_MutexLock\fR, +but this is not enforced. Notifying the +condition variable unblocks all threads waiting on the condition variable, +but they do not proceed until the mutex is released with \fBTcl_MutexUnlock\fR. +The implementation of \fBTcl_ConditionWait\fR automatically locks +the mutex before returning. +.PP +The caller of \fBTcl_ConditionWait\fR should be prepared for spurious +notifications by calling \fBTcl_ConditionWait\fR within a while loop +that tests some invariant. +.PP +.VS +A condition variable can be destroyed after its use by calling +\fBTcl_ConditionFinalize\fR. +.PP +The \fBTcl_ConditionNotify\fR, \fBTcl_ConditionWait\fR and +\fBTcl_ConditionFinalize\fR procedures are defined as empty macros if +not compiling with threads enabled. +.VE +.PP +The \fBTcl_GetThreadData\fR call returns a pointer to a block of +thread-private data. Its argument is a key that is shared by all threads +and a size for the block of storage. The storage is automatically +allocated and initialized to all zeros the first time each thread asks for it. +The storage is automatically deallocated by \fBTcl_FinalizeThread\fR. +.SH INITIALIZATION +.PP +All of these synchronization objects are self initializing. +They are implemented as opaque pointers that should be NULL +upon first use. +The mutexes and condition variables are +.VS +either cleaned up by process exit handlers (if living that long) or +explicitly by calls to \fBTcl_MutexFinalize\fR or +\fBTcl_ConditionFinalize\fR. +.VE +Thread local storage is reclaimed during \fBTcl_FinalizeThread\fR. +.SH "CREATING THREADS" +The API to create threads is not finalized at this time. +There are private facilities to create threads that contain a new +Tcl interpreter, and to send scripts among threads. +Dive into tclThreadTest.c and tclThread.c for examples. +.SH "SEE ALSO" +Tcl_GetCurrentThread, Tcl_ThreadQueueEvent, Tcl_ThreadAlert, +Tcl_ExitThread, Tcl_FinalizeThread, +Tcl_CreateThreadExitHandler, Tcl_DeleteThreadExitHandler +.SH KEYWORDS +thread, mutex, condition variable, thread local storage diff --git a/mk4/modtcl/tcl8.3.4/doc/ToUpper.3 b/mk4/modtcl/tcl8.3.4/doc/ToUpper.3 new file mode 100644 index 0000000..808fc54 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/ToUpper.3 @@ -0,0 +1,90 @@ +'\" +'\" Copyright (c) 1997 by Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: ToUpper.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_UtfToUpper 3 "8.1" Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_UniCharToUpper, Tcl_UniCharToLower, Tcl_UniCharToTitle, Tcl_UtfToUpper, Tcl_UtfToLower, Tcl_UtfToTitle \- routines for manipulating the case of Unicode characters and UTF-8 strings. +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +Tcl_UniChar +\fBTcl_UniCharToUpper\fR(\fIch\fR) +.sp +Tcl_UniChar +\fBTcl_UniCharToLower\fR(\fIch\fR) +.sp +Tcl_UniChar +\fBTcl_UniCharToTitle\fR(\fIch\fR) +.sp +int +\fBTcl_UtfToUpper\fR(\fIstr\fR) +.sp +int +\fBTcl_UtfToLower\fR(\fIstr\fR) +.sp +int +\fBTcl_UtfToTitle\fR(\fIstr\fR) +.SH ARGUMENTS +.AS char *str in/out +.AP int ch in +The Tcl_UniChar to be converted. +.AP char *str in/out +Pointer to UTF-8 string to be converted in place. +.BE + +.SH DESCRIPTION +.PP +The first three routines convert the case of individual Unicode characters: +.PP +If \fIch\fR represents a lower-case character, +\fBTcl_UniCharToUpper\fR returns the corresponding upper-case +character. If no upper-case character is defined, it returns the +character unchanged. +.PP +If \fIch\fR represents an upper-case character, +\fBTcl_UniCharToLower\fR returns the corresponding lower-case +character. If no lower-case character is defined, it returns the +character unchanged. +.PP +If \fIch\fR represents a lower-case character, +\fBTcl_UniCharToTitle\fR returns the corresponding title-case +character. If no title-case character is defined, it returns the +corresponding upper-case character. If no upper-case character is +defined, it returns the character unchanged. Title-case is defined +for a small number of characters that have a different appearance when +they are at the beginning of a capitalized word. +.PP +The next three routines convert the case of UTF-8 strings in place in +memory: +.PP +\fBTcl_UtfToUpper\fR changes every UTF-8 character in \fIstr\fR to +upper-case. Because changing the case of a character may change its +size, the byte offset of each character in the resulting string may +differ from its original location. \fBTcl_UtfToUpper\fR writes a null +byte at the end of the converted string. \fBTcl_UtfToUpper\fR returns +the new length of the string in bytes. This new length is guaranteed +to be no longer than the original string length. +.PP +\fBTcl_UtfToLower\fR is the same as \fBTcl_UtfToUpper\fR except it +turns each character in the string into its lower-case equivalent. +.PP +\fBTcl_UtfToTitle\fR is the same as \fBTcl_UtfToUpper\fR except it +turns the first character in the string into its title-case equivalent +and all following characters into their lower-case equivalents. + +.SH BUGS +.PP +At this time, the case conversions are only defined for the ISO8859-1 +characters. Unicode characters above 0x00ff are not modified by these +routines. + +.SH KEYWORDS +utf, unicode, toupper, tolower, totitle, case diff --git a/mk4/modtcl/tcl8.3.4/doc/TraceVar.3 b/mk4/modtcl/tcl8.3.4/doc/TraceVar.3 new file mode 100644 index 0000000..5a832a0 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/TraceVar.3 @@ -0,0 +1,366 @@ +'\" +'\" Copyright (c) 1989-1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: TraceVar.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_TraceVar 3 7.4 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_TraceVar, Tcl_TraceVar2, Tcl_UntraceVar, Tcl_UntraceVar2, Tcl_VarTraceInfo, Tcl_VarTraceInfo2 \- monitor accesses to a variable +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +int +\fBTcl_TraceVar(\fIinterp, varName, flags, proc, clientData\fB)\fR +.sp +int +\fBTcl_TraceVar2(\fIinterp, name1, name2, flags, proc, clientData\fB)\fR +.sp +\fBTcl_UntraceVar(\fIinterp, varName, flags, proc, clientData\fB)\fR +.sp +\fBTcl_UntraceVar2(\fIinterp, name1, name2, flags, proc, clientData\fB)\fR +.sp +ClientData +\fBTcl_VarTraceInfo(\fIinterp, varName, flags, proc, prevClientData\fB)\fR +.sp +ClientData +\fBTcl_VarTraceInfo2(\fIinterp, name1, name2, flags, proc, prevClientData\fB)\fR +.SH ARGUMENTS +.AS Tcl_VarTraceProc prevClientData +.AP Tcl_Interp *interp in +Interpreter containing variable. +.AP char *varName in +Name of variable. May refer to a scalar variable, to +an array variable with no index, or to an array variable +with a parenthesized index. +If the name references an element of an array, then it +must be in writable memory: Tcl will make temporary modifications +to it while looking up the name. +.AP int flags in +OR-ed combination of the values TCL_TRACE_READS, TCL_TRACE_WRITES, and +TCL_TRACE_UNSETS, TCL_TRACE_ARRAY, and TCL_GLOBAL_ONLY. +Not all flags are used by all +procedures. See below for more information. +.AP Tcl_VarTraceProc *proc in +Procedure to invoke whenever one of the traced operations occurs. +.AP ClientData clientData in +Arbitrary one-word value to pass to \fIproc\fR. +.AP char *name1 in +Name of scalar or array variable (without array index). +.AP char *name2 in +For a trace on an element of an array, gives the index of the +element. For traces on scalar variables or on whole arrays, +is NULL. +.AP ClientData prevClientData in +If non-NULL, gives last value returned by \fBTcl_VarTraceInfo\fR or +\fBTcl_VarTraceInfo2\fR, so this call will return information about +next trace. If NULL, this call will return information about first +trace. +.BE + +.SH DESCRIPTION +.PP +\fBTcl_TraceVar\fR allows a C procedure to monitor and control +access to a Tcl variable, so that the C procedure is invoked +whenever the variable is read or written or unset. +If the trace is created successfully then \fBTcl_TraceVar\fR returns +TCL_OK. If an error occurred (e.g. \fIvarName\fR specifies an element +of an array, but the actual variable isn't an array) then TCL_ERROR +is returned and an error message is left in the interpreter's result. +.PP +The \fIflags\fR argument to \fBTcl_TraceVar\fR indicates when the +trace procedure is to be invoked and provides information +for setting up the trace. It consists of an OR-ed combination +of any of the following values: +.TP +\fBTCL_GLOBAL_ONLY\fR +Normally, the variable will be looked up at the current level of +procedure call; if this bit is set then the variable will be looked +up at global level, ignoring any active procedures. +.TP +\fBTCL_TRACE_READS\fR +Invoke \fIproc\fR whenever an attempt is made to read the variable. +.TP +\fBTCL_TRACE_WRITES\fR +Invoke \fIproc\fR whenever an attempt is made to modify the variable. +.TP +\fBTCL_TRACE_UNSETS\fR +Invoke \fIproc\fR whenever the variable is unset. +A variable may be unset either explicitly by an \fBunset\fR command, +or implicitly when a procedure returns (its local variables are +automatically unset) or when the interpreter is deleted (all +variables are automatically unset). +.TP +\fBTCL_TRACE_ARRAY\fR +Invoke \fIproc\fR whenever the array command is invoked. +This gives the trace procedure a chance to update the array before +array names or array get is called. Note that this is called +before an array set, but that will trigger write traces. +.PP +Whenever one of the specified operations occurs on the variable, +\fIproc\fR will be invoked. +It should have arguments and result that match the type +\fBTcl_VarTraceProc\fR: +.CS +typedef char *Tcl_VarTraceProc( + ClientData \fIclientData\fR, + Tcl_Interp *\fIinterp\fR, + char *\fIname1\fR, + char *\fIname2\fR, + int \fIflags\fR); +.CE +The \fIclientData\fR and \fIinterp\fR parameters will +have the same values as those passed to \fBTcl_TraceVar\fR when the +trace was created. +\fIClientData\fR typically points to an application-specific +data structure that describes what to do when \fIproc\fR +is invoked. +\fIName1\fR and \fIname2\fR give the name of the traced variable +in the normal two-part form (see the description of \fBTcl_TraceVar2\fR +below for details). +\fIFlags\fR is an OR-ed combination of bits providing several +pieces of information. +One of the bits TCL_TRACE_READS, TCL_TRACE_WRITES, TCL_TRACE_ARRAY, +or TCL_TRACE_UNSETS +will be set in \fIflags\fR to indicate which operation is being performed +on the variable. +The bit TCL_GLOBAL_ONLY will be set whenever the variable being +accessed is a global one not accessible from the current level of +procedure call: the trace procedure will need to pass this flag +back to variable-related procedures like \fBTcl_GetVar\fR if it +attempts to access the variable. +The bit TCL_TRACE_DESTROYED will be set in \fIflags\fR if the trace is +about to be destroyed; this information may be useful to \fIproc\fR +so that it can clean up its own internal data structures (see +the section TCL_TRACE_DESTROYED below for more details). +Lastly, the bit TCL_INTERP_DESTROYED will be set if the entire +interpreter is being destroyed. +When this bit is set, \fIproc\fR must be especially careful in +the things it does (see the section TCL_INTERP_DESTROYED below). +The trace procedure's return value should normally be NULL; see +ERROR RETURNS below for information on other possibilities. +.PP +\fBTcl_UntraceVar\fR may be used to remove a trace. +If the variable specified by \fIinterp\fR, \fIvarName\fR, and \fIflags\fR +has a trace set with \fIflags\fR, \fIproc\fR, and +\fIclientData\fR, then the corresponding trace is removed. +If no such trace exists, then the call to \fBTcl_UntraceVar\fR +has no effect. +The same bits are valid for \fIflags\fR as for calls to \fBTcl_TraceVar\fR. +.PP +\fBTcl_VarTraceInfo\fR may be used to retrieve information about +traces set on a given variable. +The return value from \fBTcl_VarTraceInfo\fR is the \fIclientData\fR +associated with a particular trace. +The trace must be on the variable specified by the \fIinterp\fR, +\fIvarName\fR, and \fIflags\fR arguments (only the TCL_GLOBAL_ONLY +bit from \fIflags\fR is used; other bits are ignored) and its trace procedure +must the same as the \fIproc\fR argument. +If the \fIprevClientData\fR argument is NULL then the return +value corresponds to the first (most recently created) matching +trace, or NULL if there are no matching traces. +If the \fIprevClientData\fR argument isn't NULL, then it should +be the return value from a previous call to \fBTcl_VarTraceInfo\fR. +In this case, the new return value will correspond to the next +matching trace after the one whose \fIclientData\fR matches +\fIprevClientData\fR, or NULL if no trace matches \fIprevClientData\fR +or if there are no more matching traces after it. +This mechanism makes it possible to step through all of the +traces for a given variable that have the same \fIproc\fR. + +.SH "TWO-PART NAMES" +.PP +The procedures \fBTcl_TraceVar2\fR, \fBTcl_UntraceVar2\fR, and +\fBTcl_VarTraceInfo2\fR are identical to \fBTcl_TraceVar\fR, +\fBTcl_UntraceVar\fR, and \fBTcl_VarTraceInfo\fR, respectively, +except that the name of the variable consists of two parts. +\fIName1\fR gives the name of a scalar variable or array, +and \fIname2\fR gives the name of an element within an array. +.VS 8.1 +When \fIname2\fR is NULL, +\fIname1\fR may contain both an array and an element name: +if the name contains an open parenthesis and ends with a +close parenthesis, then the value between the parentheses is +treated as an element name (which can have any string value) and +the characters before the first open +parenthesis are treated as the name of an array variable. +If \fIname2\fR is NULL and \fIname1\fR does not refer +to an array element +.VE +it means that either the variable is +a scalar or the trace is to be set on the entire array rather +than an individual element (see WHOLE-ARRAY TRACES below for +more information). + + +.SH "ACCESSING VARIABLES DURING TRACES" +.PP +During read, write, and array traces, the +trace procedure can read, write, or unset the traced +variable using \fBTcl_GetVar2\fR, \fBTcl_SetVar2\fR, and +other procedures. +While \fIproc\fR is executing, traces are temporarily disabled +for the variable, so that calls to \fBTcl_GetVar2\fR and +\fBTcl_SetVar2\fR will not cause \fIproc\fR or other trace procedures +to be invoked again. +Disabling only occurs for the variable whose trace procedure +is active; accesses to other variables will still be traced. +However, if a variable is unset during a read or write trace then unset +traces will be invoked. +.PP +During unset traces the variable has already been completely +expunged. +It is possible for the trace procedure to read or write the +variable, but this will be a new version of the variable. +Traces are not disabled during unset traces as they are for +read and write traces, but existing traces have been removed +from the variable before any trace procedures are invoked. +If new traces are set by unset trace procedures, these traces +will be invoked on accesses to the variable by the trace +procedures. + +.SH "CALLBACK TIMING" +.PP +When read tracing has been specified for a variable, the trace +procedure will be invoked whenever the variable's value is +read. This includes \fBset\fR Tcl commands, \fB$\fR-notation +in Tcl commands, and invocations of the \fBTcl_GetVar\fR +and \fBTcl_GetVar2\fR procedures. +\fIProc\fR is invoked just before the variable's value is +returned. +It may modify the value of the variable to affect what +is returned by the traced access. +If it unsets the variable then the access will return an error +just as if the variable never existed. +.PP +When write tracing has been specified for a variable, the +trace procedure will be invoked whenever the variable's value +is modified. This includes \fBset\fR commands, +commands that modify variables as side effects (such as +\fBcatch\fR and \fBscan\fR), and calls to the \fBTcl_SetVar\fR +and \fBTcl_SetVar2\fR procedures). +\fIProc\fR will be invoked after the variable's value has been +modified, but before the new value of the variable has been +returned. +It may modify the value of the variable to override the change +and to determine the value actually returned by the traced +access. +If it deletes the variable then the traced access will return +an empty string. +.PP +When array tracing has been specified, the trace procedure +will be invoked at the beginning of the array command implementation, +before any of the operations like get, set, or names have been invoked. +The trace procedure can modify the array elements with \fBTcl_SetVar\fR +and \fBTcl_SetVar2\fR. +.PP +When unset tracing has been specified, the trace procedure +will be invoked whenever the variable is destroyed. +The traces will be called after the variable has been +completely unset. + +.SH "WHOLE-ARRAY TRACES" +.PP +If a call to \fBTcl_TraceVar\fR or \fBTcl_TraceVar2\fR specifies +the name of an array variable without an index into the array, +then the trace will be set on the array as a whole. +This means that \fIproc\fR will be invoked whenever any +element of the array is accessed in the ways specified by +\fIflags\fR. +When an array is unset, a whole-array trace will be invoked +just once, with \fIname1\fR equal to the name of the array +and \fIname2\fR NULL; it will not be invoked once for each +element. + +.SH "MULTIPLE TRACES" +.PP +It is possible for multiple traces to exist on the same variable. +When this happens, all of the trace procedures will be invoked on each +access, in order from most-recently-created to least-recently-created. +When there exist whole-array traces for an array as well as +traces on individual elements, the whole-array traces are invoked +before the individual-element traces. +If a read or write trace unsets the variable then all of the unset +traces will be invoked but the remainder of the read and write traces +will be skipped. + +.SH "ERROR RETURNS" +.PP +Under normal conditions trace procedures should return NULL, indicating +successful completion. +If \fIproc\fR returns a non-NULL value it signifies that an +error occurred. +The return value must be a pointer to a static character string +containing an error message. +If a trace procedure returns an error, no further traces are +invoked for the access and the traced access aborts with the +given message. +Trace procedures can use this facility to make variables +read-only, for example (but note that the value of the variable +will already have been modified before the trace procedure is +called, so the trace procedure will have to restore the correct +value). +.PP +The return value from \fIproc\fR is only used during read and +write tracing. +During unset traces, the return value is ignored and all relevant +trace procedures will always be invoked. + +.SH "RESTRICTIONS" +.PP +A trace procedure can be called at any time, even when there +is a partially-formed result in the interpreter's result area. If +the trace procedure does anything that could damage this result (such +as calling \fBTcl_Eval\fR) then it must save the original values of +the interpreter's \fBresult\fR and \fBfreeProc\fR fields and restore +them before it returns. + +.SH "UNDEFINED VARIABLES" +.PP +It is legal to set a trace on an undefined variable. +The variable will still appear to be undefined until the +first time its value is set. +If an undefined variable is traced and then unset, the unset will fail +with an error (``no such variable''), but the trace +procedure will still be invoked. + +.SH "TCL_TRACE_DESTROYED FLAG" +.PP +In an unset callback to \fIproc\fR, the TCL_TRACE_DESTROYED bit +is set in \fIflags\fR if the trace is being removed as part +of the deletion. +Traces on a variable are always removed whenever the variable +is deleted; the only time TCL_TRACE_DESTROYED isn't set is for +a whole-array trace invoked when only a single element of an +array is unset. + +.SH "TCL_INTERP_DESTROYED" +.PP +When an interpreter is destroyed, unset traces are called for +all of its variables. +The TCL_INTERP_DESTROYED bit will be set in the \fIflags\fR +argument passed to the trace procedures. +Trace procedures must be extremely careful in what they do if +the TCL_INTERP_DESTROYED bit is set. +It is not safe for the procedures to invoke any Tcl procedures +on the interpreter, since its state is partially deleted. +All that trace procedures should do under these circumstances is +to clean up and free their own internal data structures. + +.SH BUGS +.PP +Tcl doesn't do any error checking to prevent trace procedures +from misusing the interpreter during traces with TCL_INTERP_DESTROYED +set. +.PP +Array traces are not yet integrated with the Tcl "info exists" command, +nor is there Tcl-level access to array traces. + +.SH KEYWORDS +clientData, trace, variable diff --git a/mk4/modtcl/tcl8.3.4/doc/Translate.3 b/mk4/modtcl/tcl8.3.4/doc/Translate.3 new file mode 100644 index 0000000..712c697 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/Translate.3 @@ -0,0 +1,66 @@ +'\" +'\" Copyright (c) 1989-1993 The Regents of the University of California. +'\" Copyright (c) 1994-1998 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: Translate.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_TranslateFileName 3 8.1 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_TranslateFileName \- convert file name to native form and replace tilde with home directory +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +char * +\fBTcl_TranslateFileName\fR(\fIinterp\fR, \fIname\fR, \fIbufferPtr\fR) +.SH ARGUMENTS +.AS Tcl_DString *bufferPtr +.AP Tcl_Interp *interp in +Interpreter in which to report an error, if any. +.AP char *name in +File name, which may start with a ``~''. +.AP Tcl_DString *bufferPtr in/out +If needed, this dynamic string is used to store the new file name. +At the time of the call it should be uninitialized or free. The +caller must eventually call \fBTcl_DStringFree\fR to free up +anything stored here. +.BE + +.SH DESCRIPTION +.PP +This utility procedure translates a file name to a form suitable for +passing to the local operating system. It converts network names into +native form and does tilde substitution. +.PP +If +\fBTcl_TranslateFileName\fR has to do tilde substitution or translate +the name then it uses +the dynamic string at \fI*bufferPtr\fR to hold the new string it +generates. +After \fBTcl_TranslateFileName\fR returns a non-NULL result, the caller must +eventually invoke \fBTcl_DStringFree\fR to free any information +placed in \fI*bufferPtr\fR. The caller need not know whether or +not \fBTcl_TranslateFileName\fR actually used the string; \fBTcl_TranslateFileName\fR +initializes \fI*bufferPtr\fR even if it doesn't use it, so the call to +\fBTcl_DStringFree\fR will be safe in either case. +.PP +If an error occurs (e.g. because there was no user by the given +name) then NULL is returned and an error message will be left +in the interpreter's result. +When an error occurs, \fBTcl_TranslateFileName\fR +frees the dynamic string itself so that the caller need not call +\fBTcl_DStringFree\fR. +.PP +The caller is responsible for making sure that the interpreter's result +has its default empty value when \fBTcl_TranslateFileName\fR is invoked. + +.SH "SEE ALSO" +filename + +.SH KEYWORDS +file name, home directory, tilde, translate, user diff --git a/mk4/modtcl/tcl8.3.4/doc/UpVar.3 b/mk4/modtcl/tcl8.3.4/doc/UpVar.3 new file mode 100644 index 0000000..5b827a6 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/UpVar.3 @@ -0,0 +1,75 @@ +'\" +'\" Copyright (c) 1994 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: UpVar.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_UpVar 3 7.4 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_UpVar, Tcl_UpVar2 \- link one variable to another +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +int +\fBTcl_UpVar(\fIinterp, frameName, sourceName, destName, flags\fB)\fR +.sp +int +\fBTcl_UpVar2(\fIinterp, frameName, name1, name2, destName, flags\fB)\fR +.SH ARGUMENTS +.AS Tcl_VarTraceProc prevClientData +.AP Tcl_Interp *interp in +Interpreter containing variables; also used for error reporting. +.AP char *frameName in +Identifies the stack frame containing source variable. +May have any of the forms accepted by +the \fBupvar\fR command, such as \fB#0\fR or \fB1\fR. +.AP char *sourceName in +Name of source variable, in the frame given by \fIframeName\fR. +May refer to a scalar variable or to an array variable with a +parenthesized index. +.AP char *destName in +Name of destination variable, which is to be linked to source +variable so that references to \fIdestName\fR +refer to the other variable. Must not currently exist except as +an upvar-ed variable. +.AP int flags in +Either TCL_GLOBAL_ONLY or 0; if non-zero, then \fIdestName\fR is +a global variable; otherwise it is a local to the current procedure +(or global if no procedure is active). +.AP char *name1 in +First part of source variable's name (scalar name, or name of array +without array index). +.AP char *name2 in +If source variable is an element of an array, gives the index of the element. +For scalar source variables, is NULL. +.BE + +.SH DESCRIPTION +.PP +\fBTcl_UpVar\fR and \fBTcl_UpVar2\fR provide the same functionality +as the \fBupvar\fR command: they make a link from a source variable +to a destination variable, so that references to the destination are +passed transparently through to the source. +The name of the source variable may be specified either as a single +string such as \fBxyx\fR or \fBa(24)\fR (by calling \fBTcl_UpVar\fR) +or in two parts where the array name has been separated from the +element name (by calling \fBTcl_UpVar2\fR). +The destination variable name is specified in a single string; it +may not be an array element. +.PP +Both procedures return either TCL_OK or TCL_ERROR, and they +leave an error message in the interpreter's result if an error occurs. +.PP +As with the \fBupvar\fR command, the source variable need not exist; +if it does exist, unsetting it later does not destroy the link. The +destination variable may exist at the time of the call, but if so +it must exist as a linked variable. + +.SH KEYWORDS +linked variable, upvar, variable diff --git a/mk4/modtcl/tcl8.3.4/doc/Utf.3 b/mk4/modtcl/tcl8.3.4/doc/Utf.3 new file mode 100644 index 0000000..13a6b9e --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/Utf.3 @@ -0,0 +1,232 @@ +'\" +'\" Copyright (c) 1997 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: Utf.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Utf 3 "8.1" Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_UniChar, Tcl_UniCharToUtf, Tcl_UtfToUniChar, Tcl_UniCharToUtfDString, Tcl_UtfToUniCharDString, Tcl_UniCharLen, Tcl_UniCharNcmp, Tcl_UtfCharComplete, Tcl_NumUtfChars, Tcl_UtfFindFirst, Tcl_UtfFindLast, Tcl_UtfNext, Tcl_UtfPrev, Tcl_UniCharAtIndex, Tcl_UtfAtIndex, Tcl_UtfBackslash \- routines for manipulating UTF-8 strings. +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +typedef ... Tcl_UniChar; +.sp +int +\fBTcl_UniCharToUtf\fR(\fIch, buf\fR) +.sp +int +\fBTcl_UtfToUniChar\fR(\fIsrc, chPtr\fR) +.sp +char * +\fBTcl_UniCharToUtfDString\fR(\fIuniStr, numChars, dstPtr\fR) +.sp +Tcl_UniChar * +\fBTcl_UtfToUniCharDString\fR(\fIsrc, len, dstPtr\fR) +.sp +int +\fBTcl_UniCharLen\fR(\fIuniStr\fR) +.sp +int +\fBTcl_UniCharNcmp\fR(\fIuniStr, uniStr, num\fR) +.sp +int +\fBTcl_UtfNcmp\fR(\fIsrc, src, num\fR) +.sp +int +\fBTcl_UtfNcasecmp\fR(\fIsrc, src, num\fR) +.sp +int +\fBTcl_UtfCharComplete\fR(\fIsrc, len\fR) +.sp +int +\fBTcl_NumUtfChars\fR(\fIsrc, len\fR) +.sp +char * +\fBTcl_UtfFindFirst\fR(\fIsrc, ch\fR) +.sp +char * +\fBTcl_UtfFindLast\fR(\fIsrc, ch\fR) +.sp +char * +\fBTcl_UtfNext\fR(\fIsrc\fR) +.sp +char * +\fBTcl_UtfPrev\fR(\fIsrc, start\fR) +.sp +Tcl_UniChar +\fBTcl_UniCharAtIndex\fR(\fIsrc, index\fR) +.sp +char * +\fBTcl_UtfAtIndex\fR(\fIsrc, index\fR) +.sp +int +\fBTcl_UtfBackslash\fR(\fIsrc, readPtr, dst\fR) +.SH ARGUMENTS +.AS "CONST Tcl_UniChar" numChars in/out +.AP char *buf out +Buffer in which the UTF-8 representation of the Tcl_UniChar is stored. At most +TCL_UTF_MAX bytes are stored in the buffer. +.AP int ch in +The Tcl_UniChar to be converted or examined. +.AP Tcl_UniChar *chPtr out +Filled with the Tcl_UniChar represented by the head of the UTF-8 string. +.AP "CONST char" *src in +Pointer to a UTF-8 string. +.AP "CONST Tcl_UniChar" *uniStr in +A NULL-terminated Unicode string. +.AP int len in +The length of the UTF-8 string in bytes (not UTF-8 characters). If +negative, all bytes up to the first null byte are used. +.AP int numChars in +The length of the Unicode string in characters. Must be greater than or +equal to 0. +.AP "Tcl_DString" *dstPtr in/out +A pointer to a previously-initialized \fBTcl_DString\fR. +.AP "unsigned long" num in +The number of characters to compare. +.AP "CONST char" *start in +Pointer to the beginning of a UTF-8 string. +.AP int index in +The index of a character (not byte) in the UTF-8 string. +.AP int *readPtr out +If non-NULL, filled with the number of bytes in the backslash sequence, +including the backslash character. +.AP char *dst out +Buffer in which the bytes represented by the backslash sequence are stored. +At most TCL_UTF_MAX bytes are stored in the buffer. +.BE + +.SH DESCRIPTION +.PP +These routines convert between UTF-8 strings and Tcl_UniChars. A +Tcl_UniChar is a Unicode character represented as an unsigned, fixed-size +quantity. A UTF-8 character is a Unicode character represented as +a varying-length sequence of up to TCL_UTF_MAX bytes. A multibyte UTF-8 +sequence consists of a lead byte followed by some number of trail bytes. +.PP +\fBTCL_UTF_MAX\fR is the maximum number of bytes that it takes to +represent one Unicode character in the UTF-8 representation. +.PP +\fBTcl_UniCharToUtf\fR stores the Tcl_UniChar \fIch\fR as a UTF-8 string +in starting at \fIbuf\fR. The return value is the number of bytes stored +in \fIbuf\fR. +.PP +\fBTcl_UtfToUniChar\fR reads one UTF-8 character starting at \fIsrc\fR +and stores it as a Tcl_UniChar in \fI*chPtr\fR. The return value is the +number of bytes read from \fIsrc\fR.. The caller must ensure that the +source buffer is long enough such that this routine does not run off the +end and dereference non-existent or random memory; if the source buffer +is known to be null terminated, this will not happen. If the input is +not in proper UTF-8 format, \fBTcl_UtfToUniChar\fR will store the first +byte of \fIsrc\fR in \fI*chPtr\fR as a Tcl_UniChar between 0x0000 and +0x00ff and return 1. +.PP +\fBTcl_UniCharToUtfDString\fR converts the given Unicode string +to UTF-8, storing the result in a previously-initialized \fBTcl_DString\fR. +You must specify the length of the given Unicode string. +The return value is a pointer to the UTF-8 representation of the +Unicode string. Storage for the return value is appended to the +end of the \fBTcl_DString\fR. +.PP +\fBTcl_UtfToUniCharDString\fR coverts the given UTF-8 string to Unicode, +storing the result in the previously-initialized \fBTcl_Dstring\fR. +you may either specify the length of the given UTF-8 string or "-1", +in which case \fBTcl_UtfToUniCharDString\fR uses \fBstrlen\fR to +calculate the length. The return value is a pointer to the Unicode +representation of the UTF-8 string. Storage for the return value +is appended to the end of the \fBTcl_DString\fR. The Unicode string +is terminated with a Unicode NULL character. +.PP +\fBTcl_UniCharLen\fR corresponds to \fBstrlen\fR for Unicode +characters. It accepts a NULL-terminated Unicode string and returns +the number of Unicode characters (not bytes) in that string. +.PP +\fBTcl_UniCharNcmp\fR corresponds to \fBstrncmp\fR for Unicode +characters. It accepts two NULL-terminated Unicode strings +and the number of characters to compare. (Both strings are +assumed to be at least \fIlen\fR characters long.) +\fBTcl_UniCharNcmp\fR compares the two strings character-by-character +according to the Unicode character ordering. It returns an integer +greater than, equal to, +or less than 0 if the first string is greater than, equal to, or +less than the second string respectively. +.PP +\fBTcl_UtfNcmp\fR corresponds to \fBstrncmp\fR for UTF-8 strings. It +accepts two NULL-terminated UTF-8 strings and the number of characters +to compare. (Both strings are assumed to be at least \fIlen\fR +characters long.) \fBTcl_UtfNcmp\fR compares the two strings +character-by-character according to the Unicode character ordering. +It returns an integer greater than, equal to, or less than 0 if the +first string is greater than, equal to, or less than the second string +respectively. +.PP +\fBTcl_UtfNcasecmp\fR corresponds to \fBstrncasecmp\fR for UTF-8 +strings. It is similar to \fBTcl_UtfNcmp\fR except comparisons ignore +differences in case when comparing upper, lower or title case +characters. +.PP +\fBTcl_UtfCharComplete\fR returns 1 if the source UTF-8 string \fIsrc\fR +of length \fIlen\fR bytes is long enough to be decoded by +\fBTcl_UtfToUniChar\fR, or 0 otherwise. This function does not guarantee +that the UTF-8 string is properly formed. This routine is used by +procedures that are operating on a byte at a time and need to know if a +full Tcl_UniChar has been seen. +.PP +\fBTcl_NumUtfChars\fR corresponds to \fBstrlen\fR for UTF-8 strings. It +returns the number of Tcl_UniChars that are represented by the UTF-8 string +\fIsrc\fR. The length of the source string is \fIlen\fR bytes. If the +length is negative, all bytes up to the first NULL byte are used. +.PP +\fBTcl_UtfFindFirst\fR corresponds to \fBstrchr\fR for UTF-8 strings. It +returns a pointer to the first occurance of the Tcl_UniChar \fIch\fR +in the NULL-terminated UTF-8 string \fIsrc\fR. The NULL terminator is +considered part of the UTF-8 string. +.PP +\fBTcl_UtfFindLast\fR corresponds to \fBstrrchr\fR for UTF-8 strings. It +returns a pointer to the last occurance of the Tcl_UniChar \fIch\fR +in the NULL terminated UTF-8 string \fIsrc\fR. The NULL terminator is +considered part of the UTF-8 string. +.PP +Given \fIsrc\fR, a pointer to some location in a UTF-8 string, +\fBTcl_UtfNext\fR returns a pointer to the next UTF-8 character in the +string. The caller must not ask for the next character after the last +character in the string. +.PP +Given \fIsrc\fR, a pointer to some location in a UTF-8 string, +\fBTcl_UtfPrev\fR returns a pointer to the previous UTF-8 character in the +string. This function will not back up to a position before \fIstart\fR, +the start of the UTF-8 string. If \fIsrc\fR was already at \fIstart\fR, the +return value will be \fIstart\fR. +.PP +\fBTcl_UniCharAtIndex\fR corresponds to a C string array dereference or the +Pascal Ord() function. It returns the Tcl_UniChar represented at the +specified character (not byte) \fIindex\fR in the UTF-8 string +\fIsrc\fR. The source string must contain at least \fIindex\fR +characters. Behavior is undefined if a negative \fIindex\fR is given. +.PP +\fBTcl_UtfAtIndex\fR returns a pointer to the specified character (not +byte) \fIindex\fR in the UTF-8 string \fIsrc\fR. The source string must +contain at least \fIindex\fR characters. This is equivalent to calling +\fBTcl_UtfNext\fR \fIindex\fR times. If a negative \fIindex\fR is given, +the return pointer points to the first character in the source string. +.PP +\fBTcl_UtfBackslash\fR is a utility procedure used by several of the Tcl +commands. It parses a backslash sequence and stores the properly formed +UTF-8 character represented by the backslash sequence in the output +buffer \fIdst\fR. At most TCL_UTF_MAX bytes are stored in the buffer. +\fBTcl_UtfBackslash\fR modifies \fI*readPtr\fR to contain the number +of bytes in the backslash sequence, including the backslash character. +The return value is the number of bytes stored in the output buffer. +.PP +See the \fBTcl\fR manual entry for information on the valid backslash +sequences. All of the sequences described in the Tcl manual entry are +supported by \fBTcl_UtfBackslash\fR. + +.SH KEYWORDS +utf, unicode, backslash diff --git a/mk4/modtcl/tcl8.3.4/doc/WrongNumArgs.3 b/mk4/modtcl/tcl8.3.4/doc/WrongNumArgs.3 new file mode 100644 index 0000000..ff975d3 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/WrongNumArgs.3 @@ -0,0 +1,78 @@ +'\" +'\" Copyright (c) 1994-1997 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: WrongNumArgs.3,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH Tcl_WrongNumArgs 3 8.0 Tcl "Tcl Library Procedures" +.BS +.SH NAME +Tcl_WrongNumArgs \- generate standard error message for wrong number of arguments +.SH SYNOPSIS +.nf +\fB#include \fR +.sp +\fBTcl_WrongNumArgs\fR(\fIinterp, objc, objv, message\fR) +.SH ARGUMENTS +.AS Tcl_Interp "*CONST objv[]" +.AP Tcl_Interp interp in +Interpreter in which error will be reported: error message gets stored +in its result object. +.AP int objc in +Number of leading arguments from \fIobjv\fR to include in error +message. +.AP Tcl_Obj "*CONST\ objv[]" in +Arguments to command that had the wrong number of arguments. +.AP char *message in +Additional error information to print after leading arguments +from \fIobjv\fR. This typically gives the acceptable syntax +of the command. This argument may be NULL. +.BE + +.SH DESCRIPTION +.PP +\fBTcl_WrongNumArgs\fR is a utility procedure that is invoked by +command procedures when they discover that they have received the +wrong number of arguments. \fBTcl_WrongNumArgs\fR generates a +standard error message and stores it in the result object of +\fIinterp\fR. The message includes the \fIobjc\fR initial +elements of \fIobjv\fR plus \fImessage\fR. For example, if +\fIobjv\fR consists of the values \fBfoo\fR and \fBbar\fR, +\fIobjc\fR is 1, and \fImessage\fR is ``\fBfileName count\fR'' +then \fIinterp\fR's result object will be set to the following +string: +.CS +wrong # args: should be "foo fileName count" +.CE +If \fIobjc\fR is 2, the result will be set to the following string: +.CS +wrong # args: should be "foo bar fileName count" +.CE +\fIObjc\fR is usually 1, but may be 2 or more for commands like +\fBstring\fR and the Tk widget commands, which use the first argument +as a subcommand. +.PP +Some of the objects in the \fIobjv\fR array may be abbreviations for +a subcommand. The command +\fBTcl_GetIndexFromObj\fR will convert the abbreviated string object +into an \fIindexObject\fR. If an error occurs in the parsing of the +subcommand we would like to use the full subcommand name rather than +the abbreviation. If the \fBTcl_WrongNumArgs\fR command finds any +\fIindexObjects\fR in the \fIobjv\fR array it will use the full subcommand +name in the error message instead of the abbreviated name that was +origionally passed in. Using the above example, lets assume that +\fIbar\fR is actually an abbreviation for \fIbarfly\fR and the object +is now an indexObject becasue it was passed to +\fBTcl_GetIndexFromObj\fR. In this case the error message would be: +.CS +wrong # args: should be "foo barfly fileName count" +.CE + +.SH "SEE ALSO" +Tcl_GetIndexFromObj + +.SH KEYWORDS +command, error message, wrong number of arguments diff --git a/mk4/modtcl/tcl8.3.4/doc/after.n b/mk4/modtcl/tcl8.3.4/doc/after.n new file mode 100644 index 0000000..eb82b0b --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/after.n @@ -0,0 +1,109 @@ +'\" +'\" Copyright (c) 1990-1994 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: after.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH after n 7.5 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +after \- Execute a command after a time delay +.SH SYNOPSIS +\fBafter \fIms\fR +.sp +\fBafter \fIms \fR?\fIscript script script ...\fR? +.sp +\fBafter cancel \fIid\fR +.sp +\fBafter cancel \fIscript script script ...\fR +.sp +\fBafter idle \fR?\fIscript script script ...\fR? +.sp +\fBafter info \fR?\fIid\fR? +.BE + +.SH DESCRIPTION +.PP +This command is used to delay execution of the program or to execute +a command in background sometime in the future. It has several forms, +depending on the first argument to the command: +.TP +\fBafter \fIms\fR +\fIMs\fR must be an integer giving a time in milliseconds. +The command sleeps for \fIms\fR milliseconds and then returns. +While the command is sleeping the application does not respond to +events. +.TP +\fBafter \fIms \fR?\fIscript script script ...\fR? +In this form the command returns immediately, but it arranges +for a Tcl command to be executed \fIms\fR milliseconds later as an +event handler. +The command will be executed exactly once, at the given time. +The delayed command is formed by concatenating all the \fIscript\fR +arguments in the same fashion as the \fBconcat\fR command. +The command will be executed at global level (outside the context +of any Tcl procedure). +If an error occurs while executing the delayed command then the +\fBbgerror\fR mechanism is used to report the error. +The \fBafter\fR command returns an identifier that can be used +to cancel the delayed command using \fBafter cancel\fR. +.TP +\fBafter cancel \fIid\fR +Cancels the execution of a delayed command that +was previously scheduled. +\fIId\fR indicates which command should be canceled; it must have +been the return value from a previous \fBafter\fR command. +If the command given by \fIid\fR has already been executed then +the \fBafter cancel\fR command has no effect. +.TP +\fBafter cancel \fIscript script ...\fR +This command also cancels the execution of a delayed command. +The \fIscript\fR arguments are concatenated together with space +separators (just as in the \fBconcat\fR command). +If there is a pending command that matches the string, it is +cancelled and will never be executed; if no such command is +currently pending then the \fBafter cancel\fR command has no effect. +.TP +\fBafter idle \fIscript \fR?\fIscript script ...\fR? +Concatenates the \fIscript\fR arguments together with space +separators (just as in the \fBconcat\fR command), and arranges +for the resulting script to be evaluated later as an idle callback. +The script will be run exactly once, the next time the event +loop is entered and there are no events to process. +The command returns an identifier that can be used +to cancel the delayed command using \fBafter cancel\fR. +If an error occurs while executing the script then the +\fBbgerror\fR mechanism is used to report the error. +.TP +\fBafter info \fR?\fIid\fR? +This command returns information about existing event handlers. +If no \fIid\fR argument is supplied, the command returns +a list of the identifiers for all existing +event handlers created by the \fBafter\fR command for this +interpreter. +If \fIid\fR is supplied, it specifies an existing handler; +\fIid\fR must have been the return value from some previous call +to \fBafter\fR and it must not have triggered yet or been cancelled. +In this case the command returns a list with two elements. +The first element of the list is the script associated +with \fIid\fR, and the second element is either +\fBidle\fR or \fBtimer\fR to indicate what kind of event +handler it is. +.LP +The \fBafter \fIms\fR and \fBafter idle\fR forms of the command +assume that the application is event driven: the delayed commands +will not be executed unless the application enters the event loop. +In applications that are not normally event-driven, such as +\fBtclsh\fR, the event loop can be entered with the \fBvwait\fR +and \fBupdate\fR commands. + +.SH "SEE ALSO" +bgerror(n), concat(n), update(n), vwait(n) + +.SH KEYWORDS +cancel, delay, idle callback, sleep, time diff --git a/mk4/modtcl/tcl8.3.4/doc/append.n b/mk4/modtcl/tcl8.3.4/doc/append.n new file mode 100644 index 0000000..2947c00 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/append.n @@ -0,0 +1,35 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: append.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH append n "" Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +append \- Append to variable +.SH SYNOPSIS +\fBappend \fIvarName \fR?\fIvalue value value ...\fR? +.BE + +.SH DESCRIPTION +.PP +Append all of the \fIvalue\fR arguments to the current value +of variable \fIvarName\fR. If \fIvarName\fR doesn't exist, +it is given a value equal to the concatenation of all the +\fIvalue\fR arguments. +This command provides an efficient way to build up long +variables incrementally. +For example, ``\fBappend a $b\fR'' is much more efficient than +``\fBset a $a$b\fR'' if \fB$a\fR is long. + +.SH "SEE ALSO" +concat(n), lappend(n) + +.SH KEYWORDS +append, variable diff --git a/mk4/modtcl/tcl8.3.4/doc/array.n b/mk4/modtcl/tcl8.3.4/doc/array.n new file mode 100644 index 0000000..ac736e4 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/array.n @@ -0,0 +1,125 @@ +'\" +'\" Copyright (c) 1993-1994 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: array.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH array n 8.3 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +array \- Manipulate array variables +.SH SYNOPSIS +\fBarray \fIoption arrayName\fR ?\fIarg arg ...\fR? +.BE + +.SH DESCRIPTION +.PP +This command performs one of several operations on the +variable given by \fIarrayName\fR. +Unless otherwise specified for individual commands below, +\fIarrayName\fR must be the name of an existing array variable. +The \fIoption\fR argument determines what action is carried +out by the command. +The legal \fIoptions\fR (which may be abbreviated) are: +.TP +\fBarray anymore \fIarrayName searchId\fR +Returns 1 if there are any more elements left to be processed +in an array search, 0 if all elements have already been +returned. +\fISearchId\fR indicates which search on \fIarrayName\fR to +check, and must have been the return value from a previous +invocation of \fBarray startsearch\fR. +This option is particularly useful if an array has an element +with an empty name, since the return value from +\fBarray nextelement\fR won't indicate whether the search +has been completed. +.TP +\fBarray donesearch \fIarrayName searchId\fR +This command terminates an array search and destroys all the +state associated with that search. \fISearchId\fR indicates +which search on \fIarrayName\fR to destroy, and must have +been the return value from a previous invocation of +\fBarray startsearch\fR. Returns an empty string. +.TP +\fBarray exists \fIarrayName\fR +Returns 1 if \fIarrayName\fR is an array variable, 0 if there +is no variable by that name or if it is a scalar variable. +.TP +\fBarray get \fIarrayName\fR ?\fIpattern\fR? +Returns a list containing pairs of elements. The first +element in each pair is the name of an element in \fIarrayName\fR +and the second element of each pair is the value of the +array element. The order of the pairs is undefined. +If \fIpattern\fR is not specified, then all of the elements of the +array are included in the result. +If \fIpattern\fR is specified, then only those elements whose names +match \fIpattern\fR (using the matching rules of +\fBstring match\fR) are included. +If \fIarrayName\fR isn't the name of an array variable, or if +the array contains no elements, then an empty list is returned. +.TP +\fBarray names \fIarrayName\fR ?\fIpattern\fR? +Returns a list containing the names of all of the elements in +the array that match \fIpattern\fR (using the matching +rules of \fBstring match\fR). +If \fIpattern\fR is omitted then the command returns all of +the element names in the array. +If there are no (matching) elements in the array, or if \fIarrayName\fR +isn't the name of an array variable, then an empty string is +returned. +.TP +\fBarray nextelement \fIarrayName searchId\fR +Returns the name of the next element in \fIarrayName\fR, or +an empty string if all elements of \fIarrayName\fR have +already been returned in this search. The \fIsearchId\fR +argument identifies the search, and must have +been the return value of an \fBarray startsearch\fR command. +Warning: if elements are added to or deleted from the array, +then all searches are automatically terminated just as if +\fBarray donesearch\fR had been invoked; this will cause +\fBarray nextelement\fR operations to fail for those searches. +.TP +\fBarray set \fIarrayName list\fR +Sets the values of one or more elements in \fIarrayName\fR. +\fIlist\fR must have a form like that returned by \fBarray get\fR, +consisting of an even number of elements. +Each odd-numbered element in \fIlist\fR is treated as an element +name within \fIarrayName\fR, and the following element in \fIlist\fR +is used as a new value for that array element. +If the variable \fIarrayName\fR does not already exist +and \fIlist\fR is empty, +\fIarrayName\fR is created with an empty array value. +.TP +\fBarray size \fIarrayName\fR +Returns a decimal string giving the number of elements in the +array. +If \fIarrayName\fR isn't the name of an array then 0 is returned. +.TP +\fBarray startsearch \fIarrayName\fR +This command initializes an element-by-element search through the +array given by \fIarrayName\fR, such that invocations of the +\fBarray nextelement\fR command will return the names of the +individual elements in the array. +When the search has been completed, the \fBarray donesearch\fR +command should be invoked. +The return value is a +search identifier that must be used in \fBarray nextelement\fR +and \fBarray donesearch\fR commands; it allows multiple +searches to be underway simultaneously for the same array. +.VS 8.3 +.TP +\fBarray unset \fIarrayName\fR ?\fIpattern\fR? +Unsets all of the elements in the array that match \fIpattern\fR (using the +matching rules of \fBstring match\fR). If \fIarrayName\fR isn't the name +of an array variable or there are no matching elements in the array, then +an empty string is returned. If \fIpattern\fR is omitted and is it an +array variable, then the command unsets the entire array. +.VE 8.3 + +.SH KEYWORDS +array, element names, search diff --git a/mk4/modtcl/tcl8.3.4/doc/bgerror.n b/mk4/modtcl/tcl8.3.4/doc/bgerror.n new file mode 100644 index 0000000..3384fc8 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/bgerror.n @@ -0,0 +1,79 @@ +'\" +'\" Copyright (c) 1990-1994 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: bgerror.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH bgerror n 7.5 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +bgerror \- Command invoked to process background errors +.SH SYNOPSIS +\fBbgerror \fImessage\fR +.BE + +.SH DESCRIPTION +.PP +The \fBbgerror\fR command doesn't exist as built-in part of Tcl. Instead, +individual applications or users can define a \fBbgerror\fR +command (e.g. as a Tcl procedure) if they wish to handle background +errors. +.PP +A background error is one that occurs in an event handler or some +other command that didn't originate with the application. +For example, if an error occurs while executing a command specified +with the \fBafter\fR command, then it is a background error. +For a non-background error, the error can simply be returned up +through nested Tcl command evaluations until it reaches the top-level +code in the application; then the application can report the error +in whatever way it wishes. When a background error occurs, the +unwinding ends in the Tcl library and there is no obvious way for Tcl +to report the error. +.PP +When Tcl detects a background error, it saves information about the +error and invokes the \fBbgerror\fR command later as an idle event +handler. Before invoking \fBbgerror\fR, Tcl restores the +\fBerrorInfo\fR and \fBerrorCode\fR variables to their values at the +time the error occurred, then it invokes \fBbgerror\fR with the error +message as its only argument. Tcl assumes that the application has +implemented the \fBbgerror\fR command, and that the command will +report the error in a way that makes sense for the application. Tcl +will ignore any result returned by the \fBbgerror\fR command as long +as no error is generated. +.PP +If another Tcl error occurs within the \fBbgerror\fR command (for +example, because no \fBbgerror\fR command has been defined) then Tcl +reports the error itself by writing a message to stderr. +.PP +If several background errors accumulate before \fBbgerror\fR is +invoked to process them, \fBbgerror\fR will be invoked once for each +error, in the order they occurred. However, if \fBbgerror\fR returns +with a break exception, then any remaining errors are skipped without +calling \fBbgerror\fR. +.PP +Tcl has no default implementation for \fBbgerror\fR. However, in +applications using Tk there is a default \fBbgerror\fR procedure which +posts a dialog box containing the error message and offers the user a +chance to see a stack trace showing where the error occurred. In +addition to allowing the user to view the stack trace, the dialog +provides an additional application configurable button which may be +used, for example, to save the stack trace to a file. By default, +this is the behavior associated with that button. This behavior can +be redefined by setting the option database values +\fB*ErrorDialog.function.text\fR, to specify the caption for the +function button, and \fB*ErrorDialog.function.command\fR, to specify +the command to be run. The text of the stack trace is appended to the +command when it is evaluated. If either of these options is set to +the empty string, then the additional button will not be displayed in +the dialog. + +.SH "SEE ALSO" +after(n), tclvars(n) + +.SH KEYWORDS +background error, reporting diff --git a/mk4/modtcl/tcl8.3.4/doc/binary.n b/mk4/modtcl/tcl8.3.4/doc/binary.n new file mode 100644 index 0000000..b9253bf --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/binary.n @@ -0,0 +1,548 @@ +'\" +'\" Copyright (c) 1997 by Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: binary.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH binary n 8.0 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +binary \- Insert and extract fields from binary strings +.SH SYNOPSIS +\fBbinary format \fIformatString \fR?\fIarg arg ...\fR? +.br +\fBbinary scan \fIstring formatString \fR?\fIvarName varName ...\fR? +.BE + +.SH DESCRIPTION +.PP +This command provides facilities for manipulating binary data. The +first form, \fBbinary format\fR, creates a binary string from normal +Tcl values. For example, given the values 16 and 22, on a 32 bit +architecture, it might produce an 8-byte binary string consisting of +two 4-byte integers, one for each of the numbers. The second form of +the command, \fBbinary scan\fR, does the opposite: it extracts data +from a binary string and returns it as ordinary Tcl string values. + +.SH "BINARY FORMAT" +.PP +The \fBbinary format\fR command generates a binary string whose layout +is specified by the \fIformatString\fR and whose contents come from +the additional arguments. The resulting binary value is returned. +.PP +The \fIformatString\fR consists of a sequence of zero or more field +specifiers separated by zero or more spaces. Each field specifier is +a single type character followed by an optional numeric \fIcount\fR. +Most field specifiers consume one argument to obtain the value to be +formatted. The type character specifies how the value is to be +formatted. The \fIcount\fR typically indicates how many items of the +specified type are taken from the value. If present, the \fIcount\fR +is a non-negative decimal integer or \fB*\fR, which normally indicates +that all of the items in the value are to be used. If the number of +arguments does not match the number of fields in the format string +that consume arguments, then an error is generated. +.PP +Each type-count pair moves an imaginary cursor through the binary +data, storing bytes at the current position and advancing the cursor +to just after the last byte stored. The cursor is initially at +position 0 at the beginning of the data. The type may be any one of +the following characters: +.IP \fBa\fR 5 +Stores a character string of length \fIcount\fR in the output string. +If \fIarg\fR has fewer than \fIcount\fR bytes, then additional zero +bytes are used to pad out the field. If \fIarg\fR is longer than the +specified length, the extra characters will be ignored. If +\fIcount\fR is \fB*\fR, then all of the bytes in \fIarg\fR will be +formatted. If \fIcount\fR is omitted, then one character will be +formatted. For example, +.RS +.CS +\fBbinary format a7a*a alpha bravo charlie\fR +.CE +will return a string equivalent to \fBalpha\\000\\000bravoc\fR. +.RE +.IP \fBA\fR 5 +This form is the same as \fBa\fR except that spaces are used for +padding instead of nulls. For example, +.RS +.CS +\fBbinary format A6A*A alpha bravo charlie\fR +.CE +will return \fBalpha bravoc\fR. +.RE +.IP \fBb\fR 5 +Stores a string of \fIcount\fR binary digits in low-to-high order +within each byte in the output string. \fIArg\fR must contain a +sequence of \fB1\fR and \fB0\fR characters. The resulting bytes are +emitted in first to last order with the bits being formatted in +low-to-high order within each byte. If \fIarg\fR has fewer than +\fIcount\fR digits, then zeros will be used for the remaining bits. +If \fIarg\fR has more than the specified number of digits, the extra +digits will be ignored. If \fIcount\fR is \fB*\fR, then all of the +digits in \fIarg\fR will be formatted. If \fIcount\fR is omitted, +then one digit will be formatted. If the number of bits formatted +does not end at a byte boundary, the remaining bits of the last byte +will be zeros. For example, +.RS +.CS +\fBbinary format b5b* 11100 111000011010\fR +.CE +will return a string equivalent to \fB\\x07\\x87\\x05\fR. +.RE +.IP \fBB\fR 5 +This form is the same as \fBb\fR except that the bits are stored in +high-to-low order within each byte. For example, +.RS +.CS +\fBbinary format B5B* 11100 111000011010\fR +.CE +will return a string equivalent to \fB\\xe0\\xe1\\xa0\fR. +.RE +.IP \fBh\fR 5 +Stores a string of \fIcount\fR hexadecimal digits in low-to-high +within each byte in the output string. \fIArg\fR must contain a +sequence of characters in the set ``0123456789abcdefABCDEF''. The +resulting bytes are emitted in first to last order with the hex digits +being formatted in low-to-high order within each byte. If \fIarg\fR +has fewer than \fIcount\fR digits, then zeros will be used for the +remaining digits. If \fIarg\fR has more than the specified number of +digits, the extra digits will be ignored. If \fIcount\fR is +\fB*\fR, then all of the digits in \fIarg\fR will be formatted. If +\fIcount\fR is omitted, then one digit will be formatted. If the +number of digits formatted does not end at a byte boundary, the +remaining bits of the last byte will be zeros. For example, +.RS +.CS +\fBbinary format h3h* AB def\fR +.CE +will return a string equivalent to \fB\\xba\\x00\\xed\\x0f\fR. +.RE +.IP \fBH\fR 5 +This form is the same as \fBh\fR except that the digits are stored in +high-to-low order within each byte. For example, +.RS +.CS +\fBbinary format H3H* ab DEF\fR +.CE +will return a string equivalent to \fB\\xab\\x00\\xde\\xf0\fR. +.RE +.IP \fBc\fR 5 +Stores one or more 8-bit integer values in the output string. If no +\fIcount\fR is specified, then \fIarg\fR must consist of an integer +value; otherwise \fIarg\fR must consist of a list containing at least +\fIcount\fR integer elements. The low-order 8 bits of each integer +are stored as a one-byte value at the cursor position. If \fIcount\fR +is \fB*\fR, then all of the integers in the list are formatted. If +the number of elements in the list is fewer than \fIcount\fR, then an +error is generated. If the number of elements in the list is greater +than \fIcount\fR, then the extra elements are ignored. For example, +.RS +.CS +\fBbinary format c3cc* {3 -3 128 1} 260 {2 5}\fR +.CE +will return a string equivalent to +\fB\\x03\\xfd\\x80\\x04\\x02\\x05\fR, whereas +.CS +\fBbinary format c {2 5}\fR +.CE +will generate an error. +.RE +.IP \fBs\fR 5 +This form is the same as \fBc\fR except that it stores one or more +16-bit integers in little-endian byte order in the output string. The +low-order 16-bits of each integer are stored as a two-byte value at +the cursor position with the least significant byte stored first. For +example, +.RS +.CS +\fBbinary format s3 {3 -3 258 1}\fR +.CE +will return a string equivalent to +\fB\\x03\\x00\\xfd\\xff\\x02\\x01\fR. +.RE +.IP \fBS\fR 5 +This form is the same as \fBs\fR except that it stores one or more +16-bit integers in big-endian byte order in the output string. For +example, +.RS +.CS +\fBbinary format S3 {3 -3 258 1}\fR +.CE +will return a string equivalent to +\fB\\x00\\x03\\xff\\xfd\\x01\\x02\fR. +.RE +.IP \fBi\fR 5 +This form is the same as \fBc\fR except that it stores one or more +32-bit integers in little-endian byte order in the output string. The +low-order 32-bits of each integer are stored as a four-byte value at +the cursor position with the least significant byte stored first. For +example, +.RS +.CS +\fBbinary format i3 {3 -3 65536 1}\fR +.CE +will return a string equivalent to +\fB\\x03\\x00\\x00\\x00\\xfd\\xff\\xff\\xff\\x00\\x00\\x01\\x00\fR +.RE +.IP \fBI\fR 5 +This form is the same as \fBi\fR except that it stores one or more one +or more 32-bit integers in big-endian byte order in the output string. +For example, +.RS +.CS +\fBbinary format I3 {3 -3 65536 1}\fR +.CE +will return a string equivalent to +\fB\\x00\\x00\\x00\\x03\\xff\\xff\\xff\\xfd\\x00\\x01\\x00\\x00\fR +.RE +.IP \fBf\fR 5 +This form is the same as \fBc\fR except that it stores one or more one +or more single-precision floating in the machine's native +representation in the output string. This representation is not +portable across architectures, so it should not be used to communicate +floating point numbers across the network. The size of a floating +point number may vary across architectures, so the number of bytes +that are generated may vary. If the value overflows the +machine's native representation, then the value of FLT_MAX +as defined by the system will be used instead. Because Tcl uses +double-precision floating-point numbers internally, there may be some +loss of precision in the conversion to single-precision. For example, +on a Windows system running on an Intel Pentium processor, +.RS +.CS +\fBbinary format f2 {1.6 3.4}\fR +.CE +will return a string equivalent to +\fB\\xcd\\xcc\\xcc\\x3f\\x9a\\x99\\x59\\x40\fR. +.RE +.IP \fBd\fR 5 +This form is the same as \fBf\fR except that it stores one or more one +or more double-precision floating in the machine's native +representation in the output string. For example, on a +Windows system running on an Intel Pentium processor, +.RS +.CS +\fBbinary format d1 {1.6}\fR +.CE +will return a string equivalent to +\fB\\x9a\\x99\\x99\\x99\\x99\\x99\\xf9\\x3f\fR. +.RE +.IP \fBx\fR 5 +Stores \fIcount\fR null bytes in the output string. If \fIcount\fR is +not specified, stores one null byte. If \fIcount\fR is \fB*\fR, +generates an error. This type does not consume an argument. For +example, +.RS +.CS +\fBbinary format a3xa3x2a3 abc def ghi\fR +.CE +will return a string equivalent to \fBabc\\000def\\000\\000ghi\fR. +.RE +.IP \fBX\fR 5 +Moves the cursor back \fIcount\fR bytes in the output string. If +\fIcount\fR is \fB*\fR or is larger than the current cursor position, +then the cursor is positioned at location 0 so that the next byte +stored will be the first byte in the result string. If \fIcount\fR is +omitted then the cursor is moved back one byte. This type does not +consume an argument. For example, +.RS +.CS +\fBbinary format a3X*a3X2a3 abc def ghi\fR +.CE +will return \fBdghi\fR. +.RE +.IP \fB@\fR 5 +Moves the cursor to the absolute location in the output string +specified by \fIcount\fR. Position 0 refers to the first byte in the +output string. If \fIcount\fR refers to a position beyond the last +byte stored so far, then null bytes will be placed in the unitialized +locations and the cursor will be placed at the specified location. If +\fIcount\fR is \fB*\fR, then the cursor is moved to the current end of +the output string. If \fIcount\fR is omitted, then an error will be +generated. This type does not consume an argument. For example, +.RS +.CS +\fBbinary format a5@2a1@*a3@10a1 abcde f ghi j\fR +.CE +will return \fBabfdeghi\\000\\000j\fR. +.RE + +.SH "BINARY SCAN" +.PP +The \fBbinary scan\fR command parses fields from a binary string, +returning the number of conversions performed. \fIString\fR gives the +input to be parsed and \fIformatString\fR indicates how to parse it. +Each \fIvarName\fR gives the name of a variable; when a field is +scanned from \fIstring\fR the result is assigned to the corresponding +variable. +.PP +As with \fBbinary format\fR, the \fIformatString\fR consists of a +sequence of zero or more field specifiers separated by zero or more +spaces. Each field specifier is a single type character followed by +an optional numeric \fIcount\fR. Most field specifiers consume one +argument to obtain the variable into which the scanned values should +be placed. The type character specifies how the binary data is to be +interpreted. The \fIcount\fR typically indicates how many items of +the specified type are taken from the data. If present, the +\fIcount\fR is a non-negative decimal integer or \fB*\fR, which +normally indicates that all of the remaining items in the data are to +be used. If there are not enough bytes left after the current cursor +position to satisfy the current field specifier, then the +corresponding variable is left untouched and \fBbinary scan\fR returns +immediately with the number of variables that were set. If there are +not enough arguments for all of the fields in the format string that +consume arguments, then an error is generated. +.PP +It is \fBimportant\fR to note that the \fBc\fR, \fBs\fR, and \fBS\fR +(and \fBi\fR and \fBI\fR on 64bit systems) will be scanned into +long data size values. In doing this, values that have their high +bit set (0x80 for chars, 0x8000 for shorts, 0x80000000 for ints), +will be sign extended. Thus the following will occur: +.CS +\fBset signShort [binary format s1 0x8000]\fR +\fBbinary scan $signShort s1 val; \fI# val == 0xFFFF8000\fR +.CE +If you want to produce an unsigned value, then you can mask the return +value to the desired size. For example, to produce an unsigned short +value: +.CS +\fBset val [expr {$val & 0xFFFF}]; \fI# val == 0x8000\fR +.CE +.PP +Each type-count pair moves an imaginary cursor through the binary data, +reading bytes from the current position. The cursor is initially +at position 0 at the beginning of the data. The type may be any one of +the following characters: +.IP \fBa\fR 5 +The data is a character string of length \fIcount\fR. If \fIcount\fR +is \fB*\fR, then all of the remaining bytes in \fIstring\fR will be +scanned into the variable. If \fIcount\fR is omitted, then one +character will be scanned. For example, +.RS +.CS +\fBbinary scan abcde\\000fghi a6a10 var1 var2\fR +.CE +will return \fB1\fR with the string equivalent to \fBabcde\\000\fR +stored in \fBvar1\fR and \fBvar2\fR left unmodified. +.RE +.IP \fBA\fR 5 +This form is the same as \fBa\fR, except trailing blanks and nulls are stripped from +the scanned value before it is stored in the variable. For example, +.RS +.CS +\fBbinary scan "abc efghi \\000" A* var1\fR +.CE +will return \fB1\fR with \fBabc efghi\fR stored in \fBvar1\fR. +.RE +.IP \fBb\fR 5 +The data is turned into a string of \fIcount\fR binary digits in +low-to-high order represented as a sequence of ``1'' and ``0'' +characters. The data bytes are scanned in first to last order with +the bits being taken in low-to-high order within each byte. Any extra +bits in the last byte are ignored. If \fIcount\fR is \fB*\fR, then +all of the remaining bits in \fBstring\fR will be scanned. If +\fIcount\fR is omitted, then one bit will be scanned. For example, +.RS +.CS +\fBbinary scan \\x07\\x87\\x05 b5b* var1 var2\fR +.CE +will return \fB2\fR with \fB11100\fR stored in \fBvar1\fR and +\fB1110000110100000\fR stored in \fBvar2\fR. +.RE +.IP \fBB\fR 5 +This form is the same as \fBb\fR, except the bits are taken in +high-to-low order within each byte. For example, +.RS +.CS +\fBbinary scan \\x70\\x87\\x05 B5B* var1 var2\fR +.CE +will return \fB2\fR with \fB01110\fR stored in \fBvar1\fR and +\fB1000011100000101\fR stored in \fBvar2\fR. +.RE +.IP \fBh\fR 5 +The data is turned into a string of \fIcount\fR hexadecimal digits in +low-to-high order represented as a sequence of characters in the set +``0123456789abcdef''. The data bytes are scanned in first to last +order with the hex digits being taken in low-to-high order within each +byte. Any extra bits in the last byte are ignored. If \fIcount\fR +is \fB*\fR, then all of the remaining hex digits in \fBstring\fR will be +scanned. If \fIcount\fR is omitted, then one hex digit will be +scanned. For example, +.RS +.CS +\fBbinary scan \\x07\\x86\\x05 h3h* var1 var2\fR +.CE +will return \fB2\fR with \fB706\fR stored in \fBvar1\fR and +\fB50\fR stored in \fBvar2\fR. +.RE +.IP \fBH\fR 5 +This form is the same as \fBh\fR, except the digits are taken in +high-to-low order within each byte. For example, +.RS +.CS +\fBbinary scan \\x07\\x86\\x05 H3H* var1 var2\fR +.CE +will return \fB2\fR with \fB078\fR stored in \fBvar1\fR and +\fB05\fR stored in \fBvar2\fR. +.RE +.IP \fBc\fR 5 +The data is turned into \fIcount\fR 8-bit signed integers and stored +in the corresponding variable as a list. If \fIcount\fR is \fB*\fR, +then all of the remaining bytes in \fBstring\fR will be scanned. If +\fIcount\fR is omitted, then one 8-bit integer will be scanned. For +example, +.RS +.CS +\fBbinary scan \\x07\\x86\\x05 c2c* var1 var2\fR +.CE +will return \fB2\fR with \fB7 -122\fR stored in \fBvar1\fR and \fB5\fR +stored in \fBvar2\fR. Note that the integers returned are signed, but +they can be converted to unsigned 8-bit quantities using an expression +like: +.CS +\fBexpr ( $num + 0x100 ) % 0x100\fR +.CE +.RE +.IP \fBs\fR 5 +The data is interpreted as \fIcount\fR 16-bit signed integers +represented in little-endian byte order. The integers are stored in +the corresponding variable as a list. If \fIcount\fR is \fB*\fR, then +all of the remaining bytes in \fBstring\fR will be scanned. If +\fIcount\fR is omitted, then one 16-bit integer will be scanned. For +example, +.RS +.CS +\fBbinary scan \\x05\\x00\\x07\\x00\\xf0\\xff s2s* var1 var2\fR +.CE +will return \fB2\fR with \fB5 7\fR stored in \fBvar1\fR and \fB-16\fR +stored in \fBvar2\fR. Note that the integers returned are signed, but +they can be converted to unsigned 16-bit quantities using an expression +like: +.CS +\fBexpr ( $num + 0x10000 ) % 0x10000\fR +.CE +.RE +.IP \fBS\fR 5 +This form is the same as \fBs\fR except that the data is interpreted +as \fIcount\fR 16-bit signed integers represented in big-endian byte +order. For example, +.RS +.CS +\fBbinary scan \\x00\\x05\\x00\\x07\\xff\\xf0 S2S* var1 var2\fR +.CE +will return \fB2\fR with \fB5 7\fR stored in \fBvar1\fR and \fB-16\fR +stored in \fBvar2\fR. +.RE +.IP \fBi\fR 5 +The data is interpreted as \fIcount\fR 32-bit signed integers +represented in little-endian byte order. The integers are stored in +the corresponding variable as a list. If \fIcount\fR is \fB*\fR, then +all of the remaining bytes in \fBstring\fR will be scanned. If +\fIcount\fR is omitted, then one 32-bit integer will be scanned. For +example, +.RS +.CS +\fBbinary scan \\x05\\x00\\x00\\x00\\x07\\x00\\x00\\x00\\xf0\\xff\\xff\\xff i2i* var1 var2\fR +.CE +will return \fB2\fR with \fB5 7\fR stored in \fBvar1\fR and \fB-16\fR +stored in \fBvar2\fR. Note that the integers returned are signed and +cannot be represented by Tcl as unsigned values. +.RE +.IP \fBI\fR 5 +This form is the same as \fBI\fR except that the data is interpreted +as \fIcount\fR 32-bit signed integers represented in big-endian byte +order. For example, +.RS +.CS +\fBbinary \\x00\\x00\\x00\\x05\\x00\\x00\\x00\\x07\\xff\\xff\\xff\\xf0 I2I* var1 var2\fR +.CE +will return \fB2\fR with \fB5 7\fR stored in \fBvar1\fR and \fB-16\fR +stored in \fBvar2\fR. +.RE +.IP \fBf\fR 5 +The data is interpreted as \fIcount\fR single-precision floating point +numbers in the machine's native representation. The floating point +numbers are stored in the corresponding variable as a list. If +\fIcount\fR is \fB*\fR, then all of the remaining bytes in +\fBstring\fR will be scanned. If \fIcount\fR is omitted, then one +single-precision floating point number will be scanned. The size of a +floating point number may vary across architectures, so the number of +bytes that are scanned may vary. If the data does not represent a +valid floating point number, the resulting value is undefined and +compiler dependent. For example, on a Windows system running on an +Intel Pentium processor, +.RS +.CS +\fBbinary scan \\x3f\\xcc\\xcc\\xcd f var1\fR +.CE +will return \fB1\fR with \fB1.6000000238418579\fR stored in +\fBvar1\fR. +.RE +.IP \fBd\fR 5 +This form is the same as \fBf\fR except that the data is interpreted +as \fIcount\fR double-precision floating point numbers in the +machine's native representation. For example, on a Windows system +running on an Intel Pentium processor, +.RS +.CS +\fBbinary scan \\x9a\\x99\\x99\\x99\\x99\\x99\\xf9\\x3f d var1\fR +.CE +will return \fB1\fR with \fB1.6000000000000001\fR +stored in \fBvar1\fR. +.RE +.IP \fBx\fR 5 +Moves the cursor forward \fIcount\fR bytes in \fIstring\fR. If +\fIcount\fR is \fB*\fR or is larger than the number of bytes after the +current cursor cursor position, then the cursor is positioned after +the last byte in \fIstring\fR. If \fIcount\fR is omitted, then the +cursor is moved forward one byte. Note that this type does not +consume an argument. For example, +.RS +.CS +\fBbinary scan \\x01\\x02\\x03\\x04 x2H* var1\fR +.CE +will return \fB1\fR with \fB0304\fR stored in \fBvar1\fR. +.RE +.IP \fBX\fR 5 +Moves the cursor back \fIcount\fR bytes in \fIstring\fR. If +\fIcount\fR is \fB*\fR or is larger than the current cursor position, +then the cursor is positioned at location 0 so that the next byte +scanned will be the first byte in \fIstring\fR. If \fIcount\fR +is omitted then the cursor is moved back one byte. Note that this +type does not consume an argument. For example, +.RS +.CS +\fBbinary scan \\x01\\x02\\x03\\x04 c2XH* var1 var2\fR +.CE +will return \fB2\fR with \fB1 2\fR stored in \fBvar1\fR and \fB020304\fR +stored in \fBvar2\fR. +.RE +.IP \fB@\fR 5 +Moves the cursor to the absolute location in the data string specified +by \fIcount\fR. Note that position 0 refers to the first byte in +\fIstring\fR. If \fIcount\fR refers to a position beyond the end of +\fIstring\fR, then the cursor is positioned after the last byte. If +\fIcount\fR is omitted, then an error will be generated. For example, +.RS +.CS +\fBbinary scan \\x01\\x02\\x03\\x04 c2@1H* var1 var2\fR +.CE +will return \fB2\fR with \fB1 2\fR stored in \fBvar1\fR and \fB020304\fR +stored in \fBvar2\fR. +.RE + +.SH "PLATFORM ISSUES" +Sometimes it is desirable to format or scan integer values in the +native byte order for the machine. Refer to the \fBbyteOrder\fR +element of the \fBtcl_platform\fR array to decide which type character +to use when formatting or scanning integers. + +.SH "SEE ALSO" +format(n), scan(n), tclvars(n) + +.SH KEYWORDS +binary, format, scan diff --git a/mk4/modtcl/tcl8.3.4/doc/break.n b/mk4/modtcl/tcl8.3.4/doc/break.n new file mode 100644 index 0000000..a9a2e9b --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/break.n @@ -0,0 +1,37 @@ +'\" +'\" Copyright (c) 1993-1994 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: break.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH break n "" Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +break \- Abort looping command +.SH SYNOPSIS +\fBbreak\fR +.BE + +.SH DESCRIPTION +.PP +This command is typically invoked inside the body of a looping command +such as \fBfor\fR or \fBforeach\fR or \fBwhile\fR. +It returns a TCL_BREAK code, which causes a break exception +to occur. +The exception causes the current script to be aborted +out to the innermost containing loop command, which then +aborts its execution and returns normally. +Break exceptions are also handled in a few other situations, such +as the \fBcatch\fR command, Tk event bindings, and the outermost +scripts of procedure bodies. + +.SH "SEE ALSO" +catch(n), continue(n), for(n), foreach(n), while(n) + +.SH KEYWORDS +abort, break, loop diff --git a/mk4/modtcl/tcl8.3.4/doc/case.n b/mk4/modtcl/tcl8.3.4/doc/case.n new file mode 100644 index 0000000..dd40f80 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/case.n @@ -0,0 +1,62 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: case.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH case n 7.0 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +case \- Evaluate one of several scripts, depending on a given value +.SH SYNOPSIS +\fBcase\fI string \fR?\fBin\fR? \fIpatList body \fR?\fIpatList body \fR...? +.sp +\fBcase\fI string \fR?\fBin\fR? {\fIpatList body \fR?\fIpatList body \fR...?} +.BE + +.SH DESCRIPTION +.PP +\fINote: the \fBcase\fI command is obsolete and is supported only +for backward compatibility. At some point in the future it may be +removed entirely. You should use the \fBswitch\fI command instead.\fR +.PP +The \fBcase\fR command matches \fIstring\fR against each of +the \fIpatList\fR arguments in order. +Each \fIpatList\fR argument is a list of one or +more patterns. If any of these patterns matches \fIstring\fR then +\fBcase\fR evaluates the following \fIbody\fR argument +by passing it recursively to the Tcl interpreter and returns the result +of that evaluation. +Each \fIpatList\fR argument consists of a single +pattern or list of patterns. Each pattern may contain any of the wild-cards +described under \fBstring match\fR. If a \fIpatList\fR +argument is \fBdefault\fR, the corresponding body will be evaluated +if no \fIpatList\fR matches \fIstring\fR. If no \fIpatList\fR argument +matches \fIstring\fR and no default is given, then the \fBcase\fR +command returns an empty string. +.PP +Two syntaxes are provided for the \fIpatList\fR and \fIbody\fR arguments. +The first uses a separate argument for each of the patterns and commands; +this form is convenient if substitutions are desired on some of the +patterns or commands. +The second form places all of the patterns and commands together into +a single argument; the argument must have proper list structure, with +the elements of the list being the patterns and commands. +The second form makes it easy to construct multi-line case commands, +since the braces around the whole list make it unnecessary to include a +backslash at the end of each line. +Since the \fIpatList\fR arguments are in braces in the second form, +no command or variable substitutions are performed on them; this makes +the behavior of the second form different than the first form in some +cases. + +.SH "SEE ALSO" +switch(n) + +.SH KEYWORDS +case, match, regular expression diff --git a/mk4/modtcl/tcl8.3.4/doc/catch.n b/mk4/modtcl/tcl8.3.4/doc/catch.n new file mode 100644 index 0000000..80526d3 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/catch.n @@ -0,0 +1,66 @@ +'\" +'\" Copyright (c) 1993-1994 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: catch.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH catch n "8.0" Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +catch \- Evaluate script and trap exceptional returns +.SH SYNOPSIS +\fBcatch\fI script \fR?\fIvarName\fR? +.BE + +.SH DESCRIPTION +.PP +The \fBcatch\fR command may be used to prevent errors from aborting command +interpretation. \fBCatch\fR calls the Tcl interpreter recursively to +execute \fIscript\fR, and always returns without raising an error, +regardless of any errors that might occur while executing \fIscript\fR. +.PP +If \fIscript\fR raises an error, \fBcatch\fR will return a non-zero integer +value corresponding to one of the exceptional return codes (see tcl.h +for the definitions of code values). If the \fIvarName\fR argument is +given, then the variable it names is set to the error message from +interpreting \fIscript\fR. +.PP +If \fIscript\fR does not raise an error, \fBcatch\fR will return 0 +(TCL_OK) and set the variable to the value returned from \fIscript\fR. +.PP +Note that \fBcatch\fR catches all exceptions, including those +generated by \fBbreak\fR and \fBcontinue\fR as well as errors. The +only errors that are not caught are syntax errors found when the +script is compiled. This is because the catch command only catches +errors during runtime. When the catch statement is compiled, the +script is compiled as well and any syntax errors will generate a Tcl +error. + +.SH EXAMPLES + +The \fBcatch\fR command may be used in an \fBif\fR to branch based on +the success of a script. + +.CS +if { [catch {open $someFile w} fid] } { + puts stderr "Could not open $someFile for writing\\n$fid" + exit 1 +} +.CE +The \fBcatch\fR command will not catch compiled syntax errors. The +first time proc \fBfoo\fR is called, the body will be compiled and a +Tcl error will be generated. + +.CS +proc foo {} { + catch {expr {1 +- }} +} +.CE + +.SH KEYWORDS +catch, error diff --git a/mk4/modtcl/tcl8.3.4/doc/cd.n b/mk4/modtcl/tcl8.3.4/doc/cd.n new file mode 100644 index 0000000..2b67d9f --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/cd.n @@ -0,0 +1,31 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: cd.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH cd n "" Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +cd \- Change working directory +.SH SYNOPSIS +\fBcd \fR?\fIdirName\fR? +.BE + +.SH DESCRIPTION +.PP +Change the current working directory to \fIdirName\fR, or to the +home directory (as specified in the HOME environment variable) if +\fIdirName\fR is not given. +Returns an empty string. + +.SH "SEE ALSO" +filename(n), glob(n), pwd(n) + +.SH KEYWORDS +working directory diff --git a/mk4/modtcl/tcl8.3.4/doc/clock.n b/mk4/modtcl/tcl8.3.4/doc/clock.n new file mode 100644 index 0000000..63881ea --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/clock.n @@ -0,0 +1,214 @@ +'\" +'\" Copyright (c) 1992-1995 Karl Lehenbauer and Mark Diekhans. +'\" Copyright (c) 1995-1997 Sun Microsystems, Inc. +'\" Copyright (c) 1998-1999 Scriptics Corporation +'\" +'\" This documentation is derived from the time and date facilities of +'\" TclX, by Mark Diekhans and Karl Lehenbauer. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: clock.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH clock n 8.3 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +clock \- Obtain and manipulate time +.SH SYNOPSIS +\fBclock \fIoption\fR ?\fIarg arg ...\fR? +.BE + +.SH DESCRIPTION +.PP +This command performs one of several operations that may obtain +or manipulate strings or values that represent some notion of +time. The \fIoption\fR argument determines what action is carried +out by the command. The legal \fIoptions\fR (which may be +abbreviated) are: +.TP +.VS 8.3 +\fBclock clicks\fR ?\fB\-milliseconds\fR? +Return a high-resolution time value as a system-dependent integer +value. The unit of the value is system-dependent but should be the +highest resolution clock available on the system such as a CPU cycle +counter. If \fB\-milliseconds\fR is specified, then the value is +guaranteed to be of millisecond granularity. +This value should only be used for the relative measurement +of elapsed time. +.VE 8.3 +.TP +\fBclock format \fIclockValue\fR ?\fB\-format \fIstring\fR? ?\fB\-gmt \fIboolean\fR? +Converts an integer time value, typically returned by +\fBclock seconds\fR, \fBclock scan\fR, or the \fBatime\fR, \fBmtime\fR, +or \fBctime\fR options of the \fBfile\fR command, to human-readable +form. If the \fB\-format\fR argument is present the next argument is a +string that describes how the date and time are to be formatted. +Field descriptors consist of a \fB%\fR followed by a field +descriptor character. All other characters are copied into the result. +Valid field descriptors are: +.RS +.IP \fB%%\fR +Insert a %. +.IP \fB%a\fR +Abbreviated weekday name (Mon, Tue, etc.). +.IP \fB%A\fR +Full weekday name (Monday, Tuesday, etc.). +.IP \fB%b\fR +Abbreviated month name (Jan, Feb, etc.). +.IP \fB%B\fR +Full month name. +.IP \fB%c\fR +Locale specific date and time. +.IP \fB%d\fR +Day of month (01 - 31). +.IP \fB%H\fR +Hour in 24-hour format (00 - 23). +.IP \fB%I\fR +Hour in 12-hour format (00 - 12). +.IP \fB%j\fR +Day of year (001 - 366). +.IP \fB%m\fR +Month number (01 - 12). +.IP \fB%M\fR +Minute (00 - 59). +.IP \fB%p\fR +AM/PM indicator. +.IP \fB%S\fR +Seconds (00 - 59). +.IP \fB%U\fR +Week of year (00 - 52), Sunday is the first day of the week. +.IP \fB%w\fR +Weekday number (Sunday = 0). +.IP \fB%W\fR +Week of year (00 - 52), Monday is the first day of the week. +.IP \fB%x\fR +Locale specific date format. +.IP \fB%X\fR +Locale specific time format. +.IP \fB%y\fR +Year without century (00 - 99). +.IP \fB%Y\fR +Year with century (e.g. 1990) +.IP \fB%Z\fR +Time zone name. +.RE +.sp +.RS +In addition, the following field descriptors may be supported on some +systems (e.g. Unix but not Windows): +.IP \fB%D\fR +Date as %m/%d/%y. +.IP \fB%e\fR +Day of month (1 - 31), no leading zeros. +.IP \fB%h\fR +Abbreviated month name. +.IP \fB%n\fR +Insert a newline. +.IP \fB%r\fR +Time as %I:%M:%S %p. +.IP \fB%R\fR +Time as %H:%M. +.IP \fB%t\fR +Insert a tab. +.IP \fB%T\fR +Time as %H:%M:%S. +.RE +.sp +.RS +If the \fB\-format\fR argument is not specified, the format string +"\fB%a %b %d %H:%M:%S %Z %Y\fR" is used. If the \fB\-gmt\fR argument +is present the next argument must be a boolean which if true specifies +that the time will be formatted as Greenwich Mean Time. If false +then the local timezone will be used as defined by the operating +environment. +.RE +.TP +\fBclock scan \fIdateString\fR ?\fB\-base \fIclockVal\fR? ?\fB\-gmt \fIboolean\fR? +Convert \fIdateString\fR to an integer clock value (see \fBclock seconds\fR). +This command can parse and convert virtually any standard date and/or time +string, which can include standard time zone mnemonics. If only a time is +specified, the current date is assumed. If the string does not contain a +time zone mnemonic, the local time zone is assumed, unless the \fB\-gmt\fR +argument is true, in which case the clock value is calculated assuming +that the specified time is relative to Greenwich Mean Time. +\fB-gmt\fR, if specified, affects only the computed time value; it does not +impact the interpretation of \fB-base\fR. +.sp +If the \fB\-base\fR flag is specified, the next argument should contain +an integer clock value. Only the date in this value is used, not the +time. This is useful for determining the time on a specific day or +doing other date-relative conversions. +.sp +The \fIdateString\fR consists of zero or more specifications of the +following form: +.RS +.TP +\fItime\fR +A time of day, which is of the form: \fIhh\fR?\fI:mm\fR?\fI:ss\fR?? +?\fImeridian\fR? ?\fIzone\fR? or \fIhhmm \fR?\fImeridian\fR? +?\fIzone\fR?. If no meridian is specified, \fIhh\fR is interpreted on +a 24-hour clock. +.TP +\fIdate\fR +A specific month and day with optional year. The +acceptable formats are \fImm/dd\fR?\fI/yy\fR?, \fImonthname dd\fR +?, \fIyy\fR?, \fIdd monthname \fR?\fIyy\fR?, \fIday, dd monthname +yy\fR, \fI?CC?yymmdd\fR, \fI?CC?yy-mm-dd\fR, \fIdd-monthname-?CC?yy\fR. +The default year is the current year. If the year is less +.VS +than 100, we treat the years 00-68 as 2000-2068 and the years 69-99 +as 1969-1999. Not all platforms can represent the years 38-70, so +an error may result if these years are used. +.VE +.TP +\fIISO 8601 point-in-time\fR +An ISO 8601 point-in-time specification, such as \fICCyymmddThhmmss\fR, where +T is the literal T, \fICCyymmdd hhmmss\fR, or +\fICCyymmddThh:mm:ss\fR. +.TP +\fIrelative time\fR +A specification relative to the current time. The format is \fInumber +unit\fR acceptable units are \fByear\fR, \fBfortnight\fR, \fBmonth\fR, \fBweek\fR, \fBday\fR, +\fBhour\fR, \fBminute\fR (or \fBmin\fR), and \fBsecond\fR (or \fBsec\fR). The +unit can be specified as a singular or plural, as in \fB3 weeks\fR. +These modifiers may also be specified: +\fBtomorrow\fR, \fByesterday\fR, \fBtoday\fR, \fBnow\fR, +\fBlast\fR, \fBthis\fR, \fBnext\fR, \fBago\fR. +.RE +.sp +.RS +The actual date is calculated according to the following steps. +First, any absolute date and/or time is processed and converted. +Using that time as the base, day-of-week specifications are added. +Next, relative specifications are used. If a date or day is +specified, and no absolute or relative time is given, midnight is +used. Finally, a correction is applied so that the correct hour of +the day is produced after allowing for daylight savings time +differences and the correct date is given when going from the end +of a long month to a short month. +.sp +Daylight savings time correction is applied only when the relative time +is specified in units of days or more, ie, days, weeks, fortnights, months or +years. This means that when crossing the daylight savings time boundary, +different results will be given for \fBclock scan "1 day"\fR and +\fBclock scan "24 hours"\fR: +.CS +.ta 6c +\fB% clock scan "1 day" -base [clock scan 1999-10-31] +941443200 +% clock scan "24 hours" -base [clock scan 1999-10-31] +941439600\fR +.CE +.RE +.TP +\fBclock seconds\fR +Return the current date and time as a system-dependent integer value. The +unit of the value is seconds, allowing it to be used for relative time +calculations. The value is usually defined as total elapsed time from +an ``epoch''. You shouldn't assume the value of the epoch. + +.SH KEYWORDS +clock, date, time diff --git a/mk4/modtcl/tcl8.3.4/doc/close.n b/mk4/modtcl/tcl8.3.4/doc/close.n new file mode 100644 index 0000000..abb1828 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/close.n @@ -0,0 +1,62 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: close.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH close n 7.5 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +close \- Close an open channel. +.SH SYNOPSIS +\fBclose \fIchannelId\fR +.BE + +.SH DESCRIPTION +.PP +Closes the channel given by \fIchannelId\fR. \fIChannelId\fR must be a +channel identifier such as the return value from a previous \fBopen\fR +or \fBsocket\fR command. +All buffered output is flushed to the channel's output device, +any buffered input is discarded, the underlying file or device is closed, +and \fIchannelId\fR becomes unavailable for use. +.VS "" br +.PP +If the channel is blocking, the command does not return until all output +is flushed. +If the channel is nonblocking and there is unflushed output, the +channel remains open and the command +returns immediately; output will be flushed in the background and the +channel will be closed when all the flushing is complete. +.VE +.PP +If \fIchannelId\fR is a blocking channel for a command pipeline then +\fBclose\fR waits for the child processes to complete. +.VS "" br +.PP +If the channel is shared between interpreters, then \fBclose\fR +makes \fIchannelId\fR unavailable in the invoking interpreter but has no +other effect until all of the sharing interpreters have closed the +channel. +When the last interpreter in which the channel is registered invokes +\fBclose\fR, the cleanup actions described above occur. See the +\fBinterp\fR command for a description of channel sharing. +.PP +Channels are automatically closed when an interpreter is destroyed and +when the process exits. Channels are switched to blocking mode, to ensure +that all output is correctly flushed before the process exits. +.VE +.PP +The command returns an empty string, and may generate an error if +an error occurs while flushing output. + +.SH "SEE ALSO" +file(n), open(n), socket(n), eof(n) + +.SH KEYWORDS +blocking, channel, close, nonblocking diff --git a/mk4/modtcl/tcl8.3.4/doc/concat.n b/mk4/modtcl/tcl8.3.4/doc/concat.n new file mode 100644 index 0000000..0fafb84 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/concat.n @@ -0,0 +1,43 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: concat.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH concat n "" Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +concat \- Join lists together +.SH SYNOPSIS +\fBconcat\fI \fR?\fIarg arg ...\fR? +.BE + +.SH DESCRIPTION +.PP +This command treats each argument as a list and concatenates them +into a single list. +It also eliminates leading and trailing spaces in the \fIarg\fR's +and adds a single separator space between \fIarg\fR's. +It permits any number of arguments. For example, +the command +.CS +\fBconcat a b {c d e} {f {g h}}\fR +.CE +will return +.CS +\fBa b c d e f {g h}\fR +.CE +as its result. +.PP +If no \fIarg\fRs are supplied, the result is an empty string. + +.SH "SEE ALSO" +append(n), eval(n) + +.SH KEYWORDS +concatenate, join, lists diff --git a/mk4/modtcl/tcl8.3.4/doc/continue.n b/mk4/modtcl/tcl8.3.4/doc/continue.n new file mode 100644 index 0000000..b1b74ce --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/continue.n @@ -0,0 +1,37 @@ +'\" +'\" Copyright (c) 1993-1994 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: continue.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH continue n "" Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +continue \- Skip to the next iteration of a loop +.SH SYNOPSIS +\fBcontinue\fR +.BE + +.SH DESCRIPTION +.PP +This command is typically invoked inside the body of a looping command +such as \fBfor\fR or \fBforeach\fR or \fBwhile\fR. +It returns a TCL_CONTINUE code, which causes a continue exception +to occur. +The exception causes the current script to be aborted +out to the innermost containing loop command, which then +continues with the next iteration of the loop. +Catch exceptions are also handled in a few other situations, such +as the \fBcatch\fR command and the outermost scripts of procedure +bodies. + +.SH "SEE ALSO" +break(n), for(n), foreach(n), while(n) + +.SH KEYWORDS +continue, iteration, loop diff --git a/mk4/modtcl/tcl8.3.4/doc/dde.n b/mk4/modtcl/tcl8.3.4/doc/dde.n new file mode 100644 index 0000000..5756760 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/dde.n @@ -0,0 +1,136 @@ +'\" +'\" Copyright (c) 1997 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: dde.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH dde n 8.1 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +dde \- Execute a Dynamic Data Exchange command +.SH SYNOPSIS +.sp +\fBpackage require dde 1.1\fR +.sp +\fBdde \fIservername \fR?\fItopic\fR? +.sp +\fBdde ?\-async?\fR \fIcommand service topic \fR?\fIdata\fR? +.BE + +.SH DESCRIPTION +.PP +This command allows an application to send Dynamic Data Exchange (DDE) +command when running under Microsoft Windows. Dynamic Data Exchange is +a mechanism where applications can exchange raw data. Each DDE +transaction needs a \fIservice name\fR and a \fItopic\fR. Both the +\fIservice name\fR and \fItopic\fR are application defined; Tcl uses +the service name \fBTclEval\fR, while the topic name is the name of the +interpreter given by \fBdde servername\fR. Other applications have their +own \fIservice names\fR and \fItopics\fR. For instance, Microsoft Excel +has the service name \fBExcel\fR. +.PP +The only option to the \fBdde\fR command is: +.TP +\fB\-async\fR +Requests asynchronous invocation. This is valid only for the +\fBexecute\fR subcommand. Normally, the \fBdde execute\fR subcommand +waits until the command completes, returning appropriate error +messages. When the \fB\-async\fR option is used, the command returns +immediately, and no error information is available. +.SH "DDE COMMANDS" +.PP +The following commands are a subset of the full Dynamic Data Exchange +set of commands. +.TP +\fBdde servername \fR?\fItopic\fR? +\fBdde servername\fR registers the interpreter as a DDE server with +the service name \fBTclEval\fR and the topic name specified by \fItopic\fR. +If no \fItopic\fR is given, \fBdde servername\fR returns the name +of the current topic or the empty string if it is not registered as a service. +.TP +\fBdde execute \fIservice topic data\fR +\fBdde execute\fR takes the \fIdata\fR and sends it to the server +indicated by \fIservice\fR with the topic indicated by +\fItopic\fR. Typically, \fIservice\fR is the name of an application, +and \fItopic\fR is a file to work on. The \fIdata\fR field is given +to the remote application. Typically, the application treats the +\fIdata\fR field as a script, and the script is run in the +application. The command returns an error if the script did not +run. If the \fB\-async\fR flag was used, the command +returns immediately with no error. +.TP +\fBdde poke \fIservice topic item data\fR +\fBdde poke\fR passes the \fIdata\fR to the server indicated by +\fIservice\fR using the \fItopic\fR and \fIitem\fR specified. Typically, +\fIservice\fR is the name of an application. \fItopic\fR is application +specific but can be a command to the server or the name of a file to work +on. The \fIitem\fR is also application specific and is often not used, but +it must always be non-null. The \fIdata\fR field is given to the remote +application. +.TP +\fBdde request \fIservice topic item\fR +\fBdde request\fR is typically used to get the value of something; the +value of a cell in Microsoft Excel or the text of a selection in +Microsoft Word. \fIservice\fR is typically the name of an application, +\fItopic\fR is typically the name of the file, and \fIitem\fR is +application-specific. The command returns the value of \fIitem\fR as +defined in the application. +.TP +\fBdde services \fIservice topic\fR +\fBdde services\fR returns a list of service-topic pairs that +currently exist on the machine. If \fIservice\fR and \fItopic\fR are +both null strings ({}), then all service-topic pairs currently +available on the system are returned. If \fIservice\fR is null and +\fItopic\fR is not, then all services with the specified topic are +returned. If \fIservice\fR is not null and \fItopic\fR is, all topics +for a given service are returned. If both are not null, if that +service-topic pair currently exists, it is returned; otherwise, null +is returned. +.TP +\fBdde eval \fItopic cmd \fR?\fIarg arg ...\fR? +\fBdde eval\fR evaluates a command and its arguments using the +interpreter specified by \fItopic\fR. The DDE service must be the +\fBTclEval\fR service. This command can be used to replace send on +Windows. +.SH "DDE AND TCL" +A Tcl interpreter always has a service name of \fBTclEval\fR. Each +different interpreter of all running Tcl applications must be +given a unique +name specified by \fBdde servername\fR. Each interp is available as a +DDE topic only if the \fBdde servername\fR command was used to set the +name of the topic for each interp. So a \fBdde services TclEval {}\fR +command will return a list of service-topic pairs, where each of the +currently running interps will be a topic. +.PP +When Tcl processes a \fBdde execute\fR command, the data for the +execute is run as a script in the interp named by the topic of the +\fBdde execute\fR command. +.PP +When Tcl processes a \fBdde request\fR command, it returns the value of the +variable given in the dde command in the context of the interp named by the +dde topic. Tcl reserves the variable \fB$TCLEVAL$EXECUTE$RESULT\fR for +internal use, and \fBdde request\fR commands for that variable will give +unpredictable results. +.PP +An external application which wishes to run a script in Tcl should have +that script store its result in a variable, run the \fBdde execute\fR +command, and the run \fBdde request\fR to get the value of the +variable. +.PP +When using DDE, be careful to ensure that the event queue is flushed +using either \fBupdate\fR or \fBvwait\fR. This happens by default +when using \fBwish\fR unless a blocking command is called (such as \fBexec\fR +without adding the \fB&\fR to place the process in the background). +If for any reason the event queue is not flushed, DDE commands may +hang until the event queue is flushed. This can create a deadlock +situation. + +.SH "SEE ALSO" +tk(n), winfo(n), send(n) + +.SH KEYWORDS +application, dde, name, remote execution diff --git a/mk4/modtcl/tcl8.3.4/doc/encoding.n b/mk4/modtcl/tcl8.3.4/doc/encoding.n new file mode 100644 index 0000000..c1a3760 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/encoding.n @@ -0,0 +1,79 @@ +'\" +'\" Copyright (c) 1998 by Scriptics Corporation. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: encoding.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH encoding n "8.1" Tcl "Tcl Built-In Commands" +.BS +.SH NAME +encoding \- Manipulate encodings +.SH SYNOPSIS +\fBencoding \fIoption\fR ?\fIarg arg ...\fR? +.BE + +.SH INTRODUCTION +.PP +Strings in Tcl are encoded using 16-bit Unicode characters. Different +operating system interfaces or applications may generate strings in +other encodings such as Shift-JIS. The \fBencoding\fR command helps +to bridge the gap between Unicode and these other formats. + +.SH DESCRIPTION +.PP +Performs one of several encoding related operations, depending on +\fIoption\fR. The legal \fIoption\fRs are: +.TP +\fBencoding convertfrom ?\fIencoding\fR? \fIdata\fR +Convert \fIdata\fR to Unicode from the specified \fIencoding\fR. The +characters in \fIdata\fR are treated as binary data where the lower +8-bits of each character is taken as a single byte. The resulting +sequence of bytes is treated as a string in the specified +\fIencoding\fR. If \fIencoding\fR is not specified, the current +system encoding is used. +.TP +\fBencoding convertto ?\fIencoding\fR? \fIstring\fR +Convert \fIstring\fR from Unicode to the specified \fIencoding\fR. +The result is a sequence of bytes that represents the converted +string. Each byte is stored in the lower 8-bits of a Unicode +character. If \fIencoding\fR is not specified, the current +system encoding is used. +.TP +\fBencoding names\fR +Returns a list containing the names of all of the encodings that are +currently available. +.TP +\fBencoding system\fR ?\fIencoding\fR? +Set the system encoding to \fIencoding\fR. If \fIencoding\fR is +omitted then the command returns the current system encoding. The +system encoding is used whenever Tcl passes strings to system calls. + +.SH EXAMPLE +.PP +It is common practice to write script files using a text editor that +produces output in the euc-jp encoding, which represents the ASCII +characters as singe bytes and Japanese characters as two bytes. This +makes it easy to embed literal strings that correspond to non-ASCII +characters by simply typing the strings in place in the script. +However, because the \fBsource\fR command always reads files using the +ISO8859-1 encoding, Tcl will treat each byte in the file as a separate +character that maps to the 00 page in Unicode. The +resulting Tcl strings will not contain the expected Japanese +characters. Instead, they will contain a sequence of Latin-1 +characters that correspond to the bytes of the original string. The +\fBencoding\fR command can be used to convert this string to the +expected Japanese Unicode characters. For example, +.CS + set s [encoding convertfrom euc-jp "\\xA4\\xCF"] +.CE +would return the Unicode string "\\u306F", which is the Hiragana +letter HA. + +.SH "SEE ALSO" +Tcl_GetEncoding(3) + +.SH KEYWORDS +encoding diff --git a/mk4/modtcl/tcl8.3.4/doc/eof.n b/mk4/modtcl/tcl8.3.4/doc/eof.n new file mode 100644 index 0000000..ce61b20 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/eof.n @@ -0,0 +1,30 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: eof.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH eof n 7.5 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +eof \- Check for end of file condition on channel +.SH SYNOPSIS +\fBeof \fIchannelId\fR +.BE + +.SH DESCRIPTION +.PP +Returns 1 if an end of file condition occurred during the most +recent input operation on \fIchannelId\fR (such as \fBgets\fR), +0 otherwise. + +.SH "SEE ALSO" +file(n), open(n), close(n), fblocked(n) + +.SH KEYWORDS +channel, end of file diff --git a/mk4/modtcl/tcl8.3.4/doc/error.n b/mk4/modtcl/tcl8.3.4/doc/error.n new file mode 100644 index 0000000..bb7c91f --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/error.n @@ -0,0 +1,61 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: error.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH error n "" Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +error \- Generate an error +.SH SYNOPSIS +\fBerror \fImessage\fR ?\fIinfo\fR? ?\fIcode\fR? +.BE + +.SH DESCRIPTION +.PP +Returns a TCL_ERROR code, which causes command interpretation to be +unwound. \fIMessage\fR is a string that is returned to the application +to indicate what went wrong. +.PP +If the \fIinfo\fR argument is provided and is non-empty, +it is used to initialize the global variable \fBerrorInfo\fR. +\fBerrorInfo\fR is used to accumulate a stack trace of what +was in progress when an error occurred; as nested commands unwind, +the Tcl interpreter adds information to \fBerrorInfo\fR. If the +\fIinfo\fR argument is present, it is used to initialize +\fBerrorInfo\fR and the first increment of unwind information +will not be added by the Tcl interpreter. In other +words, the command containing the \fBerror\fR command will not appear +in \fBerrorInfo\fR; in its place will be \fIinfo\fR. +This feature is most useful in conjunction with the \fBcatch\fR command: +if a caught error cannot be handled successfully, \fIinfo\fR can be used +to return a stack trace reflecting the original point of occurrence +of the error: +.CS +\fBcatch {...} errMsg +set savedInfo $errorInfo +\&... +error $errMsg $savedInfo\fR +.CE +.PP +If the \fIcode\fR argument is present, then its value is stored +in the \fBerrorCode\fR global variable. This variable is intended +to hold a machine-readable description of the error in cases where +such information is available; see the \fBtclvars\fR manual +page for information on the proper format for the variable. +If the \fIcode\fR argument is not +present, then \fBerrorCode\fR is automatically reset to +``NONE'' by the Tcl interpreter as part of processing the +error generated by the command. + +.SH "SEE ALSO" +catch(n), tclvars(n) + +.SH KEYWORDS +error, errorCode, errorInfo diff --git a/mk4/modtcl/tcl8.3.4/doc/eval.n b/mk4/modtcl/tcl8.3.4/doc/eval.n new file mode 100644 index 0000000..608c539 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/eval.n @@ -0,0 +1,33 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: eval.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH eval n "" Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +eval \- Evaluate a Tcl script +.SH SYNOPSIS +\fBeval \fIarg \fR?\fIarg ...\fR? +.BE + +.SH DESCRIPTION +.PP +\fBEval\fR takes one or more arguments, which together comprise a Tcl +script containing one or more commands. +\fBEval\fR concatenates all its arguments in the same +fashion as the \fBconcat\fR command, passes the concatenated string to the +Tcl interpreter recursively, and returns the result of that +evaluation (or any error generated by it). + +.SH KEYWORDS +concatenate, evaluate, script + +.SH "SEE ALSO" +catch(n), concat(n), error(n), subs(n), tclvars(n) diff --git a/mk4/modtcl/tcl8.3.4/doc/exec.n b/mk4/modtcl/tcl8.3.4/doc/exec.n new file mode 100644 index 0000000..0e977bd --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/exec.n @@ -0,0 +1,307 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: exec.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH exec n 7.6 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +exec \- Invoke subprocess(es) +.SH SYNOPSIS +\fBexec \fR?\fIswitches\fR? \fIarg \fR?\fIarg ...\fR? +.BE + +.SH DESCRIPTION +.PP +This command treats its arguments as the specification +of one or more subprocesses to execute. +The arguments take the form of a standard shell pipeline +where each \fIarg\fR becomes one word of a command, and +each distinct command becomes a subprocess. +.PP +If the initial arguments to \fBexec\fR start with \fB\-\fR then +they are treated as command-line switches and are not part +of the pipeline specification. The following switches are +currently supported: +.TP 13 +\fB\-keepnewline\fR +Retains a trailing newline in the pipeline's output. +Normally a trailing newline will be deleted. +.TP 13 +\fB\-\|\-\fR +Marks the end of switches. The argument following this one will +be treated as the first \fIarg\fR even if it starts with a \fB\-\fR. +.PP +If an \fIarg\fR (or pair of \fIarg\fR's) has one of the forms +described below then it is used by \fBexec\fR to control the +flow of input and output among the subprocess(es). +Such arguments will not be passed to the subprocess(es). In forms +such as ``< \fIfileName\fR'' \fIfileName\fR may either be in a +separate argument from ``<'' or in the same argument with no +intervening space (i.e. ``<\fIfileName\fR''). +.TP 15 +| +Separates distinct commands in the pipeline. The standard output +of the preceding command will be piped into the standard input +of the next command. +.TP 15 +|& +Separates distinct commands in the pipeline. Both standard output +and standard error of the preceding command will be piped into +the standard input of the next command. +This form of redirection overrides forms such as 2> and >&. +.TP 15 +<\0\fIfileName\fR +The file named by \fIfileName\fR is opened and used as the standard +input for the first command in the pipeline. +.TP 15 +<@\0\fIfileId\fR +\fIFileId\fR must be the identifier for an open file, such as the return +value from a previous call to \fBopen\fR. +It is used as the standard input for the first command in the pipeline. +\fIFileId\fR must have been opened for reading. +.TP 15 +<<\0\fIvalue\fR +\fIValue\fR is passed to the first command as its standard input. +.TP 15 +>\0\fIfileName\fR +Standard output from the last command is redirected to the file named +\fIfileName\fR, overwriting its previous contents. +.TP 15 +2>\0\fIfileName\fR +Standard error from all commands in the pipeline is redirected to the +file named \fIfileName\fR, overwriting its previous contents. +.TP 15 +>&\0\fIfileName\fR +Both standard output from the last command and standard error from all +commands are redirected to the file named \fIfileName\fR, overwriting +its previous contents. +.TP 15 +>>\0\fIfileName\fR +Standard output from the last command is +redirected to the file named \fIfileName\fR, appending to it rather +than overwriting it. +.TP 15 +2>>\0\fIfileName\fR +Standard error from all commands in the pipeline is +redirected to the file named \fIfileName\fR, appending to it rather +than overwriting it. +.TP 15 +>>&\0\fIfileName\fR +Both standard output from the last command and standard error from +all commands are redirected to the file named \fIfileName\fR, +appending to it rather than overwriting it. +.TP 15 +>@\0\fIfileId\fR +\fIFileId\fR must be the identifier for an open file, such as the return +value from a previous call to \fBopen\fR. +Standard output from the last command is redirected to \fIfileId\fR's +file, which must have been opened for writing. +.TP 15 +2>@\0\fIfileId\fR +\fIFileId\fR must be the identifier for an open file, such as the return +value from a previous call to \fBopen\fR. +Standard error from all commands in the pipeline is +redirected to \fIfileId\fR's file. +The file must have been opened for writing. +.TP 15 +>&@\0\fIfileId\fR +\fIFileId\fR must be the identifier for an open file, such as the return +value from a previous call to \fBopen\fR. +Both standard output from the last command and standard error from +all commands are redirected to \fIfileId\fR's file. +The file must have been opened for writing. +.PP +If standard output has not been redirected then the \fBexec\fR +command returns the standard output from the last command +in the pipeline. +If any of the commands in the pipeline exit abnormally or +are killed or suspended, then \fBexec\fR will return an error +and the error message will include the pipeline's output followed by +error messages describing the abnormal terminations; the +\fBerrorCode\fR variable will contain additional information +about the last abnormal termination encountered. +If any of the commands writes to its standard error file and that +standard error isn't redirected, +then \fBexec\fR will return an error; the error message +will include the pipeline's standard output, followed by messages +about abnormal terminations (if any), followed by the standard error +output. +.PP +If the last character of the result or error message +is a newline then that character is normally deleted +from the result or error message. +This is consistent with other Tcl return values, which don't +normally end with newlines. +However, if \fB\-keepnewline\fR is specified then the trailing +newline is retained. +.PP +If standard input isn't redirected with ``<'' or ``<<'' +or ``<@'' then the standard input for the first command in the +pipeline is taken from the application's current standard input. +.PP +If the last \fIarg\fR is ``&'' then the pipeline will be +executed in background. +In this case the \fBexec\fR command will return a list whose +elements are the process identifiers for all of the subprocesses +in the pipeline. +The standard output from the last command in the pipeline will +go to the application's standard output if it hasn't been +redirected, and error output from all of +the commands in the pipeline will go to the application's +standard error file unless redirected. +.PP +The first word in each command is taken as the command name; +tilde-substitution is performed on it, and if the result contains +no slashes then the directories +in the PATH environment variable are searched for +an executable by the given name. +If the name contains a slash then it must refer to an executable +reachable from the current directory. +No ``glob'' expansion or other shell-like substitutions +are performed on the arguments to commands. + +.VS +.SH "PORTABILITY ISSUES" +.TP +\fBWindows\fR (all versions) +. +Reading from or writing to a socket, using the ``\fB@\0\fIfileId\fR'' +notation, does not work. When reading from a socket, a 16-bit DOS +application will hang and a 32-bit application will return immediately with +end-of-file. When either type of application writes to a socket, the +information is instead sent to the console, if one is present, or is +discarded. +.sp +The Tk console text widget does not provide real standard IO capabilities. +Under Tk, when redirecting from standard input, all applications will see an +immediate end-of-file; information redirected to standard output or standard +error will be discarded. +.sp +Either forward or backward slashes are accepted as path separators for +arguments to Tcl commands. When executing an application, the path name +specified for the application may also contain forward or backward slashes +as path separators. Bear in mind, however, that most Windows applications +accept arguments with forward slashes only as option delimiters and +backslashes only in paths. Any arguments to an application that specify a +path name with forward slashes will not automatically be converted to use +the backslash character. If an argument contains forward slashes as the +path separator, it may or may not be recognized as a path name, depending on +the program. +.sp +Additionally, when calling a 16-bit DOS or Windows 3.X application, all path +names must use the short, cryptic, path format (e.g., using ``applba~1.def'' +instead of ``applbakery.default''). +.sp +Two or more forward or backward slashes in a row in a path refer to a +network path. For example, a simple concatenation of the root directory +\fBc:/\fR with a subdirectory \fB/windows/system\fR will yield +\fBc://windows/system\fR (two slashes together), which refers to the mount +point called \fBsystem\fR on the machine called \fBwindows\fR (and the +\fBc:/\fR is ignored), and is not equivalent to \fBc:/windows/system\fR, +which describes a directory on the current computer. The \fBfile join\fR +command should be used to concatenate path components. +.TP +\fBWindows NT\fR +. +When attempting to execute an application, \fBexec\fR first searches for the +name as it was specified. Then, in order, \fB.com\fR, \fB.exe\fR, and \fB.bat\fR +are appended to the end of the specified name and it searches for +the longer name. If a directory name was not specified as part of the +application name, the following directories are automatically searched in +order when attempting to locate the application: +.sp +.RS +.RS +The directory from which the Tcl executable was loaded. +.br +The current directory. +.br +The Windows NT 32-bit system directory. +.br +The Windows NT 16-bit system directory. +.br +The Windows NT home directory. +.br +The directories listed in the path. +.RE +.sp +In order to execute the shell builtin commands like \fBdir\fR and \fBcopy\fR, +the caller must prepend ``\fBcmd.exe /c\0\fR'' to the desired command. +.sp +.RE +.TP +\fBWindows 95\fR +. +When attempting to execute an application, \fBexec\fR first searches for the +name as it was specified. Then, in order, \fB.com\fR, \fB.exe\fR, and \fB.bat\fR +are appended to the end of the specified name and it searches for +the longer name. If a directory name was not specified as part of the +application name, the following directories are automatically searched in +order when attempting to locate the application: +.sp +.RS +.RS +The directory from which the Tcl executable was loaded. +.br +The current directory. +.br +The Windows 95 system directory. +.br +The Windows 95 home directory. +.br +The directories listed in the path. +.RE +.sp +In order to execute the shell builtin commands like \fBdir\fR and \fBcopy\fR, +the caller must prepend ``\fBcommand.com /c\0\fR'' to the desired command. +.sp +Once a 16-bit DOS application has read standard input from a console and +then quit, all subsequently run 16-bit DOS applications will see the +standard input as already closed. 32-bit applications do not have this +problem and will run correctly, even after a 16-bit DOS application thinks +that standard input is closed. There is no known workaround for this bug +at this time. +.sp +Redirection between the \fBNUL:\fR device and a 16-bit application does not +always work. When redirecting from \fBNUL:\fR, some applications may hang, +others will get an infinite stream of ``0x01'' bytes, and some will actually +correctly get an immediate end-of-file; the behavior seems to depend upon +something compiled into the application itself. When redirecting greater than +4K or so to \fBNUL:\fR, some applications will hang. The above problems do not +happen with 32-bit applications. +.sp +All DOS 16-bit applications are run synchronously. All standard input from +a pipe to a 16-bit DOS application is collected into a temporary file; the +other end of the pipe must be closed before the 16-bit DOS application +begins executing. All standard output or error from a 16-bit DOS +application to a pipe is collected into temporary files; the application +must terminate before the temporary files are redirected to the next stage +of the pipeline. This is due to a workaround for a Windows 95 bug in the +implementation of pipes, and is how the standard Windows 95 DOS shell +handles pipes itself. +.sp +Certain applications, such as \fBcommand.com\fR, should not be executed +interactively. Applications which directly access the console window, +rather than reading from their standard input and writing to their standard +output may fail, hang Tcl, or even hang the system if their own private +console window is not available to them. +.RE +.TP +\fBMacintosh\fR +The \fBexec\fR command is not implemented and does not exist under Macintosh. +.TP +\fBUnix\fR\0\0\0\0\0\0\0 +The \fBexec\fR command is fully functional and works as described. + +.SH "SEE ALSO" +error(n), open(n) + +.SH KEYWORDS +execute, pipeline, redirection, subprocess diff --git a/mk4/modtcl/tcl8.3.4/doc/exit.n b/mk4/modtcl/tcl8.3.4/doc/exit.n new file mode 100644 index 0000000..d06c575 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/exit.n @@ -0,0 +1,31 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: exit.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH exit n "" Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +exit \- End the application +.SH SYNOPSIS +\fBexit \fR?\fIreturnCode\fR? +.BE + +.SH DESCRIPTION +.PP +Terminate the process, returning \fIreturnCode\fR to the +system as the exit status. +If \fIreturnCode\fR isn't specified then it defaults +to 0. + +.SH "SEE ALSO" +exec(n), tclvars(n) + +.SH KEYWORDS +exit, process diff --git a/mk4/modtcl/tcl8.3.4/doc/expr.n b/mk4/modtcl/tcl8.3.4/doc/expr.n new file mode 100644 index 0000000..84016a7 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/expr.n @@ -0,0 +1,387 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-2000 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: expr.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH expr n 8.3 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +expr \- Evaluate an expression +.SH SYNOPSIS +\fBexpr \fIarg \fR?\fIarg arg ...\fR? +.BE + +.SH DESCRIPTION +.PP +Concatenates \fIarg\fR's (adding separator spaces between them), +evaluates the result as a Tcl expression, and returns the value. +The operators permitted in Tcl expressions are a subset of +the operators permitted in C expressions, and they have the +same meaning and precedence as the corresponding C operators. +Expressions almost always yield numeric results +(integer or floating-point values). +For example, the expression +.CS +\fBexpr 8.2 + 6\fR +.CE +evaluates to 14.2. +Tcl expressions differ from C expressions in the way that +operands are specified. Also, Tcl expressions support +non-numeric operands and string comparisons. +.SH OPERANDS +.PP +A Tcl expression consists of a combination of operands, operators, +and parentheses. +White space may be used between the operands and operators and +parentheses; it is ignored by the expression's instructions. +Where possible, operands are interpreted as integer values. +Integer values may be specified in decimal (the normal case), in octal (if the +first character of the operand is \fB0\fR), or in hexadecimal (if the first +two characters of the operand are \fB0x\fR). +If an operand does not have one of the integer formats given +above, then it is treated as a floating-point number if that is +possible. Floating-point numbers may be specified in any of the +ways accepted by an ANSI-compliant C compiler (except that the +\fBf\fR, \fBF\fR, \fBl\fR, and \fBL\fR suffixes will not be permitted in +most installations). For example, all of the +following are valid floating-point numbers: 2.1, 3., 6e4, 7.91e+16. +If no numeric interpretation is possible, then an operand is left +as a string (and only a limited set of operators may be applied to +it). +.PP +Operands may be specified in any of the following ways: +.IP [1] +As an numeric value, either integer or floating-point. +.IP [2] +As a Tcl variable, using standard \fB$\fR notation. +The variable's value will be used as the operand. +.IP [3] +As a string enclosed in double-quotes. +The expression parser will perform backslash, variable, and +command substitutions on the information between the quotes, +and use the resulting value as the operand +.IP [4] +As a string enclosed in braces. +The characters between the open brace and matching close brace +will be used as the operand without any substitutions. +.IP [5] +As a Tcl command enclosed in brackets. +The command will be executed and its result will be used as +the operand. +.IP [6] +As a mathematical function whose arguments have any of the above +forms for operands, such as \fBsin($x)\fR. See below for a list of defined +functions. +.LP +Where substitutions occur above (e.g. inside quoted strings), they +are performed by the expression's instructions. +However, an additional layer of substitution may already have +been performed by the command parser before the expression +processor was called. +As discussed below, it is usually best to enclose expressions +in braces to prevent the command parser from performing substitutions +on the contents. +.PP +For some examples of simple expressions, suppose the variable +\fBa\fR has the value 3 and +the variable \fBb\fR has the value 6. +Then the command on the left side of each of the lines below +will produce the value on the right side of the line: +.CS +.ta 6c +\fBexpr 3.1 + $a 6.1 +expr 2 + "$a.$b" 5.6 +expr 4*[llength "6 2"] 8 +expr {{word one} < "word $a"} 0\fR +.CE +.SH OPERATORS +.PP +The valid operators are listed below, grouped in decreasing order +of precedence: +.TP 20 +\fB\-\0\0+\0\0~\0\0!\fR +Unary minus, unary plus, bit-wise NOT, logical NOT. None of these operands +may be applied to string operands, and bit-wise NOT may be +applied only to integers. +.TP 20 +\fB*\0\0/\0\0%\fR +Multiply, divide, remainder. None of these operands may be +applied to string operands, and remainder may be applied only +to integers. +The remainder will always have the same sign as the divisor and +an absolute value smaller than the divisor. +.TP 20 +\fB+\0\0\-\fR +Add and subtract. Valid for any numeric operands. +.TP 20 +\fB<<\0\0>>\fR +Left and right shift. Valid for integer operands only. +A right shift always propagates the sign bit. +.TP 20 +\fB<\0\0>\0\0<=\0\0>=\fR +Boolean less, greater, less than or equal, and greater than or equal. +Each operator produces 1 if the condition is true, 0 otherwise. +These operators may be applied to strings as well as numeric operands, +in which case string comparison is used. +.TP 20 +\fB==\0\0!=\fR +Boolean equal and not equal. Each operator produces a zero/one result. +Valid for all operand types. +.TP 20 +\fB&\fR +Bit-wise AND. Valid for integer operands only. +.TP 20 +\fB^\fR +Bit-wise exclusive OR. Valid for integer operands only. +.TP 20 +\fB|\fR +Bit-wise OR. Valid for integer operands only. +.TP 20 +\fB&&\fR +Logical AND. Produces a 1 result if both operands are non-zero, +0 otherwise. +Valid for boolean and numeric (integers or floating-point) operands only. +.TP 20 +\fB||\fR +Logical OR. Produces a 0 result if both operands are zero, 1 otherwise. +Valid for boolean and numeric (integers or floating-point) operands only. +.TP 20 +\fIx\fB?\fIy\fB:\fIz\fR +If-then-else, as in C. If \fIx\fR +evaluates to non-zero, then the result is the value of \fIy\fR. +Otherwise the result is the value of \fIz\fR. +The \fIx\fR operand must have a numeric value. +.LP +See the C manual for more details on the results +produced by each operator. +All of the binary operators group left-to-right within the same +precedence level. For example, the command +.CS +\fBexpr 4*2 < 7\fR +.CE +returns 0. +.PP +The \fB&&\fR, \fB||\fR, and \fB?:\fR operators have ``lazy +evaluation'', just as in C, +which means that operands are not evaluated if they are +not needed to determine the outcome. For example, in the command +.CS +\fBexpr {$v ? [a] : [b]}\fR +.CE +only one of \fB[a]\fR or \fB[b]\fR will actually be evaluated, +depending on the value of \fB$v\fR. Note, however, that this is +only true if the entire expression is enclosed in braces; otherwise +the Tcl parser will evaluate both \fB[a]\fR and \fB[b]\fR before +invoking the \fBexpr\fR command. +.SH "MATH FUNCTIONS" +.PP +Tcl supports the following mathematical functions in expressions: +.DS +.ta 3c 6c 9c +\fBabs\fR \fBcosh\fR \fBlog\fR \fBsqrt\fR +\fBacos\fR \fBdouble\fR \fBlog10\fR \fBsrand\fR +\fBasin\fR \fBexp\fR \fBpow\fR \fBtan\fR +\fBatan\fR \fBfloor\fR \fBrand\fR \fBtanh\fR +\fBatan2\fR \fBfmod\fR \fBround\fR +\fBceil\fR \fBhypot\fR \fBsin\fR +\fBcos\fR \fBint\fR \fBsinh\fR +.DE +.PP +.TP +\fBabs(\fIarg\fB)\fR +Returns the absolute value of \fIarg\fR. \fIArg\fR may be either +integer or floating-point, and the result is returned in the same form. +.TP +\fBacos(\fIarg\fB)\fR +Returns the arc cosine of \fIarg\fR, in the range [0,pi] +radians. \fIArg\fR should be in the range [-1,1]. +.TP +\fBasin(\fIarg\fB)\fR +Returns the arc sine of \fIarg\fR, in the range [-pi/2,pi/2] radians. +\fIArg\fR should be in the range [-1,1]. +.TP +\fBatan(\fIarg\fB)\fR +Returns the arc tangent of \fIarg\fR, in the range [-pi/2,pi/2] radians. +.TP +\fBatan2(\fIx, y\fB)\fR +Returns the arc tangent of \fIy\fR/\fIx\fR, in the range [-pi,pi] +radians. \fIx\fR and \fIy\fR cannot both be 0. +.TP +\fBceil(\fIarg\fB)\fR +Returns the smallest integer value not less than \fIarg\fR. +.TP +\fBcos(\fIarg\fB)\fR +Returns the cosine of \fIarg\fR, measured in radians. +.TP +\fBcosh(\fIarg\fB)\fR +Returns the hyperbolic cosine of \fIarg\fR. If the result would cause +an overflow, an error is returned. +.TP +\fBdouble(\fIarg\fB)\fR +If \fIarg\fR is a floating value, returns \fIarg\fR, otherwise converts +\fIarg\fR to floating and returns the converted value. +.TP +\fBexp(\fIarg\fB)\fR +Returns the exponential of \fIarg\fR, defined as e**\fIarg\fR. If the +result would cause an overflow, an error is returned. +.TP +\fBfloor(\fIarg\fB)\fR +Returns the largest integral value not greater than \fIarg\fR. +.TP +\fBfmod(\fIx, y\fB)\fR +Returns the floating-point remainder of the division of \fIx\fR by +\fIy\fR. If \fIy\fR is 0, an error is returned. +.TP +\fBhypot(\fIx, y\fB)\fR +Computes the length of the hypotenuse of a right-angled triangle +(\fIx\fR*\fIx\fR+\fIy\fR*\fIy\fR). +.TP +\fBint(\fIarg\fB)\fR +If \fIarg\fR is an integer value, returns \fIarg\fR, otherwise converts +\fIarg\fR to integer by truncation and returns the converted value. +.TP +\fBlog(\fIarg\fB)\fR +Returns the natural logarithm of \fIarg\fR. \fIArg\fR must be a +positive value. +.TP +\fBlog10(\fIarg\fB)\fR +Returns the base 10 logarithm of \fIarg\fR. \fIArg\fR must be a +positive value. +.TP +\fBpow(\fIx, y\fB)\fR +Computes the value of \fIx\fR raised to the power \fIy\fR. If \fIx\fR +is negative, \fIy\fR must be an integer value. +.TP +\fBrand()\fR +Returns a floating point number from zero to just less than one or, +in mathematical terms, the range [0,1). The seed comes from the +internal clock of the machine or may be set manual with the srand +function. +.TP +\fBround(\fIarg\fB)\fR +If \fIarg\fR is an integer value, returns \fIarg\fR, otherwise converts +\fIarg\fR to integer by rounding and returns the converted value. +.TP +\fBsin(\fIarg\fB)\fR +Returns the sine of \fIarg\fR, measured in radians. +.TP +\fBsinh(\fIarg\fB)\fR +Returns the hyperbolic sine of \fIarg\fR. If the result would cause +an overflow, an error is returned. +.TP +\fBsqrt(\fIarg\fB)\fR +Returns the square root of \fIarg\fR. \fIArg\fR must be non-negative. +.TP +\fBsrand(\fIarg\fB)\fR +The \fIarg\fR, which must be an integer, is used to reset the seed for +the random number generator. Returns the first random number from +that seed. Each interpreter has it's own seed. +.TP +\fBtan(\fIarg\fB)\fR +Returns the tangent of \fIarg\fR, measured in radians. +.TP +\fBtanh(\fIarg\fB)\fR +Returns the hyperbolic tangent of \fIarg\fR. +.PP +In addition to these predefined functions, applications may +define additional functions using \fBTcl_CreateMathFunc\fR(). +.SH "TYPES, OVERFLOW, AND PRECISION" +.PP +All internal computations involving integers are done with the C type +\fIlong\fR, and all internal computations involving floating-point are +done with the C type \fIdouble\fR. +When converting a string to floating-point, exponent overflow is +detected and results in a Tcl error. +For conversion to integer from string, detection of overflow depends +on the behavior of some routines in the local C library, so it should +be regarded as unreliable. +In any case, integer overflow and underflow are generally not detected +reliably for intermediate results. Floating-point overflow and underflow +are detected to the degree supported by the hardware, which is generally +pretty reliable. +.PP +Conversion among internal representations for integer, floating-point, +and string operands is done automatically as needed. +For arithmetic computations, integers are used until some +floating-point number is introduced, after which floating-point is used. +For example, +.CS +\fBexpr 5 / 4\fR +.CE +returns 1, while +.CS +\fBexpr 5 / 4.0\fR +\fBexpr 5 / ( [string length "abcd"] + 0.0 )\fR +.CE +both return 1.25. +Floating-point values are always returned with a ``\fB.\fR'' +or an \fBe\fR so that they will not look like integer values. For +example, +.CS +\fBexpr 20.0/5.0\fR +.CE +returns \fB4.0\fR, not \fB4\fR. + +.SH "STRING OPERATIONS" +.PP +String values may be used as operands of the comparison operators, +although the expression evaluator tries to do comparisons as integer +or floating-point when it can. +If one of the operands of a comparison is a string and the other +has a numeric value, the numeric operand is converted back to +a string using the C \fIsprintf\fR format specifier +\fB%d\fR for integers and \fB%g\fR for floating-point values. +For example, the commands +.CS +\fBexpr {"0x03" > "2"}\fR +\fBexpr {"0y" < "0x12"}\fR +.CE +both return 1. The first comparison is done using integer +comparison, and the second is done using string comparison after +the second operand is converted to the string \fB18\fR. +Because of Tcl's tendency to treat values as numbers whenever +possible, it isn't generally a good idea to use operators like \fB==\fR +when you really want string comparison and the values of the +operands could be arbitrary; it's better in these cases to use +the \fBstring\fR command instead. + +.SH "PERFORMANCE CONSIDERATIONS" +.PP +Enclose expressions in braces for the best speed and the smallest +storage requirements. +This allows the Tcl bytecode compiler to generate the best code. +.PP +As mentioned above, expressions are substituted twice: +once by the Tcl parser and once by the \fBexpr\fR command. +For example, the commands +.CS +\fBset a 3\fR +\fBset b {$a + 2}\fR +\fBexpr $b*4\fR +.CE +return 11, not a multiple of 4. +This is because the Tcl parser will first substitute \fB$a + 2\fR for +the variable \fBb\fR, +then the \fBexpr\fR command will evaluate the expression \fB$a + 2*4\fR. +.PP +Most expressions do not require a second round of substitutions. +Either they are enclosed in braces or, if not, +their variable and command substitutions yield numbers or strings +that don't themselves require substitutions. +However, because a few unbraced expressions +need two rounds of substitutions, +the bytecode compiler must emit +additional instructions to handle this situation. +The most expensive code is required for +unbraced expressions that contain command substitutions. +These expressions must be implemented by generating new code +each time the expression is executed. + +.SH KEYWORDS +arithmetic, boolean, compare, expression, fuzzy comparison diff --git a/mk4/modtcl/tcl8.3.4/doc/fblocked.n b/mk4/modtcl/tcl8.3.4/doc/fblocked.n new file mode 100644 index 0000000..79ffca9 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/fblocked.n @@ -0,0 +1,33 @@ +'\" +'\" Copyright (c) 1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: fblocked.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +.so man.macros +.TH fblocked n 7.5 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +fblocked \- Test whether the last input operation exhausted all available input +.SH SYNOPSIS +\fBfblocked \fIchannelId\fR +.BE + +.SH DESCRIPTION +.PP +The \fBfblocked\fR command returns 1 if the most recent input operation +on \fIchannelId\fR returned less information than requested because all +available input was exhausted. +For example, if \fBgets\fR is invoked when there are only three +characters available for input and no end-of-line sequence, \fBgets\fR +returns an empty string and a subsequent call to \fBfblocked\fR will +return 1. +.PP + +.SH "SEE ALSO" +gets(n), open(n), read(n) + +.SH KEYWORDS +blocking, nonblocking diff --git a/mk4/modtcl/tcl8.3.4/doc/fconfigure.n b/mk4/modtcl/tcl8.3.4/doc/fconfigure.n new file mode 100644 index 0000000..05a4759 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/fconfigure.n @@ -0,0 +1,201 @@ +'\" +'\" Copyright (c) 1995-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: fconfigure.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH fconfigure n 8.1 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +fconfigure \- Set and get options on a channel +.SH SYNOPSIS +.nf +\fBfconfigure \fIchannelId\fR +\fBfconfigure \fIchannelId\fR \fIname\fR +\fBfconfigure \fIchannelId\fR \fIname value \fR?\fIname value ...\fR? +.fi +.BE + +.SH DESCRIPTION +.PP +The \fBfconfigure\fR command sets and retrieves options for channels. +\fIChannelId\fR identifies the channel for which to set or query an option. +If no \fIname\fR or \fIvalue\fR arguments are supplied, the command +returns a list containing alternating option names and values for the channel. +If \fIname\fR is supplied but no \fIvalue\fR then the command returns +the current value of the given option. +If one or more pairs of \fIname\fR and \fIvalue\fR are supplied, the +command sets each of the named options to the corresponding \fIvalue\fR; +in this case the return value is an empty string. +.PP +The options described below are supported for all channels. In addition, +each channel type may add options that only it supports. See the manual +entry for the command that creates each type of channels for the options +that that specific type of channel supports. For example, see the manual +entry for the \fBsocket\fR command for its additional options. +.TP +\fB\-blocking\fR \fIboolean\fR +The \fB\-blocking\fR option determines whether I/O operations on the +channel can cause the process to block indefinitely. +The value of the option must be a proper boolean value. +Channels are normally in blocking mode; if a channel is placed into +nonblocking mode it will affect the operation of the \fBgets\fR, +\fBread\fR, \fBputs\fR, \fBflush\fR, and \fBclose\fR commands; +see the documentation for those commands for details. +For nonblocking mode to work correctly, the application must be +using the Tcl event loop (e.g. by calling \fBTcl_DoOneEvent\fR or +invoking the \fBvwait\fR command). +.TP +\fB\-buffering\fR \fInewValue\fR +. +If \fInewValue\fR is \fBfull\fR then the I/O system will buffer output +until its internal buffer is full or until the \fBflush\fR command is +invoked. If \fInewValue\fR is \fBline\fR, then the I/O system will +automatically flush output for the channel whenever a newline character +is output. If \fInewValue\fR is \fBnone\fR, the I/O system will flush +automatically after every output operation. The default is for +\fB\-buffering\fR to be set to \fBfull\fR except for channels that +connect to terminal-like devices; for these channels the initial setting +is \fBline\fR. Additionally, \fBstdin\fR and \fBstdout\fR are +intially set to \fBline\fR, and \fBstderr\fR is set to \fBnone\fR. +.TP +\fB\-buffersize\fR \fInewSize\fR +. +\fINewvalue\fR must be an integer; its value is used to set the size of +buffers, in bytes, subsequently allocated for this channel to store input +or output. \fINewvalue\fR must be between ten and one million, allowing +buffers of ten to one million bytes in size. +.VS 8.1 br +.TP +\fB\-encoding\fR \fIname\fR +. +This option is used to specify the encoding of the channel, so that the data +can be converted to and from Unicode for use in Tcl. For instance, in +order for Tcl to read characters from a Japanese file in \fBshiftjis\fR +and properly process and display the contents, the encoding would be set +to \fBshiftjis\fR. Thereafter, when reading from the channel, the bytes in +the Japanese file would be converted to Unicode as they are read. +Writing is also supported \- as Tcl strings are written to the channel they +will automatically be converted to the specified encoding on output. +.RS +.PP +If a file contains pure binary data (for instance, a JPEG image), the +encoding for the channel should be configured to be \fBbinary\fR. Tcl +will then assign no interpretation to the data in the file and simply read or +write raw bytes. The Tcl \fBbinary\fR command can be used to manipulate this +byte-oriented data. +.PP +The default encoding for newly opened channels is the same platform- and +locale-dependent system encoding used for interfacing with the operating +system. +.RE +.VE +.TP +\fB\-eofchar\fR \fIchar\fR +.TP +\fB\-eofchar\fR \fB{\fIinChar outChar\fB}\fR +. +This option supports DOS file systems that use Control-z (\ex1a) as an +end of file marker. If \fIchar\fR is not an empty string, then this +character signals end-of-file when it is encountered during input. For +output, the end-of-file character is output when the channel is closed. +If \fIchar\fR is the empty string, then there is no special end of file +character marker. For read-write channels, a two-element list specifies +the end of file marker for input and output, respectively. As a +convenience, when setting the end-of-file character for a read-write +channel you can specify a single value that will apply to both reading +and writing. When querying the end-of-file character of a read-write +channel, a two-element list will always be returned. The default value +for \fB\-eofchar\fR is the empty string in all cases except for files +under Windows. In that case the \fB\-eofchar\fR is Control-z (\ex1a) for +reading and the empty string for writing. +.TP +\fB\-translation\fR \fImode\fR +.TP +\fB\-translation\fR \fB{\fIinMode outMode\fB}\fR +. +In Tcl scripts the end of a line is always represented using a single +newline character (\en). However, in actual files and devices the end of +a line may be represented differently on different platforms, or even for +different devices on the same platform. For example, under UNIX newlines +are used in files, whereas carriage-return-linefeed sequences are +normally used in network connections. On input (i.e., with \fBgets\fP +and \fBread\fP) the Tcl I/O system automatically translates the external +end-of-line representation into newline characters. Upon output (i.e., +with \fBputs\fP), the I/O system translates newlines to the external +end-of-line representation. The default translation mode, \fBauto\fP, +handles all the common cases automatically, but the \fB\-translation\fR +option provides explicit control over the end of line translations. +.RS +.PP +The value associated with \fB\-translation\fR is a single item for +read-only and write-only channels. The value is a two-element list for +read-write channels; the read translation mode is the first element of +the list, and the write translation mode is the second element. As a +convenience, when setting the translation mode for a read-write channel +you can specify a single value that will apply to both reading and +writing. When querying the translation mode of a read-write channel, a +two-element list will always be returned. The following values are +currently supported: +.TP +\fBauto\fR +. +As the input translation mode, \fBauto\fR treats any of newline +(\fBlf\fP), carriage return (\fBcr\fP), or carriage return followed by a +newline (\fBcrlf\fP) as the end of line representation. The end of line +representation can even change from line-to-line, and all cases are +translated to a newline. As the output translation mode, \fBauto\fR +chooses a platform specific representation; for sockets on all platforms +Tcl chooses \fBcrlf\fR, for all Unix flavors, it chooses \fBlf\fR, for the +Macintosh platform it chooses \fBcr\fR and for the various flavors of +Windows it chooses \fBcrlf\fR. The default setting for +\fB\-translation\fR is \fBauto\fR for both input and output. +.VS 8.1 br +.TP +\fBbinary\fR +. +No end-of-line translations are performed. This is nearly identical to +\fBlf\fP mode, except that in addition \fBbinary\fP mode also sets the +end-of-file character to the empty string (which disables it) and sets the +encoding to \fBbinary\fR (which disables encoding filtering). See the +description of \fB\-eofchar\fR and \fB\-encoding\fR for more information. +.VE +.TP +\fBcr\fR +. +The end of a line in the underlying file or device is represented by a +single carriage return character. As the input translation mode, +\fBcr\fP mode converts carriage returns to newline characters. As the +output translation mode, \fBcr\fP mode translates newline characters to +carriage returns. This mode is typically used on Macintosh platforms. +.TP +\fBcrlf\fR +. +The end of a line in the underlying file or device is represented by a +carriage return character followed by a linefeed character. As the input +translation mode, \fBcrlf\fP mode converts carriage-return-linefeed +sequences to newline characters. As the output translation mode, +\fBcrlf\fP mode translates newline characters to carriage-return-linefeed +sequences. This mode is typically used on Windows platforms and for +network connections. +.TP +\fBlf\fR +. +The end of a line in the underlying file or device is represented by a +single newline (linefeed) character. In this mode no translations occur +during either input or output. This mode is typically used on UNIX +platforms. +.RE +.PP + +.SH "SEE ALSO" +close(n), flush(n), gets(n), puts(n), read(n), socket(n) + +.SH KEYWORDS +blocking, buffering, carriage return, end of line, flushing, linemode, +newline, nonblocking, platform, translation, encoding, filter, byte array, +binary diff --git a/mk4/modtcl/tcl8.3.4/doc/fcopy.n b/mk4/modtcl/tcl8.3.4/doc/fcopy.n new file mode 100644 index 0000000..733b90d --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/fcopy.n @@ -0,0 +1,127 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1997 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: fcopy.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH fcopy n 8.0 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +fcopy \- Copy data from one channel to another. +.SH SYNOPSIS +\fBfcopy \fIinchan\fR \fIoutchan\fR ?\fB\-size \fIsize\fR? ?\fB\-command \fIcallback\fR? +.BE + +.SH DESCRIPTION +.PP +The \fBfcopy\fP command copies data from one I/O channel, \fIinchan\fR to another I/O channel, \fIoutchan\fR. +The \fBfcopy\fP command leverages the buffering in the Tcl I/O system to +avoid extra copies and to avoid buffering too much data in +main memory when copying large files to slow destinations like +network sockets. +.PP +The \fBfcopy\fP +command transfers data from \fIinchan\fR until end of file +or \fIsize\fP bytes have been +transferred. If no \fB\-size\fP argument is given, +then the copy goes until end of file. +All the data read from \fIinchan\fR is copied to \fIoutchan\fR. +Without the \fB\-command\fP option, \fBfcopy\fP blocks until the copy is complete +and returns the number of bytes written to \fIoutchan\fR. +.PP +The \fB\-command\fP argument makes \fBfcopy\fP work in the background. +In this case it returns immediately and the \fIcallback\fP is invoked +later when the copy completes. +The \fIcallback\fP is called with +one or two additional +arguments that indicates how many bytes were written to \fIoutchan\fR. +If an error occurred during the background copy, the second argument is the +error string associated with the error. +With a background copy, +it is not necessary to put \fIinchan\fR or \fIoutchan\fR into +non-blocking mode; the \fBfcopy\fP command takes care of that automatically. +However, it is necessary to enter the event loop by using +the \fBvwait\fP command or by using Tk. +.PP +You are not allowed to do other I/O operations with +\fIinchan\fR or \fIoutchan\fR during a background fcopy. +If either \fIinchan\fR or \fIoutchan\fR get closed +while the copy is in progress, the current copy is stopped +and the command callback is \fInot\fP made. +If \fIinchan\fR is closed, +then all data already queued for \fIoutchan\fR is written out. +.PP +Note that \fIinchan\fR can become readable during a background copy. +You should turn off any \fBfileevent\fP handlers during a background +copy so those handlers do not interfere with the copy. +Any I/O attempted by a \fBfileevent\fP handler will get a "channel busy" error. +.PP +\fBFcopy\fR translates end-of-line sequences in \fIinchan\fR and \fIoutchan\fR +according to the \fB\-translation\fR option +for these channels. +See the manual entry for \fBfconfigure\fR for details on the +\fB\-translation\fR option. +The translations mean that the number of bytes read from \fIinchan\fR +can be different than the number of bytes written to \fIoutchan\fR. +Only the number of bytes written to \fIoutchan\fR is reported, +either as the return value of a synchronous \fBfcopy\fP or +as the argument to the callback for an asynchronous \fBfcopy\fP. + +.SH EXAMPLE +.PP +This first example shows how the callback gets +passed the number of bytes transferred. +It also uses vwait to put the application into the event loop. +Of course, this simplified example could be done without the command +callback. +.DS +proc Cleanup {in out bytes {error {}}} { + global total + set total $bytes + close $in + close $out + if {[string length $error] != 0} { + # error occurred during the copy + } +} +set in [open $file1] +set out [socket $server $port] +fcopy $in $out -command [list Cleanup $in $out] +vwait total + +.DE +.PP +The second example copies in chunks and tests for end of file +in the command callback +.DS +proc CopyMore {in out chunk bytes {error {}}} { + global total done + incr total $bytes + if {([string length $error] != 0) || [eof $in] { + set done $total + close $in + close $out + } else { + fcopy $in $out -command [list CopyMore $in $out $chunk] \\ + -size $chunk + } +} +set in [open $file1] +set out [socket $server $port] +set chunk 1024 +set total 0 +fcopy $in $out -command [list CopyMore $in $out $chunk] -size $chunk +vwait done + +.DE + +.SH "SEE ALSO" +eof(n), fblocked(n), fconfigure(n) + +.SH KEYWORDS +blocking, channel, end of line, end of file, nonblocking, read, translation diff --git a/mk4/modtcl/tcl8.3.4/doc/file.n b/mk4/modtcl/tcl8.3.4/doc/file.n new file mode 100644 index 0000000..354b284 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/file.n @@ -0,0 +1,344 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: file.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH file n 8.3 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +file \- Manipulate file names and attributes +.SH SYNOPSIS +\fBfile \fIoption\fR \fIname\fR ?\fIarg arg ...\fR? +.BE + +.SH DESCRIPTION +.PP +This command provides several operations on a file's name or attributes. +\fIName\fR is the name of a file; if it starts with a tilde, then tilde +substitution is done before executing the command (see the manual entry for +\fBfilename\fR for details). \fIOption\fR indicates what to do with the +file name. Any unique abbreviation for \fIoption\fR is acceptable. The +valid options are: +.TP +\fBfile atime \fIname\fR ?\fBtime\fR? +. +Returns a decimal string giving the time at which file \fIname\fR was last +accessed. If \fItime\fR is specified, it is an access time to set +for the file. The time is measured in the standard POSIX fashion as +seconds from a fixed starting time (often January 1, 1970). If the file +doesn't exist or its access time cannot be queried or set then an error is +generated. On Windows, FAT file systems do not support access time. +.TP +\fBfile attributes \fIname\fR +.br +\fBfile attributes \fIname\fR ?\fBoption\fR? +.br +\fBfile attributes \fIname\fR ?\fBoption value option value...\fR? +.RS +This subcommand returns or sets platform specific values associated +with a file. The first form returns a list of the platform specific +flags and their values. The second form returns the value for the +specific option. The third form sets one or more of the values. The +values are as follows: +.PP +On Unix, \fB-group\fR gets or sets the group name for the file. A group id +can be given to the command, but it returns a group name. \fB-owner\fR gets +or sets the user name of the owner of the file. The command returns the +owner name, but the numerical id can be passed when setting the +owner. \fB-permissions\fR sets or retrieves the octal code that chmod(1) +uses. This command does also has limited support for setting using the +symbolic attributes for chmod(1), of the form [ugo]?[[+\-=][rwxst],[...]], +where multiple symbolic attributes can be separated by commas (example: +\fBu+s,go\-rw\fR add sticky bit for user, remove read and write +permissions for group and other). A simplified \fBls\fR style string, +of the form rwxrwxrwx (must be 9 characters), is also supported +(example: \fBrwxr\-xr\-t\fR is equivalent to 01755). +.PP +On Windows, \fB-archive\fR gives the value or sets or clears the +archive attribute of the file. \fB-hidden\fR gives the value or sets +or clears the hidden attribute of the file. \fB-longname\fR will +expand each path element to its long version. This attribute cannot be +set. \fB-readonly\fR gives the value or sets or clears the readonly +attribute of the file. \fB-shortname\fR gives a string where every +path element is replaced with its short (8.3) version of the +name. This attribute cannot be set. \fB-system\fR gives or sets or +clears the value of the system attribute of the file. +.PP +On Macintosh, \fB-creator\fR gives or sets the Finder creator type of +the file. \fB-hidden\fR gives or sets or clears the hidden attribute +of the file. \fB-readonly\fR gives or sets or clears the readonly +attribute of the file. Note that directories can only be locked if +File Sharing is turned on. \fB-type\fR gives or sets the Finder file +type for the file. +.RE +.VS +.TP +\fBfile channels ?\fIpattern\fR? +. +If \fIpattern\fR isn't specified, returns a list of names of all +registered open channels in this interpreter. If \fIpattern\fR is +specified, only those names matching \fIpattern\fR are returned. Matching +is determined using the same rules as for \fBstring match\fR. +.VE +.TP +\fBfile copy \fR?\fB\-force\fR? ?\fB\-\|\-\fR? \fIsource\fR \fItarget\fR +.br +\fBfile copy \fR?\fB\-force\fR? ?\fB\-\|\-\fR? \fIsource\fR ?\fIsource\fR ...? \fItargetDir\fR +.RS +The first form makes a copy of the file or directory \fIsource\fR under +the pathname \fItarget\fR. If \fItarget\fR is an existing directory, +then the second form is used. The second form makes a copy inside +\fItargetDir\fR of each \fIsource\fR file listed. If a directory is +specified as a \fIsource\fR, then the contents of the directory will be +recursively copied into \fItargetDir\fR. Existing files will not be +overwritten unless the \fB\-force\fR option is specified. Trying to +overwrite a non-empty directory, overwrite a directory with a file, or a +file with a directory will all result in errors even if \fI\-force\fR was +specified. Arguments are processed in the order specified, halting at the +first error, if any. A \fB\-\|\-\fR marks the end of switches; the argument +following the \fB\-\|\-\fR will be treated as a \fIsource\fR even if it +starts with a \fB\-\fR. +.RE +.TP +\fBfile delete \fR?\fB\-force\fR? ?\fB\-\|\-\fR? \fIpathname\fR ?\fIpathname\fR ... ? +. +Removes the file or directory specified by each \fIpathname\fR argument. +Non-empty directories will be removed only if the \fB\-force\fR option is +specified. Trying to delete a non-existant file is not considered an +error. Trying to delete a read-only file will cause the file to be deleted, +even if the \fB\-force\fR flags is not specified. Arguments are processed +in the order specified, halting at the first error, if any. A \fB\-\|\-\fR +marks the end of switches; the argument following the \fB\-\|\-\fR will be +treated as a \fIpathname\fR even if it starts with a \fB\-\fR. +.TP +\fBfile dirname \fIname\fR +Returns a name comprised of all of the path components in \fIname\fR +excluding the last element. If \fIname\fR is a relative file name and +only contains one path element, then returns ``\fB.\fR'' (or ``\fB:\fR'' +on the Macintosh). If \fIname\fR refers to a root directory, then the +root directory is returned. For example, +.RS +.CS +\fBfile dirname c:/\fR +.CE +returns \fBc:/\fR. +.PP +Note that tilde substitution will only be +performed if it is necessary to complete the command. For example, +.CS +\fBfile dirname ~/src/foo.c\fR +.CE +returns \fB~/src\fR, whereas +.CS +\fBfile dirname ~\fR +.CE +returns \fB/home\fR (or something similar). +.RE +.TP +\fBfile executable \fIname\fR +. +Returns \fB1\fR if file \fIname\fR is executable by the current user, +\fB0\fR otherwise. +.TP +\fBfile exists \fIname\fR +. +Returns \fB1\fR if file \fIname\fR exists and the current user has +search privileges for the directories leading to it, \fB0\fR otherwise. +.TP +\fBfile extension \fIname\fR +. +Returns all of the characters in \fIname\fR after and including the last +dot in the last element of \fIname\fR. If there is no dot in the last +element of \fIname\fR then returns the empty string. +.TP +\fBfile isdirectory \fIname\fR +. +Returns \fB1\fR if file \fIname\fR is a directory, \fB0\fR otherwise. +.TP +\fBfile isfile \fIname\fR +. +Returns \fB1\fR if file \fIname\fR is a regular file, \fB0\fR otherwise. +.TP +\fBfile join \fIname\fR ?\fIname ...\fR? +. +Takes one or more file names and combines them, using the correct path +separator for the current platform. If a particular \fIname\fR is +relative, then it will be joined to the previous file name argument. +Otherwise, any earlier arguments will be discarded, and joining will +proceed from the current argument. For example, +.RS +.CS +\fBfile join a b /foo bar\fR +.CE +returns \fB/foo/bar\fR. +.PP +Note that any of the names can contain separators, and that the result +is always canonical for the current platform: \fB/\fR for Unix and +Windows, and \fB:\fR for Macintosh. +.RE +.TP +\fBfile lstat \fIname varName\fR +. +Same as \fBstat\fR option (see below) except uses the \fIlstat\fR +kernel call instead of \fIstat\fR. This means that if \fIname\fR +refers to a symbolic link the information returned in \fIvarName\fR +is for the link rather than the file it refers to. On systems that +don't support symbolic links this option behaves exactly the same +as the \fBstat\fR option. +.TP +\fBfile mkdir \fIdir\fR ?\fIdir\fR ...? +. +Creates each directory specified. For each pathname \fIdir\fR specified, +this command will create all non-existing parent directories as +well as \fIdir\fR itself. If an existing directory is specified, then +no action is taken and no error is returned. Trying to overwrite an existing +file with a directory will result in an error. Arguments are processed in +the order specified, halting at the first error, if any. +.TP +\fBfile mtime \fIname\fR ?\fItime\fR? +. +Returns a decimal string giving the time at which file \fIname\fR was last +modified. If \fItime\fR is specified, it is a modification time to set for +the file (equivalent to Unix \fBtouch\fR). The time is measured in the +standard POSIX fashion as seconds from a fixed starting time (often January +1, 1970). If the file doesn't exist or its modified time cannot be queried +or set then an error is generated. +.TP +\fBfile nativename \fIname\fR +. +Returns the platform-specific name of the file. This is useful if the +filename is needed to pass to a platform-specific call, such as exec +under Windows or AppleScript on the Macintosh. +.TP +\fBfile owned \fIname\fR +. +Returns \fB1\fR if file \fIname\fR is owned by the current user, \fB0\fR +otherwise. +.TP +\fBfile pathtype \fIname\fR +. +Returns one of \fBabsolute\fR, \fBrelative\fR, \fBvolumerelative\fR. If +\fIname\fR refers to a specific file on a specific volume, the path type +will be \fBabsolute\fR. If \fIname\fR refers to a file relative to the +current working directory, then the path type will be \fBrelative\fR. If +\fIname\fR refers to a file relative to the current working directory on +a specified volume, or to a specific file on the current working volume, then +the file type is \fBvolumerelative\fR. +.TP +\fBfile readable \fIname\fR +. +Returns \fB1\fR if file \fIname\fR is readable by the current user, +\fB0\fR otherwise. +.TP +\fBfile readlink \fIname\fR +. +Returns the value of the symbolic link given by \fIname\fR (i.e. the name +of the file it points to). If \fIname\fR isn't a symbolic link or its +value cannot be read, then an error is returned. On systems that don't +support symbolic links this option is undefined. +.PP +\fBfile rename \fR?\fB\-force\fR? ?\fB\-\|\-\fR? \fIsource\fR \fItarget\fR +.br +\fBfile rename \fR?\fB\-force\fR? ?\fB\-\|\-\fR? \fIsource\fR ?\fIsource\fR ...? \fItargetDir\fR +.RS +The first form takes the file or directory specified by pathname +\fIsource\fR and renames it to \fItarget\fR, moving the file if the +pathname \fItarget\fR specifies a name in a different directory. If +\fItarget\fR is an existing directory, then the second form is used. The +second form moves each \fIsource\fR file or directory into the directory +\fItargetDir\fR. Existing files will not be overwritten unless the +\fB\-force\fR option is specified. Trying to overwrite a non-empty +directory, overwrite a directory with a file, or a file with a directory +will all result in errors. Arguments are processed in the order specified, +halting at the first error, if any. A \fB\-\|\-\fR marks the end of +switches; the argument following the \fB\-\|\-\fR will be treated as a +\fIsource\fR even if it starts with a \fB\-\fR. +.RE +.TP +\fBfile rootname \fIname\fR +. +Returns all of the characters in \fIname\fR up to but not including the +last ``.'' character in the last component of name. If the last +component of \fIname\fR doesn't contain a dot, then returns \fIname\fR. +.TP +\fBfile size \fIname\fR +. +Returns a decimal string giving the size of file \fIname\fR in bytes. If +the file doesn't exist or its size cannot be queried then an error is +generated. +.TP +\fBfile split \fIname\fR +. +Returns a list whose elements are the path components in \fIname\fR. The +first element of the list will have the same path type as \fIname\fR. +All other elements will be relative. Path separators will be discarded +unless they are needed ensure that an element is unambiguously relative. +For example, under Unix +.RS +.CS +\fBfile split /foo/~bar/baz\fR +.CE +returns \fB/\0\0foo\0\0./~bar\0\0baz\fR to ensure that later commands +that use the third component do not attempt to perform tilde +substitution. +.RE +.TP +\fBfile stat \fIname varName\fR +. +Invokes the \fBstat\fR kernel call on \fIname\fR, and uses the variable +given by \fIvarName\fR to hold information returned from the kernel call. +\fIVarName\fR is treated as an array variable, and the following elements +of that variable are set: \fBatime\fR, \fBctime\fR, \fBdev\fR, \fBgid\fR, +\fBino\fR, \fBmode\fR, \fBmtime\fR, \fBnlink\fR, \fBsize\fR, \fBtype\fR, +\fBuid\fR. Each element except \fBtype\fR is a decimal string with the +value of the corresponding field from the \fBstat\fR return structure; +see the manual entry for \fBstat\fR for details on the meanings of the +values. The \fBtype\fR element gives the type of the file in the same +form returned by the command \fBfile type\fR. This command returns an +empty string. +.TP +\fBfile tail \fIname\fR +. +Returns all of the characters in \fIname\fR after the last directory +separator. If \fIname\fR contains no separators then returns +\fIname\fR. +.TP +\fBfile type \fIname\fR +. +Returns a string giving the type of file \fIname\fR, which will be one of +\fBfile\fR, \fBdirectory\fR, \fBcharacterSpecial\fR, \fBblockSpecial\fR, +\fBfifo\fR, \fBlink\fR, or \fBsocket\fR. +.TP +\fBfile volume\fR +. +Returns the absolute paths to the volumes mounted on the system, as a +proper Tcl list. On the Macintosh, this will be a list of the mounted +drives, both local and network. N.B. if two drives have the same name, +they will both appear on the volume list, but there is currently no way, +from Tcl, to access any but the first of these drives. On UNIX, the +command will always return "/", since all filesystems are locally mounted. +On Windows, it will return a list of the available local drives +(e.g. {a:/ c:/}). +.TP +\fBfile writable \fIname\fR +. +Returns \fB1\fR if file \fIname\fR is writable by the current user, +\fB0\fR otherwise. +.SH "PORTABILITY ISSUES" +.TP +\fBUnix\fR\0\0\0\0\0\0\0 +. +These commands always operate using the real user and group identifiers, +not the effective ones. + +.SH "SEE ALSO" +filename + +.SH KEYWORDS +attributes, copy files, delete files, directory, file, move files, name, rename files, stat diff --git a/mk4/modtcl/tcl8.3.4/doc/fileevent.n b/mk4/modtcl/tcl8.3.4/doc/fileevent.n new file mode 100644 index 0000000..de58188 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/fileevent.n @@ -0,0 +1,109 @@ +'\" +'\" Copyright (c) 1994 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: fileevent.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH fileevent n 7.5 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +fileevent \- Execute a script when a channel becomes readable or writable +.SH SYNOPSIS +\fBfileevent \fIchannelId \fBreadable \fR?\fIscript\fR? +.sp +\fBfileevent \fIchannelId \fBwritable \fR?\fIscript\fR? +.BE + +.SH DESCRIPTION +.PP +This command is used to create \fIfile event handlers\fR. A file event +handler is a binding between a channel and a script, such that the script +is evaluated whenever the channel becomes readable or writable. File event +handlers are most commonly used to allow data to be received from another +process on an event-driven basis, so that the receiver can continue to +interact with the user while waiting for the data to arrive. If an +application invokes \fBgets\fR or \fBread\fR on a blocking channel when +there is no input data available, the process will block; until the input +data arrives, it will not be able to service other events, so it will +appear to the user to ``freeze up''. With \fBfileevent\fR, the process can +tell when data is present and only invoke \fBgets\fR or \fBread\fR when +they won't block. +.PP +The \fIchannelId\fR argument to \fBfileevent\fR refers to an open channel, +such as the return value from a previous \fBopen\fR or \fBsocket\fR +command. +If the \fIscript\fR argument is specified, then \fBfileevent\fR +creates a new event handler: \fIscript\fR will be evaluated +whenever the channel becomes readable or writable (depending on the +second argument to \fBfileevent\fR). +In this case \fBfileevent\fR returns an empty string. +The \fBreadable\fR and \fBwritable\fR event handlers for a file +are independent, and may be created and deleted separately. +However, there may be at most one \fBreadable\fR and one \fBwritable\fR +handler for a file at a given time in a given interpreter. +If \fBfileevent\fR is called when the specified handler already +exists in the invoking interpreter, the new script replaces the old one. +.PP +If the \fIscript\fR argument is not specified, \fBfileevent\fR +returns the current script for \fIchannelId\fR, or an empty string +if there is none. +If the \fIscript\fR argument is specified as an empty string +then the event handler is deleted, so that no script will be invoked. +A file event handler is also deleted automatically whenever +its channel is closed or its interpreter is deleted. +.PP +A channel is considered to be readable if there is unread data +available on the underlying device. +A channel is also considered to be readable if there is unread +data in an input buffer, except in the special case where the +most recent attempt to read from the channel was a \fBgets\fR +call that could not find a complete line in the input buffer. +This feature allows a file to be read a line at a time in nonblocking mode +using events. +A channel is also considered to be readable if an end of file or +error condition is present on the underlying file or device. +It is important for \fIscript\fR to check for these conditions +and handle them appropriately; for example, if there is no special +check for end of file, an infinite loop may occur where \fIscript\fR +reads no data, returns, and is immediately invoked again. +.PP +A channel is considered to be writable if at least one byte of data +can be written to the underlying file or device without blocking, +or if an error condition is present on the underlying file or device. +.PP +Event-driven I/O works best for channels that have been +placed into nonblocking mode with the \fBfconfigure\fR command. +In blocking mode, a \fBputs\fR command may block if you give it +more data than the underlying file or device can accept, and a +\fBgets\fR or \fBread\fR command will block if you attempt to read +more data than is ready; no events will be processed while the +commands block. +In nonblocking mode \fBputs\fR, \fBread\fR, and \fBgets\fR never block. +See the documentation for the individual commands for information +on how they handle blocking and nonblocking channels. +.PP +The script for a file event is executed at global level (outside the +context of any Tcl procedure) in the interpreter in which the +\fBfileevent\fR command was invoked. +If an error occurs while executing the script then the +\fBbgerror\fR mechanism is used to report the error. +In addition, the file event handler is deleted if it ever returns +an error; this is done in order to prevent infinite loops due to +buggy handlers. + +.SH CREDITS +.PP +\fBfileevent\fR is based on the \fBaddinput\fR command created +by Mark Diekhans. + +.SH "SEE ALSO" +bgerror(n), fconfigure(n), gets(n), puts(n), read(n) + +.SH KEYWORDS +asynchronous I/O, blocking, channel, event handler, nonblocking, readable, +script, writable. diff --git a/mk4/modtcl/tcl8.3.4/doc/filename.n b/mk4/modtcl/tcl8.3.4/doc/filename.n new file mode 100644 index 0000000..33fb52b --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/filename.n @@ -0,0 +1,200 @@ +'\" +'\" Copyright (c) 1995-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: filename.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH filename n 7.5 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +filename \- File name conventions supported by Tcl commands +.BE +.SH INTRODUCTION +.PP +All Tcl commands and C procedures that take file names as arguments +expect the file names to be in one of three forms, depending on the +current platform. On each platform, Tcl supports file names in the +standard forms(s) for that platform. In addition, on all platforms, +Tcl supports a Unix-like syntax intended to provide a convenient way +of constructing simple file names. However, scripts that are intended +to be portable should not assume a particular form for file names. +Instead, portable scripts must use the \fBfile split\fR and \fBfile +join\fR commands to manipulate file names (see the \fBfile\fR manual +entry for more details). + +.SH "PATH TYPES" +.PP +File names are grouped into three general types based on the starting point +for the path used to specify the file: absolute, relative, and +volume-relative. Absolute names are completely qualified, giving a path to +the file relative to a particular volume and the root directory on that +volume. Relative names are unqualified, giving a path to the file relative +to the current working directory. Volume-relative names are partially +qualified, either giving the path relative to the root directory on the +current volume, or relative to the current directory of the specified +volume. The \fBfile pathtype\fR command can be used to determine the +type of a given path. + +.SH "PATH SYNTAX" +.PP +The rules for native names depend on the value reported in the Tcl +array element \fBtcl_platform(platform)\fR: +.TP 10 +\fBmac\fR +On Apple Macintosh systems, Tcl supports two forms of path names. The +normal Mac style names use colons as path separators. Paths may be +relative or absolute, and file names may contain any character other +than colon. A leading colon causes the rest of the path to be +interpreted relative to the current directory. If a path contains a +colon that is not at the beginning, then the path is interpreted as an +absolute path. Sequences of two or more colons anywhere in the path +are used to construct relative paths where \fB::\fR refers to the +parent of the current directory, \fB:::\fR refers to the parent of the +parent, and so forth. +.RS +.PP +In addition to Macintosh style names, Tcl also supports a subset of +Unix-like names. If a path contains no colons, then it is interpreted +like a Unix path. Slash is used as the path separator. The file name +\fB\&.\fR refers to the current directory, and \fB\&..\fR refers to the +parent of the current directory. However, some names like \fB/\fR or +\fB/..\fR have no mapping, and are interpreted as Macintosh names. In +general, commands that generate file names will return Macintosh style +names, but commands that accept file names will take both Macintosh +and Unix-style names. +.PP +The following examples illustrate various forms of path names: +.TP 15 +\fB:\fR +Relative path to the current folder. +.TP 15 +\fBMyFile\fR +Relative path to a file named \fBMyFile\fR in the current folder. +.TP 15 +\fBMyDisk:MyFile\fR +Absolute path to a file named \fBMyFile\fR on the device named \fBMyDisk\fR. +.TP 15 +\fB:MyDir:MyFile\fR +Relative path to a file name \fBMyFile\fR in a folder named +\fBMyDir\fR in the current folder. +.TP 15 +\fB::MyFile\fR +Relative path to a file named \fBMyFile\fR in the folder above the +current folder. +.TP 15 +\fB:::MyFile\fR +Relative path to a file named \fBMyFile\fR in the folder two levels above the +current folder. +.TP 15 +\fB/MyDisk/MyFile\fR +Absolute path to a file named \fBMyFile\fR on the device named +\fBMyDisk\fR. +.TP 15 +\fB\&../MyFile\fR +Relative path to a file named \fBMyFile\fR in the folder above the +current folder. +.RE +.TP +\fBunix\fR +On Unix platforms, Tcl uses path names where the components are +separated by slashes. Path names may be relative or absolute, and +file names may contain any character other than slash. The file names +\fB\&.\fR and \fB\&..\fR are special and refer to the current directory +and the parent of the current directory respectively. Multiple +adjacent slash characters are interpreted as a single separator. +The following examples illustrate various forms of path names: +.RS +.TP 15 +\fB/\fR +Absolute path to the root directory. +.TP 15 +\fB/etc/passwd\fR +Absolute path to the file named \fBpasswd\fR in the directory +\fBetc\fR in the root directory. +.TP 15 +\fB\&.\fR +Relative path to the current directory. +.TP 15 +\fBfoo\fR +Relative path to the file \fBfoo\fR in the current directory. +.TP 15 +\fBfoo/bar\fR +Relative path to the file \fBbar\fR in the directory \fBfoo\fR in the +current directory. +.TP 15 +\fB\&../foo\fR +Relative path to the file \fBfoo\fR in the directory above the current +directory. +.RE +.TP +\fBwindows\fR +On Microsoft Windows platforms, Tcl supports both drive-relative and UNC +style names. Both \fB/\fR and \fB\e\fR may be used as directory separators +in either type of name. Drive-relative names consist of an optional drive +specifier followed by an absolute or relative path. UNC paths follow the +general form \fB\e\eservername\esharename\epath\efile\fR. In both forms, +the file names \fB.\fR and \fB..\fR are special and refer to the current +directory and the parent of the current directory respectively. The +following examples illustrate various forms of path names: +.RS +.TP 15 +\fB\&\e\eHost\eshare/file\fR +Absolute UNC path to a file called \fBfile\fR in the root directory of +the export point \fBshare\fR on the host \fBHost\fR. +.TP 15 +\fBc:foo\fR +Volume-relative path to a file \fBfoo\fR in the current directory on drive +\fBc\fR. +.TP 15 +\fBc:/foo\fR +Absolute path to a file \fBfoo\fR in the root directory of drive +\fBc\fR. +.TP 15 +\fBfoo\ebar\fR +Relative path to a file \fBbar\fR in the \fBfoo\fR directory in the current +directory on the current volume. +.TP 15 +\fB\&\efoo\fR +Volume-relative path to a file \fBfoo\fR in the root directory of the current +volume. +.RE + +.SH "TILDE SUBSTITUTION" +.PP +In addition to the file name rules described above, Tcl also supports +\fIcsh\fR-style tilde substitution. If a file name starts with a +tilde, then the file name will be interpreted as if the first element +is replaced with the location of the home directory for the given +user. If the tilde is followed immediately by a separator, then the +\fB$HOME\fR environment variable is substituted. Otherwise the +characters between the tilde and the next separator are taken as a +user name, which is used to retrieve the user's home directory for +substitution. +.PP +The Macintosh and Windows platforms do not support tilde substitution +when a user name follows the tilde. On these platforms, attempts to +use a tilde followed by a user name will generate an error. File +names that have a tilde without a user name will be substituted using +the \fB$HOME\fR environment variable, just like for Unix. + +.SH "PORTABILITY ISSUES" +.PP +Not all file systems are case sensitive, so scripts should avoid code +that depends on the case of characters in a file name. In addition, +the character sets allowed on different devices may differ, so scripts +should choose file names that do not contain special characters like: +\fB<>:"/\e|\fR. The safest approach is to use names consisting of +alphanumeric characters only. Also Windows 3.1 only supports file +names with a root of no more than 8 characters and an extension of no +more than 3 characters. + +.SH KEYWORDS +current directory, absolute file name, relative file name, +volume-relative file name, portability + +.SH "SEE ALSO" +file(n), glob(n) diff --git a/mk4/modtcl/tcl8.3.4/doc/flush.n b/mk4/modtcl/tcl8.3.4/doc/flush.n new file mode 100644 index 0000000..2a2f193 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/flush.n @@ -0,0 +1,35 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: flush.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH flush n 7.5 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +flush \- Flush buffered output for a channel +.SH SYNOPSIS +\fBflush \fIchannelId\fR +.BE + +.SH DESCRIPTION +.PP +Flushes any output that has been buffered for \fIchannelId\fR. +\fIChannelId\fR must be a channel identifier such as returned by a previous +\fBopen\fR or \fBsocket\fR command, and it must have been opened for writing. +If the channel is in blocking mode the command does not return until all the +buffered output has been flushed to the channel. If the channel is in +nonblocking mode, the command may return before all buffered output has been +flushed; the remainder will be flushed in the background as fast as the +underlying file or device is able to absorb it. + +.SH "SEE ALSO" +file(n), open(n), socket(n) + +.SH KEYWORDS +blocking, buffer, channel, flush, nonblocking, output diff --git a/mk4/modtcl/tcl8.3.4/doc/for.n b/mk4/modtcl/tcl8.3.4/doc/for.n new file mode 100644 index 0000000..ace84d9 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/for.n @@ -0,0 +1,63 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1997 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: for.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH for n "" Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +for \- ``For'' loop +.SH SYNOPSIS +\fBfor \fIstart test next body\fR +.BE + +.SH DESCRIPTION +.PP +\fBFor\fR is a looping command, similar in structure to the C +\fBfor\fR statement. The \fIstart\fR, \fInext\fR, and +\fIbody\fR arguments must be Tcl command strings, and \fItest\fR +is an expression string. +The \fBfor\fR command first invokes the Tcl interpreter to +execute \fIstart\fR. Then it repeatedly evaluates \fItest\fR as +an expression; if the result is non-zero it invokes the Tcl +interpreter on \fIbody\fR, then invokes the Tcl interpreter on \fInext\fR, +then repeats the loop. The command terminates when \fItest\fR evaluates +to 0. If a \fBcontinue\fR command is invoked within \fIbody\fR then +any remaining commands in the current execution of \fIbody\fR are skipped; +processing continues by invoking the Tcl interpreter on \fInext\fR, then +evaluating \fItest\fR, and so on. If a \fBbreak\fR command is invoked +within \fIbody\fR +or \fInext\fR, +then the \fBfor\fR command will +return immediately. +The operation of \fBbreak\fR and \fBcontinue\fR are similar to the +corresponding statements in C. +\fBFor\fR returns an empty string. +.PP +Note: \fItest\fR should almost always be enclosed in braces. If not, +variable substitutions will be made before the \fBfor\fR +command starts executing, which means that variable changes +made by the loop body will not be considered in the expression. +This is likely to result in an infinite loop. If \fItest\fR is +enclosed in braces, variable substitutions are delayed until the +expression is evaluated (before +each loop iteration), so changes in the variables will be visible. +For an example, try the following script with and without the braces +around \fB$x<10\fR: +.CS +for {set x 0} {$x<10} {incr x} { + puts "x is $x" +} +.CE + +.SH "SEE ALSO" +break, continue, foreach, while + +.SH KEYWORDS +for, iteration, looping diff --git a/mk4/modtcl/tcl8.3.4/doc/foreach.n b/mk4/modtcl/tcl8.3.4/doc/foreach.n new file mode 100644 index 0000000..919fc70 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/foreach.n @@ -0,0 +1,90 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: foreach.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH foreach n "" Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +foreach \- Iterate over all elements in one or more lists +.SH SYNOPSIS +\fBforeach \fIvarname list body\fR +.br +\fBforeach \fIvarlist1 list1\fR ?\fIvarlist2 list2 ...\fR? \fIbody\fR +.BE + +.SH DESCRIPTION +.PP +The \fBforeach\fR command implements a loop where the loop +variable(s) take on values from one or more lists. +In the simplest case there is one loop variable, \fIvarname\fR, +and one list, \fIlist\fR, that is a list of values to assign to \fIvarname\fR. +The \fIbody\fR argument is a Tcl script. +For each element of \fIlist\fR (in order +from first to last), \fBforeach\fR assigns the contents of the +element to \fIvarname\fR as if the \fBlindex\fR command had been used +to extract the element, then calls the Tcl interpreter to execute +\fIbody\fR. +.PP +In the general case there can be more than one value list +(e.g., \fIlist1\fR and \fIlist2\fR), +and each value list can be associated with a list of loop variables +(e.g., \fIvarlist1\fR and \fIvarlist2\fR). +During each iteration of the loop +the variables of each \fIvarlist\fP are assigned +consecutive values from the corresponding \fIlist\fP. +Values in each \fIlist\fP are used in order from first to last, +and each value is used exactly once. +The total number of loop iterations is large enough to use +up all the values from all the value lists. +If a value list does not contain enough +elements for each of its loop variables in each iteration, +empty values are used for the missing elements. +.PP +The \fBbreak\fR and \fBcontinue\fR statements may be +invoked inside \fIbody\fR, with the same effect as in the \fBfor\fR +command. \fBForeach\fR returns an empty string. +.SH EXAMPLES +.PP +The following loop uses i and j as loop variables to iterate over +pairs of elements of a single list. +.DS +set x {} +foreach {i j} {a b c d e f} { + lappend x $j $i +} +# The value of x is "b a d c f e" +# There are 3 iterations of the loop. +.DE +.PP +The next loop uses i and j to iterate over two lists in parallel. +.DS +set x {} +foreach i {a b c} j {d e f g} { + lappend x $i $j +} +# The value of x is "a d b e c f {} g" +# There are 4 iterations of the loop. +.DE +.PP +The two forms are combined in the following example. +.DS +set x {} +foreach i {a b c} {j k} {d e f g} { + lappend x $i $j $k +} +# The value of x is "a d e b f g c {} {}" +# There are 3 iterations of the loop. +.DE + +.SH "SEE ALSO" +for(n), while(n), break(n), continue(n) + +.SH KEYWORDS +foreach, iteration, list, looping diff --git a/mk4/modtcl/tcl8.3.4/doc/format.n b/mk4/modtcl/tcl8.3.4/doc/format.n new file mode 100644 index 0000000..f06f9b2 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/format.n @@ -0,0 +1,217 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: format.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH format n 8.1 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +format \- Format a string in the style of sprintf +.SH SYNOPSIS +\fBformat \fIformatString \fR?\fIarg arg ...\fR? +.BE + +.SH INTRODUCTION +.PP +This command generates a formatted string in the same way as the +ANSI C \fBsprintf\fR procedure (it uses \fBsprintf\fR in its +implementation). +\fIFormatString\fR indicates how to format the result, using +\fB%\fR conversion specifiers as in \fBsprintf\fR, and the additional +arguments, if any, provide values to be substituted into the result. +The return value from \fBformat\fR is the formatted string. + +.SH "DETAILS ON FORMATTING" +.PP +The command operates by scanning \fIformatString\fR from left to right. +Each character from the format string is appended to the result +string unless it is a percent sign. +If the character is a \fB%\fR then it is not copied to the result string. +Instead, the characters following the \fB%\fR character are treated as +a conversion specifier. +The conversion specifier controls the conversion of the next successive +\fIarg\fR to a particular format and the result is appended to +the result string in place of the conversion specifier. +If there are multiple conversion specifiers in the format string, +then each one controls the conversion of one additional \fIarg\fR. +The \fBformat\fR command must be given enough \fIarg\fRs to meet the needs +of all of the conversion specifiers in \fIformatString\fR. +.PP +Each conversion specifier may contain up to six different parts: +an XPG3 position specifier, +a set of flags, a minimum field width, a precision, a length modifier, +and a conversion character. +Any of these fields may be omitted except for the conversion character. +The fields that are present must appear in the order given above. +The paragraphs below discuss each of these fields in turn. +.PP +If the \fB%\fR is followed by a decimal number and a \fB$\fR, as in +``\fB%2$d\fR'', then the value to convert is not taken from the +next sequential argument. +Instead, it is taken from the argument indicated by the number, +where 1 corresponds to the first \fIarg\fR. +If the conversion specifier requires multiple arguments because +of \fB*\fR characters in the specifier then +successive arguments are used, starting with the argument +given by the number. +This follows the XPG3 conventions for positional specifiers. +If there are any positional specifiers in \fIformatString\fR +then all of the specifiers must be positional. +.PP +The second portion of a conversion specifier may contain any of the +following flag characters, in any order: +.TP 10 +\fB\-\fR +Specifies that the converted argument should be left-justified +in its field (numbers are normally right-justified with leading +spaces if needed). +.TP 10 +\fB+\fR +Specifies that a number should always be printed with a sign, +even if positive. +.TP 10 +\fIspace\fR +Specifies that a space should be added to the beginning of the +number if the first character isn't a sign. +.TP 10 +\fB0\fR +Specifies that the number should be padded on the left with +zeroes instead of spaces. +.TP 10 +\fB#\fR +Requests an alternate output form. For \fBo\fR and \fBO\fR +conversions it guarantees that the first digit is always \fB0\fR. +For \fBx\fR or \fBX\fR conversions, \fB0x\fR or \fB0X\fR (respectively) +will be added to the beginning of the result unless it is zero. +For all floating-point conversions (\fBe\fR, \fBE\fR, \fBf\fR, +\fBg\fR, and \fBG\fR) it guarantees that the result always +has a decimal point. +For \fBg\fR and \fBG\fR conversions it specifies that +trailing zeroes should not be removed. +.PP +The third portion of a conversion specifier is a number giving a +minimum field width for this conversion. +It is typically used to make columns line up in tabular printouts. +If the converted argument contains fewer characters than the +minimum field width then it will be padded so that it is as wide +as the minimum field width. +Padding normally occurs by adding extra spaces on the left of the +converted argument, but the \fB0\fR and \fB\-\fR flags +may be used to specify padding with zeroes on the left or with +spaces on the right, respectively. +If the minimum field width is specified as \fB*\fR rather than +a number, then the next argument to the \fBformat\fR command +determines the minimum field width; it must be a numeric string. +.PP +The fourth portion of a conversion specifier is a precision, +which consists of a period followed by a number. +The number is used in different ways for different conversions. +For \fBe\fR, \fBE\fR, and \fBf\fR conversions it specifies the number +of digits to appear to the right of the decimal point. +For \fBg\fR and \fBG\fR conversions it specifies the total number +of digits to appear, including those on both sides of the decimal +point (however, trailing zeroes after the decimal point will still +be omitted unless the \fB#\fR flag has been specified). +For integer conversions, it specifies a minimum number of digits +to print (leading zeroes will be added if necessary). +For \fBs\fR conversions it specifies the maximum number of characters to be +printed; if the string is longer than this then the trailing characters will be dropped. +If the precision is specified with \fB*\fR rather than a number +then the next argument to the \fBformat\fR command determines the precision; +it must be a numeric string. +.PP +The fifth part of a conversion specifier is a length modifier, +which must be \fBh\fR or \fBl\fR. +If it is \fBh\fR it specifies that the numeric value should be +truncated to a 16-bit value before converting. +This option is rarely useful. +The \fBl\fR modifier is ignored. +.PP +The last thing in a conversion specifier is an alphabetic character +that determines what kind of conversion to perform. +The following conversion characters are currently supported: +.TP 10 +\fBd\fR +Convert integer to signed decimal string. +.TP 10 +\fBu\fR +Convert integer to unsigned decimal string. +.TP 10 +\fBi\fR +Convert integer to signed decimal string; the integer may either be +in decimal, in octal (with a leading \fB0\fR) or in hexadecimal +(with a leading \fB0x\fR). +.TP 10 +\fBo\fR +Convert integer to unsigned octal string. +.TP 10 +\fBx\fR or \fBX\fR +Convert integer to unsigned hexadecimal string, using digits +``0123456789abcdef'' for \fBx\fR and ``0123456789ABCDEF'' for \fBX\fR). +.VS +.TP 10 +\fBc\fR +Convert integer to the Unicode character it represents. +.VE +.TP 10 +\fBs\fR +No conversion; just insert string. +.TP 10 +\fBf\fR +Convert floating-point number to signed decimal string of +the form \fIxx.yyy\fR, where the number of \fIy\fR's is determined by +the precision (default: 6). +If the precision is 0 then no decimal point is output. +.TP 10 +\fBe\fR or \fBe\fR +Convert floating-point number to scientific notation in the +form \fIx.yyy\fBe\(+-\fIzz\fR, where the number of \fIy\fR's is determined +by the precision (default: 6). +If the precision is 0 then no decimal point is output. +If the \fBE\fR form is used then \fBE\fR is +printed instead of \fBe\fR. +.TP 10 +\fBg\fR or \fBG\fR +If the exponent is less than \-4 or greater than or equal to the +precision, then convert floating-point number as for \fB%e\fR or +\fB%E\fR. +Otherwise convert as for \fB%f\fR. +Trailing zeroes and a trailing decimal point are omitted. +.TP 10 +\fB%\fR +No conversion: just insert \fB%\fR. +.LP +For the numerical conversions the argument being converted must +be an integer or floating-point string; format converts the argument +to binary and then converts it back to a string according to +the conversion specifier. + +.SH "DIFFERENCES FROM ANSI SPRINTF" +.PP +The behavior of the format command is the same as the +ANSI C \fBsprintf\fR procedure except for the following +differences: +.IP [1] +\fB%p\fR and \fB%n\fR specifiers are not currently supported. +.IP [2] +For \fB%c\fR conversions the argument must be a decimal string, +which will then be converted to the corresponding character value. +.IP [3] +The \fBl\fR modifier is ignored; integer values are always converted +as if there were no modifier present and real values are always +converted as if the \fBl\fR modifier were present (i.e. type +\fBdouble\fR is used for the internal representation). +If the \fBh\fR modifier is specified then integer values are truncated +to \fBshort\fR before conversion. + +.SH "SEE ALSO" +sprintf(3), string(n) + +.SH KEYWORDS +conversion specifier, format, sprintf, string, substitution diff --git a/mk4/modtcl/tcl8.3.4/doc/gets.n b/mk4/modtcl/tcl8.3.4/doc/gets.n new file mode 100644 index 0000000..79e1bdf --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/gets.n @@ -0,0 +1,50 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: gets.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH gets n 7.5 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +gets \- Read a line from a channel +.SH SYNOPSIS +\fBgets \fIchannelId\fR ?\fIvarName\fR? +.BE + +.SH DESCRIPTION +.PP +This command reads the next line from \fIchannelId\fR, returns everything +in the line up to (but not including) the end-of-line character(s), and +discards the end-of-line character(s). +If \fIvarName\fR is omitted the line is returned as the result of the +command. +If \fIvarName\fR is specified then the line is placed in the variable by +that name and the return value is a count of the number of characters +returned. +.PP +If end of file occurs while scanning for an end of +line, the command returns whatever input is available up to the end of file. +If \fIchannelId\fR is in nonblocking mode and there is not a full +line of input available, the command returns an empty string and +does not consume any input. +If \fIvarName\fR is specified and an empty string is returned in +\fIvarName\fR because of end-of-file or because of insufficient +data in nonblocking mode, then the return count is -1. +Note that if \fIvarName\fR is not specified then the end-of-file +and no-full-line-available cases can +produce the same results as if there were an input line consisting +only of the end-of-line character(s). +The \fBeof\fR and \fBfblocked\fR commands can be used to distinguish +these three cases. + +.SH "SEE ALSO" +file(n), eof(n), fblocked(n) + +.SH KEYWORDS +blocking, channel, end of file, end of line, line, nonblocking, read diff --git a/mk4/modtcl/tcl8.3.4/doc/glob.n b/mk4/modtcl/tcl8.3.4/doc/glob.n new file mode 100644 index 0000000..b975e4a --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/glob.n @@ -0,0 +1,161 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: glob.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH glob n 8.3 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +glob \- Return names of files that match patterns +.SH SYNOPSIS +\fBglob \fR?\fIswitches\fR? \fIpattern \fR?\fIpattern ...\fR? +.BE + +.SH DESCRIPTION +.PP +This command performs file name ``globbing'' in a fashion similar to +the csh shell. It returns a list of the files whose names match any +of the \fIpattern\fR arguments. +.LP +If the initial arguments to \fBglob\fR start with \fB\-\fR then +they are treated as switches. The following switches are +currently supported: +.VS 8.3 +.TP +\fB\-directory\fR \fIdirectory\fR +Search for files which match the given patterns starting in the given +\fIdirectory\fR. This allows searching of directories whose name +contains glob-sensitive characters without the need to quote such +characters explicitly. This option may not be used in conjunction with +\fB\-path\fR. +.TP +\fB\-join\fR +The remaining pattern arguments are treated as a single pattern +obtained by joining the arguments with directory separators. +.VE 8.3 +.TP +\fB\-nocomplain\fR +Allows an empty list to be returned without error; without this +switch an error is returned if the result list would be empty. +.VS 8.3 +.TP +\fB\-path\fR \fIpathPrefix\fR +Search for files with the given \fIpathPrefix\fR where the rest of the name +matches the given patterns. This allows searching for files with names +similar to a given file even when the names contain glob-sensitive +characters. This option may not be used in conjunction with +\fB\-directory\fR. +.TP +\fB\-types\fR \fItypeList\fR +Only list files or directories which match \fItypeList\fR, where the items +in the list have two forms. The first form is like the \-type option of +the Unix find command: +\fIb\fR (block special file), +\fIc\fR (character special file), +\fId\fR (directory), +\fIf\fR (plain file), +\fIl\fR (symbolic link), +\fIp\fR (named pipe), +or \fIs\fR (socket), where multiple types may be specified in the list. +\fBGlob\fR will return all files which match at least one of the types given. +.RS +.PP +The second form specifies types where all the types given must match. +These are \fIr\fR, \fIw\fR, \fIx\fR as file permissions, and +\fIreadonly\fR, \fIhidden\fR as special permission cases. On the +Macintosh, MacOS types and creators are also supported, where any item +which is four characters long is assumed to be a MacOS type +(e.g. \fBTEXT\fR). Items which are of the form \fI{macintosh type XXXX}\fR +or \fI{macintosh creator XXXX}\fR will match types or creators +respectively. Unrecognised types, or specifications of multiple MacOS +types/creators will signal an error. +.PP +The two forms may be mixed, so \fB\-types {d f r w}\fR will find all +regular files OR directories that have both read AND write permissions. +The following are equivalent: +.RS +.CS +\fBglob \-type d *\fR +\fBglob */\fR +.CE +.RE +except that the first case doesn't return the trailing ``/'' and +is more platform independent. +.RE +.VE 8.3 +.TP +\fB\-\|\-\fR +Marks the end of switches. The argument following this one will +be treated as a \fIpattern\fR even if it starts with a \fB\-\fR. +.PP +The \fIpattern\fR arguments may contain any of the following +special characters: +.TP 10 +\fB?\fR +Matches any single character. +.TP 10 +\fB*\fR +Matches any sequence of zero or more characters. +.TP 10 +\fB[\fIchars\fB]\fR +Matches any single character in \fIchars\fR. If \fIchars\fR +contains a sequence of the form \fIa\fB\-\fIb\fR then any +character between \fIa\fR and \fIb\fR (inclusive) will match. +.TP 10 +\fB\e\fIx\fR +Matches the character \fIx\fR. +.TP 10 +\fB{\fIa\fB,\fIb\fB,\fI...\fR} +Matches any of the strings \fIa\fR, \fIb\fR, etc. +.LP +As with csh, a ``.'' at the beginning of a file's name or just +after a ``/'' must be matched explicitly or with a {} construct. +In addition, all ``/'' characters must be matched explicitly. +.LP +If the first character in a \fIpattern\fR is ``~'' then it refers +to the home directory for the user whose name follows the ``~''. +If the ``~'' is followed immediately by ``/'' then the value of +the HOME environment variable is used. +.LP +The \fBglob\fR command differs from csh globbing in two ways. +First, it does not sort its result list (use the \fBlsort\fR +command if you want the list sorted). +Second, \fBglob\fR only returns the names of files that actually +exist; in csh no check for existence is made unless a pattern +contains a ?, *, or [] construct. + +.SH "PORTABILITY ISSUES" +.PP +Unlike other Tcl commands that will accept both network and native +style names (see the \fBfilename\fR manual entry for details on how +native and network names are specified), the \fBglob\fR command only +accepts native names. +.TP +\fBWindows\fR +. +For Windows UNC names, the servername and sharename components of the path +may not contain ?, *, or [] constructs. On Windows NT, if \fIpattern\fR is +of the form ``\fB~\fIusername\fB@\fIdomain\fR'' it refers to the home +directory of the user whose account information resides on the specified NT +domain server. Otherwise, user account information is obtained from +the local computer. On Windows 95 and 98, \fBglob\fR accepts patterns +like ``.../'' and ``..../'' for successively higher up parent directories. +.TP +\fBMacintosh\fR +. +When using the options, \fB\-dir\fR, \fB\-join\fR or \fB\-path\fR, glob +assumes the directory separator for the entire pattern is the standard +``:''. When not using these options, glob examines each pattern argument +and uses ``/'' unless the pattern contains a ``:''. + +.SH "SEE ALSO" +file(n) + +.SH KEYWORDS +exist, file, glob, pattern diff --git a/mk4/modtcl/tcl8.3.4/doc/global.n b/mk4/modtcl/tcl8.3.4/doc/global.n new file mode 100644 index 0000000..43fdddf --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/global.n @@ -0,0 +1,39 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1997 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: global.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH global n "" Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +global \- Access global variables +.SH SYNOPSIS +\fBglobal \fIvarname \fR?\fIvarname ...\fR? +.BE + +.SH DESCRIPTION +.PP +This command is ignored unless a Tcl procedure is being interpreted. +If so then it declares the given \fIvarname\fR's to be global variables +rather than local ones. +Global variables are variables in the global namespace. +For the duration of the current procedure +(and only while executing in the current procedure), +any reference to any of the \fIvarname\fRs +will refer to the global variable by the same name. +.PP +Please note that this is done by creating local variables that are +linked to the global variables, and therefore that these variables +will be listed by \fBinfo locals\fR like all other local variables. + +.SH "SEE ALSO" +namespace(n), upvar(n), variable(n) + +.SH KEYWORDS +global, namespace, procedure, variable diff --git a/mk4/modtcl/tcl8.3.4/doc/history.n b/mk4/modtcl/tcl8.3.4/doc/history.n new file mode 100644 index 0000000..58b6124 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/history.n @@ -0,0 +1,104 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1997 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: history.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH history n "" Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +history \- Manipulate the history list +.SH SYNOPSIS +\fBhistory \fR?\fIoption\fR? ?\fIarg arg ...\fR? +.BE + +.SH DESCRIPTION +.PP +The \fBhistory\fR command performs one of several operations related to +recently-executed commands recorded in a history list. Each of +these recorded commands is referred to as an ``event''. When +specifying an event to the \fBhistory\fR command, the following +forms may be used: +.IP [1] +A number: if positive, it refers to the event with +that number (all events are numbered starting at 1). If the number +is negative, it selects an event relative to the current event +(\fB\-1\fR refers to the previous event, \fB\-2\fR to the one before that, and +so on). Event \fB0\fP refers to the current event. +.IP [2] +A string: selects the most recent event that matches the string. +An event is considered to match the string either if the string is +the same as the first characters of the event, or if the string +matches the event in the sense of the \fBstring match\fR command. +.PP +The \fBhistory\fR command can take any of the following forms: +.TP +\fBhistory\fR +Same +as \fBhistory info\fR, described below. +.TP +\fBhistory add\fI command \fR?\fBexec\fR? +Adds the \fIcommand\fR argument to the history list as a new event. If +\fBexec\fR is specified (or abbreviated) then the command is also +executed and its result is returned. If \fBexec\fR isn't specified +then an empty string is returned as result. +.TP +\fBhistory change\fI newValue\fR ?\fIevent\fR? +Replaces the value recorded for an event with \fInewValue\fR. \fIEvent\fR +specifies the event to replace, and +defaults to the \fIcurrent\fR event (not event \fB\-1\fR). This command +is intended for use in commands that implement new forms of history +substitution and wish to replace the current event (which invokes the +substitution) with the command created through substitution. The return +value is an empty string. +.TP +\fBhistory clear\fR +Erase the history list. The current keep limit is retained. +The history event numbers are reset. +.TP +\fBhistory event\fR ?\fIevent\fR? +Returns the value of the event given by \fIevent\fR. \fIEvent\fR +defaults to \fB\-1\fR. +.TP +\fBhistory info \fR?\fIcount\fR? +Returns a formatted string (intended for humans to read) giving +the event number and contents for each of the events in the history +list except the current event. If \fIcount\fR is specified +then only the most recent \fIcount\fR events are returned. +.TP +\fBhistory keep \fR?\fIcount\fR? +This command may be used to change the size of the history list to +\fIcount\fR events. Initially, 20 events are retained in the history +list. If \fIcount\fR is not specified, the current keep limit is returned. +.TP +\fBhistory nextid\fR +Returns the number of the next event to be recorded +in the history list. It is useful for things like printing the +event number in command-line prompts. +.TP +\fBhistory redo \fR?\fIevent\fR? +Re-executes the command indicated by \fIevent\fR and return its result. +\fIEvent\fR defaults to \fB\-1\fR. This command results in history +revision: see below for details. +.SH "HISTORY REVISION" +.PP +Pre-8.0 Tcl had a complex history revision mechanism. +The current mechanism is more limited, and the old +history operations \fBsubstitute\fP and \fBwords\fP have been removed. +(As a consolation, the \fBclear\fP operation was added.) +.PP +The history option \fBredo\fR results in much simpler ``history revision''. +When this option is invoked then the most recent event +is modified to eliminate the history command and replace it with +the result of the history command. +If you want to redo an event without modifying history, then use +the \fBevent\fP operation to retrieve some event, +and the \fBadd\fP operation to add it to history and execute it. + +.SH KEYWORDS +event, history, record diff --git a/mk4/modtcl/tcl8.3.4/doc/http.n b/mk4/modtcl/tcl8.3.4/doc/http.n new file mode 100644 index 0000000..fb4d9b0 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/http.n @@ -0,0 +1,526 @@ +'\" +'\" Copyright (c) 1995-1997 Sun Microsystems, Inc. +'\" Copyright (c) 1998-2000 by Ajuba Solutions. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: http.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH "Http" n 8.3 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +Http \- Client-side implementation of the HTTP/1.0 protocol. +.SH SYNOPSIS +\fBpackage require http ?2.4?\fP +.sp +\fB::http::config \fI?options?\fR +.sp +\fB::http::geturl \fIurl ?options?\fR +.sp +\fB::http::formatQuery \fIlist\fR +.sp +\fB::http::reset \fItoken\fR +.sp +\fB::http::wait \fItoken\fR +.sp +\fB::http::status \fItoken\fR +.sp +\fB::http::size \fItoken\fR +.sp +\fB::http::code \fItoken\fR +.sp +\fB::http::ncode \fItoken\fR +.sp +\fB::http::data \fItoken\fR +.sp +\fB::http::error \fItoken\fR +.sp +\fB::http::cleanup \fItoken\fR +.sp +\fB::http::register \fIproto port command\fR +.sp +\fB::http::unregister \fIproto\fR +.BE + +.SH DESCRIPTION +.PP +The \fBhttp\fR package provides the client side of the HTTP/1.0 +protocol. The package implements the GET, POST, and HEAD operations +of HTTP/1.0. It allows configuration of a proxy host to get through +firewalls. The package is compatible with the \fBSafesock\fR security +policy, so it can be used by untrusted applets to do URL fetching from +a restricted set of hosts. This package can be extened to support +additional HTTP transport protocols, such as HTTPS, by providing +a custom \fBsocket\fR command, via \fBhttp::register\fR. +.PP +The \fB::http::geturl\fR procedure does a HTTP transaction. +Its \fIoptions \fR determine whether a GET, POST, or HEAD transaction +is performed. +The return value of \fB::http::geturl\fR is a token for the transaction. +The value is also the name of an array in the ::http namespace +that contains state information about the transaction. The elements +of this array are described in the STATE ARRAY section. +.PP +If the \fB-command\fP option is specified, then +the HTTP operation is done in the background. +\fB::http::geturl\fR returns immediately after generating the +HTTP request and the callback is invoked +when the transaction completes. For this to work, the Tcl event loop +must be active. In Tk applications this is always true. For pure-Tcl +applications, the caller can use \fB::http::wait\fR after calling +\fB::http::geturl\fR to start the event loop. +.SH COMMANDS +.TP +\fB::http::config\fP ?\fIoptions\fR? +The \fB::http::config\fR command is used to set and query the name of the +proxy server and port, and the User-Agent name used in the HTTP +requests. If no options are specified, then the current configuration +is returned. If a single argument is specified, then it should be one +of the flags described below. In this case the current value of +that setting is returned. Otherwise, the options should be a set of +flags and values that define the configuration: +.RS +.TP +\fB\-accept\fP \fImimetypes\fP +The Accept header of the request. The default is */*, which means that +all types of documents are accepted. Otherwise you can supply a +comma separated list of mime type patterns that you are +willing to receive. For example, "image/gif, image/jpeg, text/*". +.TP +\fB\-proxyhost\fP \fIhostname\fP +The name of the proxy host, if any. If this value is the +empty string, the URL host is contacted directly. +.TP +\fB\-proxyport\fP \fInumber\fP +The proxy port number. +.TP +\fB\-proxyfilter\fP \fIcommand\fP +The command is a callback that is made during +\fB::http::geturl\fR +to determine if a proxy is required for a given host. One argument, a +host name, is added to \fIcommand\fR when it is invoked. If a proxy +is required, the callback should return a two element list containing +the proxy server and proxy port. Otherwise the filter should return +an empty list. The default filter returns the values of the +\fB\-proxyhost\fR and \fB\-proxyport\fR settings if they are +non-empty. +.TP +\fB\-useragent\fP \fIstring\fP +The value of the User-Agent header in the HTTP request. The default +is \fB"Tcl http client package 2.2."\fR +.RE +.TP +\fB::http::geturl\fP \fIurl\fP ?\fIoptions\fP? +The \fB::http::geturl\fR command is the main procedure in the package. +The \fB\-query\fR option causes a POST operation and +the \fB\-validate\fR option causes a HEAD operation; +otherwise, a GET operation is performed. The \fB::http::geturl\fR command +returns a \fItoken\fR value that can be used to get +information about the transaction. See the STATE ARRAY and ERRORS section for +details. The \fB::http::geturl\fR command blocks until the operation +completes, unless the \fB\-command\fR option specifies a callback +that is invoked when the HTTP transaction completes. +\fB::http::geturl\fR takes several options: +.RS +.TP +\fB\-binary\fP \fIboolean\fP +Specifies whether to force interpreting the url data as binary. Normally +this is auto-detected (anything not beginning with a \fBtext\fR content +type or whose content encoding is \fBgzip\fR or \fBcompress\fR is +considered binary data). +.TP +\fB\-blocksize\fP \fIsize\fP +The blocksize used when reading the URL. +At most \fIsize\fR bytes are read at once. After each block, a call to the +\fB\-progress\fR callback is made (if that option is specified). +.TP +\fB\-channel\fP \fIname\fP +Copy the URL contents to channel \fIname\fR instead of saving it in +\fBstate(body)\fR. +.TP +\fB\-command\fP \fIcallback\fP +Invoke \fIcallback\fP after the HTTP transaction completes. +This option causes \fB::http::geturl\fP to return immediately. +The \fIcallback\fP gets an additional argument that is the \fItoken\fR returned +from \fB::http::geturl\fR. This token is the name of an array that is +described in the STATE ARRAY section. Here is a template for the +callback: +.RS +.CS +proc httpCallback {token} { + upvar #0 $token state + # Access state as a Tcl array +} +.CE +.RE +.TP +\fB\-handler\fP \fIcallback\fP +Invoke \fIcallback\fP whenever HTTP data is available; if present, nothing +else will be done with the HTTP data. This procedure gets two additional +arguments: the socket for the HTTP data and the \fItoken\fR returned from +\fB::http::geturl\fR. The token is the name of a global array that is described +in the STATE ARRAY section. The procedure is expected to return the number +of bytes read from the socket. Here is a template for the callback: +.RS +.CS +proc httpHandlerCallback {socket token} { + upvar #0 $token state + # Access socket, and state as a Tcl array + ... + (example: set data [read $socket 1000];set nbytes [string length $data]) + ... + return nbytes +} +.CE +.RE +.TP +\fB\-headers\fP \fIkeyvaluelist\fP +This option is used to add extra headers to the HTTP request. The +\fIkeyvaluelist\fR argument must be a list with an even number of +elements that alternate between keys and values. The keys become +header field names. Newlines are stripped from the values so the +header cannot be corrupted. For example, if \fIkeyvaluelist\fR is +\fBPragma no-cache\fR then the following header is included in the +HTTP request: +.CS +Pragma: no-cache +.CE +.TP +\fB\-progress\fP \fIcallback\fP +The \fIcallback\fR is made after each transfer of data from the URL. +The callback gets three additional arguments: the \fItoken\fR from +\fB::http::geturl\fR, the expected total size of the contents from the +\fBContent-Length\fR meta-data, and the current number of bytes +transferred so far. The expected total size may be unknown, in which +case zero is passed to the callback. Here is a template for the +progress callback: +.RS +.CS +proc httpProgress {token total current} { + upvar #0 $token state +} +.CE +.RE +.TP +\fB\-query\fP \fIquery\fP +This flag causes \fB::http::geturl\fR to do a POST request that passes the +\fIquery\fR to the server. The \fIquery\fR must be a x-url-encoding +formatted query. The \fB::http::formatQuery\fR procedure can be used to +do the formatting. +.TP +\fB\-queryblocksize\fP \fIsize\fP +The blocksize used when posting query data to the URL. +At most +\fIsize\fR +bytes are written at once. After each block, a call to the +\fB\-queryprogress\fR +callback is made (if that option is specified). +.TP +\fB\-querychannel\fP \fIchannelID\fP +This flag causes \fB::http::geturl\fR to do a POST request that passes the +data contained in \fIchannelID\fR to the server. The data contained in \fIchannelID\fR must be a x-url-encoding +formatted query unless the \fB\-type\fP option below is used. +If a Content-Length header is not specified via the \fB\-headers\fR options, +\fB::http::geturl\fR attempts to determine the size of the post data +in order to create that header. If it is +unable to determine the size, it returns an error. +.TP +\fB\-queryprogress\fP \fIcallback\fP +The \fIcallback\fR is made after each transfer of data to the URL +(i.e. POST) and acts exactly like the \fB\-progress\fR option (the +callback format is the same). +.TP +\fB\-timeout\fP \fImilliseconds\fP +If \fImilliseconds\fR is non-zero, then \fB::http::geturl\fR sets up a timeout +to occur after the specified number of milliseconds. +A timeout results in a call to \fB::http::reset\fP and to +the \fB-command\fP callback, if specified. +The return value of \fB::http::status\fP is \fBtimeout\fP +after a timeout has occurred. +.TP +\fB\-type\fP \fImime-type\fP +Use \fImime-type\fR as the \fBContent-Type\fR value, instead of the +default value (\fBapplication/x-www-form-urlencoded\fR) during a +POST operation. +.TP +\fB\-validate\fP \fIboolean\fP +If \fIboolean\fR is non-zero, then \fB::http::geturl\fR does an HTTP HEAD +request. This request returns meta information about the URL, but the +contents are not returned. The meta information is available in the +\fBstate(meta) \fR variable after the transaction. See the STATE +ARRAY section for details. +.RE +.TP +\fB::http::formatQuery\fP \fIkey value\fP ?\fIkey value\fP ...? +This procedure does x-url-encoding of query data. It takes an even +number of arguments that are the keys and values of the query. It +encodes the keys and values, and generates one string that has the +proper & and = separators. The result is suitable for the +\fB\-query\fR value passed to \fB::http::geturl\fR. +.TP +\fB::http::reset\fP \fItoken\fP ?\fIwhy\fP? +This command resets the HTTP transaction identified by \fItoken\fR, if +any. This sets the \fBstate(status)\fP value to \fIwhy\fP, which defaults to \fBreset\fR, and then calls the registered \fB\-command\fR callback. +.TP +\fB::http::wait\fP \fItoken\fP +This is a convenience procedure that blocks and waits for the +transaction to complete. This only works in trusted code because it +uses \fBvwait\fR. Also, it's not useful for the case where +\fB::http::geturl\fP is called \fIwithout\fP the \fB-command\fP option +because in this case the \fB::http::geturl\fP call doesn't return +until the HTTP transaction is complete, and thus there's nothing to +wait for. +.TP +\fB::http::data\fP \fItoken\fP +This is a convenience procedure that returns the \fBbody\fP element +(i.e., the URL data) of the state array. +.TP +\fB::http::error\fP \fItoken\fP +This is a convenience procedure that returns the \fBerror\fP element +of the state array. +.TP +\fB::http::status\fP \fItoken\fP +This is a convenience procedure that returns the \fBstatus\fP element of +the state array. +.TP +\fB::http::code\fP \fItoken\fP +This is a convenience procedure that returns the \fBhttp\fP element of the +state array. +.TP +\fB::http::ncode\fP \fItoken\fP +This is a convenience procedure that returns just the numeric return +code (200, 404, etc.) from the \fBhttp\fP element of the state array. +.TP +\fB::http::size\fP \fItoken\fP +This is a convenience procedure that returns the \fBcurrentsize\fP +element of the state array, which represents the number of bytes +received from the URL in the \fB::http::geturl\fP call. +.TP +\fB::http::cleanup\fP \fItoken\fP +This procedure cleans up the state associated with the connection +identified by \fItoken\fP. After this call, the procedures +like \fB::http::data\fP cannot be used to get information +about the operation. It is \fIstrongly\fP recommended that you call +this function after you're done with a given HTTP request. Not doing +so will result in memory not being freed, and if your app calls +\fB::http::geturl\fP enough times, the memory leak could cause a +performance hit...or worse. +.TP +\fB::http::register\fP \fIproto port command\fP +This procedure allows one to provide custom HTTP transport types +such as HTTPS, by registering a prefix, the default port, and the +command to execute to create the Tcl \fBchannel\fR. E.g.: +.RS +.CS +package require http +package require tls + +http::register https 443 ::tls::socket + +set token [http::geturl https://my.secure.site/] +.CE +.RE +.TP +\fB::http::unregister\fP \fIproto\fP +This procedure unregisters a protocol handler that was previously +registered via \fBhttp::register\fR. + +.SH "ERRORS" +The \fBhttp::geturl\fP procedure will raise errors in the following cases: +invalid command line options, +an invalid URL, +a URL on a non-existent host, +or a URL at a bad port on an existing host. +These errors mean that it +cannot even start the network transaction. +It will also raise an error if it gets an I/O error while +writing out the HTTP request header. +For synchronous \fB::http::geturl\fP calls (where \fB-command\fP is +not specified), it will raise an error if it gets an I/O error while +reading the HTTP reply headers or data. Because \fB::http::geturl\fP +doesn't return a token in these cases, it does all the required +cleanup and there's no issue of your app having to call +\fB::http::cleanup\fP. +.PP +For asynchronous \fB::http::geturl\fP calls, all of the above error +situations apply, except that if there's any error while +reading the +HTTP reply headers or data, no exception is thrown. This is because +after writing the HTTP headers, \fB::http::geturl\fP returns, and the +rest of the HTTP transaction occurs in the background. The command +callback can check if any error occurred during the read by calling +\fB::http::status\fP to check the status and if it's \fIerror\fP, +calling \fB::http::error\fP to get the error message. +.PP +Alternatively, if the main program flow reaches a point where it needs +to know the result of the asynchronous HTTP request, it can call +\fB::http::wait\fP and then check status and error, just as the +callback does. +.PP +In any case, you must still call +\fBhttp::cleanup\fP to delete the state array when you're done. +.PP +There are other possible results of the HTTP transaction +determined by examining the status from \fBhttp::status\fP. +These are described below. +.TP +ok +If the HTTP transaction completes entirely, then status will be \fBok\fP. +However, you should still check the \fBhttp::code\fP value to get +the HTTP status. The \fBhttp::ncode\fP procedure provides just +the numeric error (e.g., 200, 404 or 500) while the \fBhttp::code\fP +procedure returns a value like "HTTP 404 File not found". +.TP +eof +If the server closes the socket without replying, then no error +is raised, but the status of the transaction will be \fBeof\fP. +.TP +error +The error message will also be stored in the \fBerror\fP status +array element, accessible via \fB::http::error\fP. +.PP +Another error possibility is that \fBhttp::geturl\fP is unable to +write all the post query data to the server before the server +responds and closes the socket. +The error message is saved in the \fBposterror\fP status array +element and then \fBhttp::geturl\fP attempts to complete the +transaction. +If it can read the server's response +it will end up with an \fBok\fP status, otherwise it will have +an \fBeof\fP status. + +.SH "STATE ARRAY" +The \fB::http::geturl\fR procedure returns a \fItoken\fR that can be used to +get to the state of the HTTP transaction in the form of a Tcl array. +Use this construct to create an easy-to-use array variable: +.CS +upvar #0 $token state +.CE +Once the data associated with the url is no longer needed, the state +array should be unset to free up storage. +The \fBhttp::cleanup\fP procedure is provided for that purpose. +The following elements of +the array are supported: +.RS +.TP +\fBbody\fR +The contents of the URL. This will be empty if the \fB\-channel\fR +option has been specified. This value is returned by the \fB::http::data\fP command. +.TP +\fBcharset\fR +The value of the charset attribute from the \fBContent-Type\fR meta-data +value. If none was specified, this defaults to the RFC standard +\fBiso8859-1\fR, or the value of \fB$::http::defaultCharset\fR. Incoming +text data will be automatically converted from this charset to utf-8. +.TP +\fBcoding\fR +A copy of the \fBContent-Encoding\fR meta-data value. +.TP +\fBcurrentsize\fR +The current number of bytes fetched from the URL. +This value is returned by the \fB::http::size\fP command. +.TP +\fBerror\fR +If defined, this is the error string seen when the HTTP transaction +was aborted. +.TP +\fBhttp\fR +The HTTP status reply from the server. This value +is returned by the \fB::http::code\fP command. The format of this value is: +.RS +.CS +\fIHTTP/1.0 code string\fP +.CE +The \fIcode\fR is a three-digit number defined in the HTTP standard. +A code of 200 is OK. Codes beginning with 4 or 5 indicate errors. +Codes beginning with 3 are redirection errors. In this case the +\fBLocation\fR meta-data specifies a new URL that contains the +requested information. +.RE +.TP +\fBmeta\fR +The HTTP protocol returns meta-data that describes the URL contents. +The \fBmeta\fR element of the state array is a list of the keys and +values of the meta-data. This is in a format useful for initializing +an array that just contains the meta-data: +.RS +.CS +array set meta $state(meta) +.CE +Some of the meta-data keys are listed below, but the HTTP standard defines +more, and servers are free to add their own. +.TP +\fBContent-Type\fR +The type of the URL contents. Examples include \fBtext/html\fR, +\fBimage/gif,\fR \fBapplication/postscript\fR and +\fBapplication/x-tcl\fR. +.TP +\fBContent-Length\fR +The advertised size of the contents. The actual size obtained by +\fB::http::geturl\fR is available as \fBstate(size)\fR. +.TP +\fBLocation\fR +An alternate URL that contains the requested data. +.RE +.TP +\fBposterror\fR +The error, if any, that occurred while writing +the post query data to the server. +.TP +\fBstatus\fR +Either \fBok\fR, for successful completion, \fBreset\fR for +user-reset, \fBtimeout\fP if a timeout occurred before the transaction +could complete, or \fBerror\fR for an error condition. During the +transaction this value is the empty string. +.TP +\fBtotalsize\fR +A copy of the \fBContent-Length\fR meta-data value. +.TP +\fBtype\fR +A copy of the \fBContent-Type\fR meta-data value. +.TP +\fBurl\fR +The requested URL. +.RE +.SH EXAMPLE +.DS +# Copy a URL to a file and print meta-data +proc ::http::copy { url file {chunk 4096} } { + set out [open $file w] + set token [geturl $url -channel $out -progress ::http::Progress \\ + -blocksize $chunk] + close $out + # This ends the line started by http::Progress + puts stderr "" + upvar #0 $token state + set max 0 + foreach {name value} $state(meta) { + if {[string length $name] > $max} { + set max [string length $name] + } + if {[regexp -nocase ^location$ $name]} { + # Handle URL redirects + puts stderr "Location:$value" + return [copy [string trim $value] $file $chunk] + } + } + incr max + foreach {name value} $state(meta) { + puts [format "%-*s %s" $max $name: $value] + } + + return $token +} +proc ::http::Progress {args} { + puts -nonewline stderr . ; flush stderr +} +.DE + +.SH "SEE ALSO" +safe(n), socket(n), safesock(n) + +.SH KEYWORDS +security policy, socket diff --git a/mk4/modtcl/tcl8.3.4/doc/if.n b/mk4/modtcl/tcl8.3.4/doc/if.n new file mode 100644 index 0000000..1229f51 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/if.n @@ -0,0 +1,46 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: if.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH if n "" Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +if \- Execute scripts conditionally +.SH SYNOPSIS +\fBif \fIexpr1 \fR?\fBthen\fR? \fIbody1 \fBelseif \fIexpr2 \fR?\fBthen\fR? \fIbody2\fR \fBelseif\fR ... ?\fBelse\fR? ?\fIbodyN\fR? +.BE + +.SH DESCRIPTION +.PP +The \fIif\fR command evaluates \fIexpr1\fR as an expression (in the +same way that \fBexpr\fR evaluates its argument). The value of the +expression must be a boolean +(a numeric value, where 0 is false and +anything is true, or a string value such as \fBtrue\fR or \fByes\fR +for true and \fBfalse\fR or \fBno\fR for false); +if it is true then \fIbody1\fR is executed by passing it to the +Tcl interpreter. +Otherwise \fIexpr2\fR is evaluated as an expression and if it is true +then \fBbody2\fR is executed, and so on. +If none of the expressions evaluates to true then \fIbodyN\fR is +executed. +The \fBthen\fR and \fBelse\fR arguments are optional +``noise words'' to make the command easier to read. +There may be any number of \fBelseif\fR clauses, including zero. +\fIBodyN\fR may also be omitted as long as \fBelse\fR is omitted too. +The return value from the command is the result of the body script +that was executed, or an empty string +if none of the expressions was non-zero and there was no \fIbodyN\fR. + +.SH "SEE ALSO" +expr(n), for(n), foreach(n) + +.SH KEYWORDS +boolean, conditional, else, false, if, true diff --git a/mk4/modtcl/tcl8.3.4/doc/incr.n b/mk4/modtcl/tcl8.3.4/doc/incr.n new file mode 100644 index 0000000..77501b8 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/incr.n @@ -0,0 +1,34 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: incr.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH incr n "" Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +incr \- Increment the value of a variable +.SH SYNOPSIS +\fBincr \fIvarName \fR?\fIincrement\fR? +.BE + +.SH DESCRIPTION +.PP +Increments the value stored in the variable whose name is \fIvarName\fR. +The value of the variable must be an integer. +If \fIincrement\fR is supplied then its value (which must be an +integer) is added to the value of variable \fIvarName\fR; otherwise +1 is added to \fIvarName\fR. +The new value is stored as a decimal string in variable \fIvarName\fR +and also returned as result. + +.SH "SEE ALSO" +expr(n) + +.SH KEYWORDS +add, increment, variable, value diff --git a/mk4/modtcl/tcl8.3.4/doc/info.n b/mk4/modtcl/tcl8.3.4/doc/info.n new file mode 100644 index 0000000..cce5cdc --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/info.n @@ -0,0 +1,185 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1997 Sun Microsystems, Inc. +'\" Copyright (c) 1993-1997 Bell Labs Innovations for Lucent Technologies +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: info.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH info n 7.5 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +info \- Return information about the state of the Tcl interpreter +.SH SYNOPSIS +\fBinfo \fIoption \fR?\fIarg arg ...\fR? +.BE + +.SH DESCRIPTION +.PP +This command provides information about various internals of the Tcl +interpreter. +The legal \fIoption\fR's (which may be abbreviated) are: +.TP +\fBinfo args \fIprocname\fR +Returns a list containing the names of the arguments to procedure +\fIprocname\fR, in order. \fIProcname\fR must be the name of a +Tcl command procedure. +.TP +\fBinfo body \fIprocname\fR +Returns the body of procedure \fIprocname\fR. \fIProcname\fR must be +the name of a Tcl command procedure. +.TP +\fBinfo cmdcount\fR +Returns a count of the total number of commands that have been invoked +in this interpreter. +.TP +\fBinfo commands \fR?\fIpattern\fR? +If \fIpattern\fR isn't specified, +returns a list of names of all the Tcl commands in the current namespace, +including both the built-in commands written in C and +the command procedures defined using the \fBproc\fR command. +If \fIpattern\fR is specified, +only those names matching \fIpattern\fR are returned. +Matching is determined using the same rules as for \fBstring match\fR. +\fIpattern\fR can be a qualified name like \fBFoo::print*\fR. +That is, it may specify a particular namespace +using a sequence of namespace names separated by \fB::\fRs, +and may have pattern matching special characters +at the end to specify a set of commands in that namespace. +If \fIpattern\fR is a qualified name, +the resulting list of command names has each one qualified with the name +of the specified namespace. +.TP +\fBinfo complete \fIcommand\fR +Returns 1 if \fIcommand\fR is a complete Tcl command in the sense of +having no unclosed quotes, braces, brackets or array element names, +If the command doesn't appear to be complete then 0 is returned. +This command is typically used in line-oriented input environments +to allow users to type in commands that span multiple lines; if the +command isn't complete, the script can delay evaluating it until additional +lines have been typed to complete the command. +.TP +\fBinfo default \fIprocname arg varname\fR +\fIProcname\fR must be the name of a Tcl command procedure and \fIarg\fR +must be the name of an argument to that procedure. If \fIarg\fR +doesn't have a default value then the command returns \fB0\fR. +Otherwise it returns \fB1\fR and places the default value of \fIarg\fR +into variable \fIvarname\fR. +.TP +\fBinfo exists \fIvarName\fR +Returns \fB1\fR if the variable named \fIvarName\fR exists in the +current context (either as a global or local variable) and has been +defined by being given a value, returns \fB0\fR otherwise. +.TP +\fBinfo globals \fR?\fIpattern\fR? +If \fIpattern\fR isn't specified, returns a list of all the names +of currently-defined global variables. +Global variables are variables in the global namespace. +If \fIpattern\fR is specified, only those names matching \fIpattern\fR +are returned. Matching is determined using the same rules as for +\fBstring match\fR. +.TP +\fBinfo hostname\fR +Returns the name of the computer on which this invocation is being +executed. +.TP +\fBinfo level\fR ?\fInumber\fR? +If \fInumber\fR is not specified, this command returns a number +giving the stack level of the invoking procedure, or 0 if the +command is invoked at top-level. If \fInumber\fR is specified, +then the result is a list consisting of the name and arguments for the +procedure call at level \fInumber\fR on the stack. If \fInumber\fR +is positive then it selects a particular stack level (1 refers +to the top-most active procedure, 2 to the procedure it called, and +so on); otherwise it gives a level relative to the current level +(0 refers to the current procedure, -1 to its caller, and so on). +See the \fBuplevel\fR command for more information on what stack +levels mean. +.TP +\fBinfo library\fR +Returns the name of the library directory in which standard Tcl +scripts are stored. +This is actually the value of the \fBtcl_library\fR +variable and may be changed by setting \fBtcl_library\fR. +See the \fBtclvars\fR manual entry for more information. +.TP +\fBinfo loaded \fR?\fIinterp\fR? +Returns a list describing all of the packages that have been loaded into +\fIinterp\fR with the \fBload\fR command. +Each list element is a sub-list with two elements consisting of the +name of the file from which the package was loaded and the name of +the package. +For statically-loaded packages the file name will be an empty string. +If \fIinterp\fR is omitted then information is returned for all packages +loaded in any interpreter in the process. +To get a list of just the packages in the current interpreter, specify +an empty string for the \fIinterp\fR argument. +.TP +\fBinfo locals \fR?\fIpattern\fR? +If \fIpattern\fR isn't specified, returns a list of all the names +of currently-defined local variables, including arguments to the +current procedure, if any. +Variables defined with the \fBglobal\fR and \fBupvar\fR commands +will not be returned. +If \fIpattern\fR is specified, only those names matching \fIpattern\fR +are returned. Matching is determined using the same rules as for +\fBstring match\fR. +.TP +\fBinfo nameofexecutable\fR +Returns the full path name of the binary file from which the application +was invoked. If Tcl was unable to identify the file, then an empty +string is returned. +.TP +\fBinfo patchlevel\fR +Returns the value of the global variable \fBtcl_patchLevel\fR; see +the \fBtclvars\fR manual entry for more information. +.TP +\fBinfo procs \fR?\fIpattern\fR? +If \fIpattern\fR isn't specified, returns a list of all the +names of Tcl command procedures in the current namespace. +If \fIpattern\fR is specified, +only those procedure names in the current namespace +matching \fIpattern\fR are returned. +Matching is determined using the same rules as for +\fBstring match\fR. +.TP +\fBinfo script\fR +If a Tcl script file is currently being evaluated (i.e. there is a +call to \fBTcl_EvalFile\fR active or there is an active invocation +of the \fBsource\fR command), then this command returns the name +of the innermost file being processed. Otherwise the command returns an +empty string. +.TP +\fBinfo sharedlibextension\fR +Returns the extension used on this platform for the names of files +containing shared libraries (for example, \fB.so\fR under Solaris). +If shared libraries aren't supported on this platform then an empty +string is returned. +.TP +\fBinfo tclversion\fR +Returns the value of the global variable \fBtcl_version\fR; see +the \fBtclvars\fR manual entry for more information. +.TP +\fBinfo vars\fR ?\fIpattern\fR? +If \fIpattern\fR isn't specified, +returns a list of all the names of currently-visible variables. +This includes locals and currently-visible globals. +If \fIpattern\fR is specified, only those names matching \fIpattern\fR +are returned. Matching is determined using the same rules as for +\fBstring match\fR. +\fIpattern\fR can be a qualified name like \fBFoo::option*\fR. +That is, it may specify a particular namespace +using a sequence of namespace names separated by \fB::\fRs, +and may have pattern matching special characters +at the end to specify a set of variables in that namespace. +If \fIpattern\fR is a qualified name, +the resulting list of variable names +has each matching namespace variable qualified with the name +of its namespace. + +.SH KEYWORDS +command, information, interpreter, level, namespace, procedure, variable diff --git a/mk4/modtcl/tcl8.3.4/doc/interp.n b/mk4/modtcl/tcl8.3.4/doc/interp.n new file mode 100644 index 0000000..660a4c3 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/interp.n @@ -0,0 +1,542 @@ +'\" +'\" Copyright (c) 1995-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: interp.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH interp n 7.6 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +interp \- Create and manipulate Tcl interpreters +.SH SYNOPSIS +\fBinterp \fIoption \fR?\fIarg arg ...\fR? +.BE + +.SH DESCRIPTION +.PP +This command makes it possible to create one or more new Tcl +interpreters that co-exist with the creating interpreter in the +same application. The creating interpreter is called the \fImaster\fR +and the new interpreter is called a \fIslave\fR. +A master can create any number of slaves, and each slave can +itself create additional slaves for which it is master, resulting +in a hierarchy of interpreters. +.PP +Each interpreter is independent from the others: it has its own name +space for commands, procedures, and global variables. +A master interpreter may create connections between its slaves and +itself using a mechanism called an \fIalias\fR. An \fIalias\fR is +a command in a slave interpreter which, when invoked, causes a +command to be invoked in its master interpreter or in another slave +interpreter. The only other connections between interpreters are +through environment variables (the \fBenv\fR variable), which are +normally shared among all interpreters in the application. Note that the +name space for files (such as the names returned by the \fBopen\fR command) +is no longer shared between interpreters. Explicit commands are provided to +share files and to transfer references to open files from one interpreter +to another. +.PP +The \fBinterp\fR command also provides support for \fIsafe\fR +interpreters. A safe interpreter is a slave whose functions have +been greatly restricted, so that it is safe to execute untrusted +scripts without fear of them damaging other interpreters or the +application's environment. For example, all IO channel creation +commands and subprocess creation commands are made inaccessible to safe +interpreters. +.VS +See SAFE INTERPRETERS below for more information on +what features are present in a safe interpreter. +The dangerous functionality is not removed from the safe interpreter; +instead, it is \fIhidden\fR, so that only trusted interpreters can obtain +access to it. For a detailed explanation of hidden commands, see +HIDDEN COMMANDS, below. +The alias mechanism can be used for protected communication (analogous to a +kernel call) between a slave interpreter and its master. See ALIAS +INVOCATION, below, for more details on how the alias mechanism works. +.VE +.PP +A qualified interpreter name is a proper Tcl lists containing a subset of its +ancestors in the interpreter hierarchy, terminated by the string naming the +interpreter in its immediate master. Interpreter names are relative to the +interpreter in which they are used. For example, if \fBa\fR is a slave of +the current interpreter and it has a slave \fBa1\fR, which in turn has a +slave \fBa11\fR, the qualified name of \fBa11\fR in \fBa\fR is the list +\fBa1 a11\fR. +.PP +The \fBinterp\fR command, described below, accepts qualified interpreter +names as arguments; the interpreter in which the command is being evaluated +can always be referred to as \fB{}\fR (the empty list or string). Note that +it is impossible to refer to a master (ancestor) interpreter by name in a +slave interpreter except through aliases. Also, there is no global name by +which one can refer to the first interpreter created in an application. +Both restrictions are motivated by safety concerns. + +.VS +.SH "THE INTERP COMMAND" +.PP +.VE +The \fBinterp\fR command is used to create, delete, and manipulate +slave interpreters, and to share or transfer +channels between interpreters. It can have any of several forms, depending +on the \fIoption\fR argument: +.TP +\fBinterp\fR \fBalias\fR \fIsrcPath\fR \fIsrcCmd\fR +Returns a Tcl list whose elements are the \fItargetCmd\fR and +\fIarg\fRs associated with the alias named \fIsrcCmd\fR +(all of these are the values specified when the alias was +created; it is possible that the actual source command in the +slave is different from \fIsrcCmd\fR if it was renamed). +.TP +\fBinterp\fR \fBalias\fR \fIsrcPath\fR \fIsrcCmd\fR \fB{}\fR +Deletes the alias for \fIsrcCmd\fR in the slave interpreter identified by +\fIsrcPath\fR. +\fIsrcCmd\fR refers to the name under which the alias +was created; if the source command has been renamed, the renamed +command will be deleted. +.TP +\fBinterp\fR \fBalias\fR \fIsrcPath\fR \fIsrcCmd\fR \fItargetPath\fR \fItargetCmd \fR?\fIarg arg ...\fR? +This command creates an alias between one slave and another (see the +\fBalias\fR slave command below for creating aliases between a slave +and its master). In this command, either of the slave interpreters +may be anywhere in the hierarchy of interpreters under the interpreter +invoking the command. +\fISrcPath\fR and \fIsrcCmd\fR identify the source of the alias. +\fISrcPath\fR is a Tcl list whose elements select a particular +interpreter. For example, ``\fBa b\fR'' identifies an interpreter +\fBb\fR, which is a slave of interpreter \fBa\fR, which is a slave +of the invoking interpreter. An empty list specifies the interpreter +invoking the command. \fIsrcCmd\fR gives the name of a new +command, which will be created in the source interpreter. +\fITargetPath\fR and \fItargetCmd\fR specify a target interpreter +and command, and the \fIarg\fR arguments, if any, specify additional +arguments to \fItargetCmd\fR which are prepended to any arguments specified +in the invocation of \fIsrcCmd\fR. +\fITargetCmd\fR may be undefined at the time of this call, or it may +already exist; it is not created by this command. +The alias arranges for the given target command to be invoked +in the target interpreter whenever the given source command is +invoked in the source interpreter. See ALIAS INVOCATION below for +more details. +.TP +\fBinterp\fR \fBaliases \fR?\fIpath\fR? +This command returns a Tcl list of the names of all the source commands for +aliases defined in the interpreter identified by \fIpath\fR. +.TP +\fBinterp\fR \fBcreate \fR?\fB\-safe\fR? ?\fB\-\|\-\fR? ?\fIpath\fR? +Creates a slave interpreter identified by \fIpath\fR and a new command, +called a \fIslave command\fR. The name of the slave command is the last +component of \fIpath\fR. The new slave interpreter and the slave command +are created in the interpreter identified by the path obtained by removing +the last component from \fIpath\fR. For example, if \fIpath is \fBa b +c\fR then a new slave interpreter and slave command named \fBc\fR are +created in the interpreter identified by the path \fBa b\fR. +The slave command may be used to manipulate the new interpreter as +described below. If \fIpath\fR is omitted, Tcl creates a unique name of the +form \fBinterp\fIx\fR, where \fIx\fR is an integer, and uses it for the +interpreter and the slave command. If the \fB\-safe\fR switch is specified +(or if the master interpreter is a safe interpreter), the new slave +interpreter will be created as a safe interpreter with limited +functionality; otherwise the slave will include the full set of Tcl +built-in commands and variables. The \fB\-\|\-\fR switch can be used to +mark the end of switches; it may be needed if \fIpath\fR is an unusual +value such as \fB\-safe\fR. The result of the command is the name of the +new interpreter. The name of a slave interpreter must be unique among all +the slaves for its master; an error occurs if a slave interpreter by the +given name already exists in this master. +.TP +\fBinterp\fR \fBdelete \fR?\fIpath ...?\fR +Deletes zero or more interpreters given by the optional \fIpath\fR +arguments, and for each interpreter, it also deletes its slaves. The +command also deletes the slave command for each interpreter deleted. +For each \fIpath\fR argument, if no interpreter by that name +exists, the command raises an error. +.TP +\fBinterp\fR \fBeval\fR \fIpath arg \fR?\fIarg ...\fR? +This command concatenates all of the \fIarg\fR arguments in the same +fashion as the \fBconcat\fR command, then evaluates the resulting string as +a Tcl script in the slave interpreter identified by \fIpath\fR. The result +of this evaluation (including error information such as the \fBerrorInfo\fR +and \fBerrorCode\fR variables, if an error occurs) is returned to the +invoking interpreter. +.TP +\fBinterp exists \fIpath\fR +Returns \fB1\fR if a slave interpreter by the specified \fIpath\fR +exists in this master, \fB0\fR otherwise. If \fIpath\fR is omitted, the +invoking interpreter is used. +.VS "" BR +.TP +\fBinterp expose \fIpath\fR \fIhiddenName\fR ?\fIexposedCmdName\fR? +Makes the hidden command \fIhiddenName\fR exposed, eventually bringing +it back under a new \fIexposedCmdName\fR name (this name is currently +accepted only if it is a valid global name space name without any ::), +in the interpreter +denoted by \fIpath\fR. +If an exposed command with the targetted name already exists, this command +fails. +Hidden commands are explained in more detail in HIDDEN COMMANDS, below. +.TP +\fBinterp\fR \fBhide\fR \fIpath\fR \fIexposedCmdName\fR ?\fIhiddenCmdName\fR? +Makes the exposed command \fIexposedCmdName\fR hidden, renaming +it to the hidden command \fIhiddenCmdName\fR, or keeping the same name if +\fIhiddenCmdName\fR is not given, in the interpreter denoted +by \fIpath\fR. +If a hidden command with the targetted name already exists, this command +fails. +Currently both \fIexposedCmdName\fR and \fIhiddenCmdName\fR can +not contain namespace qualifiers, or an error is raised. +Commands to be hidden by \fBinterp hide\fR are looked up in the global +namespace even if the current namespace is not the global one. This +prevents slaves from fooling a master interpreter into hiding the wrong +command, by making the current namespace be different from the global one. +Hidden commands are explained in more detail in HIDDEN COMMANDS, below. +.TP +\fBinterp\fR \fBhidden\fR \fIpath\fR +Returns a list of the names of all hidden commands in the interpreter +identified by \fIpath\fR. +.TP +\fBinterp\fR \fBinvokehidden\fR \fIpath\fR ?\fB-global\fR? \fIhiddenCmdName\fR ?\fIarg ...\fR? +Invokes the hidden command \fIhiddenCmdName\fR with the arguments supplied +in the interpreter denoted by \fIpath\fR. No substitutions or evaluation +are applied to the arguments. +If the \fB-global\fR flag is present, the hidden command is invoked at the +global level in the target interpreter; otherwise it is invoked at the +current call frame and can access local variables in that and outer call +frames. +Hidden commands are explained in more detail in HIDDEN COMMANDS, below. +.VE +.TP +\fBinterp issafe\fR ?\fIpath\fR? +Returns \fB1\fR if the interpreter identified by the specified \fIpath\fR +is safe, \fB0\fR otherwise. +.VS "" BR +.TP +\fBinterp marktrusted\fR \fIpath\fR +Marks the interpreter identified by \fIpath\fR as trusted. Does +not expose the hidden commands. This command can only be invoked from a +trusted interpreter. +The command has no effect if the interpreter identified by \fIpath\fR is +already trusted. +.VE +.TP +\fBinterp\fR \fBshare\fR \fIsrcPath channelId destPath\fR +Causes the IO channel identified by \fIchannelId\fR to become shared +between the interpreter identified by \fIsrcPath\fR and the interpreter +identified by \fIdestPath\fR. Both interpreters have the same permissions +on the IO channel. +Both interpreters must close it to close the underlying IO channel; IO +channels accessible in an interpreter are automatically closed when an +interpreter is destroyed. +.TP +\fBinterp\fR \fBslaves\fR ?\fIpath\fR? +Returns a Tcl list of the names of all the slave interpreters associated +with the interpreter identified by \fIpath\fR. If \fIpath\fR is omitted, +the invoking interpreter is used. +.TP +\fBinterp\fR \fBtarget\fR \fIpath alias\fR +Returns a Tcl list describing the target interpreter for an alias. The +alias is specified with an interpreter path and source command name, just +as in \fBinterp alias\fR above. The name of the target interpreter is +returned as an interpreter path, relative to the invoking interpreter. +If the target interpreter for the alias is the invoking interpreter then an +empty list is returned. If the target interpreter for the alias is not the +invoking interpreter or one of its descendants then an error is generated. +The target command does not have to be defined at the time of this invocation. +.TP +\fBinterp\fR \fBtransfer\fR \fIsrcPath channelId destPath\fR +Causes the IO channel identified by \fIchannelId\fR to become available in +the interpreter identified by \fIdestPath\fR and unavailable in the +interpreter identified by \fIsrcPath\fR. + +.SH "SLAVE COMMAND" +.PP +For each slave interpreter created with the \fBinterp\fR command, a +new Tcl command is created in the master interpreter with the same +name as the new interpreter. This command may be used to invoke +various operations on the interpreter. It has the following +general form: +.CS +\fIslave command \fR?\fIarg arg ...\fR? +.CE +\fISlave\fR is the name of the interpreter, and \fIcommand\fR +and the \fIarg\fRs determine the exact behavior of the command. +The valid forms of this command are: +.TP +\fIslave \fBaliases\fR +Returns a Tcl list whose elements are the names of all the +aliases in \fIslave\fR. The names returned are the \fIsrcCmd\fR +values used when the aliases were created (which may not be the same +as the current names of the commands, if they have been +renamed). +.TP +\fIslave \fBalias \fIsrcCmd\fR +Returns a Tcl list whose elements are the \fItargetCmd\fR and +\fIarg\fRs associated with the alias named \fIsrcCmd\fR +(all of these are the values specified when the alias was +created; it is possible that the actual source command in the +slave is different from \fIsrcCmd\fR if it was renamed). +.TP +\fIslave \fBalias \fIsrcCmd \fB{}\fR +Deletes the alias for \fIsrcCmd\fR in the slave interpreter. +\fIsrcCmd\fR refers to the name under which the alias +was created; if the source command has been renamed, the renamed +command will be deleted. +.TP +\fIslave \fBalias \fIsrcCmd targetCmd \fR?\fIarg ..\fR? +Creates an alias such that whenever \fIsrcCmd\fR is invoked +in \fIslave\fR, \fItargetCmd\fR is invoked in the master. +The \fIarg\fR arguments will be passed to \fItargetCmd\fR as additional +arguments, prepended before any arguments passed in the invocation of +\fIsrcCmd\fR. +See ALIAS INVOCATION below for details. +.TP +\fIslave \fBeval \fIarg \fR?\fIarg ..\fR? +This command concatenates all of the \fIarg\fR arguments in +the same fashion as the \fBconcat\fR command, then evaluates +the resulting string as a Tcl script in \fIslave\fR. +The result of this evaluation (including error information +such as the \fBerrorInfo\fR and \fBerrorCode\fR variables, if an +error occurs) is returned to the invoking interpreter. +.VS "" BR +.TP +\fIslave \fBexpose \fIhiddenName \fR?\fIexposedCmdName\fR? +This command exposes the hidden command \fIhiddenName\fR, eventually bringing +it back under a new \fIexposedCmdName\fR name (this name is currently +accepted only if it is a valid global name space name without any ::), +in \fIslave\fR. +If an exposed command with the targetted name already exists, this command +fails. +For more details on hidden commands, see HIDDEN COMMANDS, below. +.TP +\fIslave \fBhide \fIexposedCmdName\fR ?\fIhiddenCmdName\fR? +This command hides the exposed command \fIexposedCmdName\fR, renaming it to +the hidden command \fIhiddenCmdName\fR, or keeping the same name if the +the argument is not given, in the \fIslave\fR interpreter. +If a hidden command with the targetted name already exists, this command +fails. +Currently both \fIexposedCmdName\fR and \fIhiddenCmdName\fR can +not contain namespace qualifiers, or an error is raised. +Commands to be hidden are looked up in the global +namespace even if the current namespace is not the global one. This +prevents slaves from fooling a master interpreter into hiding the wrong +command, by making the current namespace be different from the global one. +For more details on hidden commands, see HIDDEN COMMANDS, below. +.TP +\fIslave \fBhidden\fR +Returns a list of the names of all hidden commands in \fIslave\fR. +.TP +\fIslave \fBinvokehidden\fR ?\fB-global\fR \fIhiddenName \fR?\fIarg ..\fR? +This command invokes the hidden command \fIhiddenName\fR with the +supplied arguments, in \fIslave\fR. No substitutions or evaluations are +applied to the arguments. +If the \fB-global\fR flag is given, the command is invoked at the global +level in the slave; otherwise it is invoked at the current call frame and +can access local variables in that or outer call frames. +For more details on hidden commands, see HIDDEN +COMMANDS, below. +.VE +.TP +\fIslave \fBissafe\fR +Returns \fB1\fR if the slave interpreter is safe, \fB0\fR otherwise. +.VS "" BR +.TP +\fIslave \fBmarktrusted\fR +Marks the slave interpreter as trusted. Can only be invoked by a +trusted interpreter. This command does not expose any hidden +commands in the slave interpreter. The command has no effect if the slave +is already trusted. +.VE + +.SH "SAFE INTERPRETERS" +.PP +A safe interpreter is one with restricted functionality, so that +is safe to execute an arbitrary script from your worst enemy without +fear of that script damaging the enclosing application or the rest +of your computing environment. In order to make an interpreter +safe, certain commands and variables are removed from the interpreter. +For example, commands to create files on disk are removed, and the +\fBexec\fR command is removed, since it could be used to cause damage +through subprocesses. +Limited access to these facilities can be provided, by creating +aliases to the master interpreter which check their arguments carefully +and provide restricted access to a safe subset of facilities. +For example, file creation might be allowed in a particular subdirectory +and subprocess invocation might be allowed for a carefully selected and +fixed set of programs. +.PP +A safe interpreter is created by specifying the \fB\-safe\fR switch +to the \fBinterp create\fR command. Furthermore, any slave created +by a safe interpreter will also be safe. +.PP +A safe interpreter is created with exactly the following set of +built-in commands: +.DS +.ta 1.2i 2.4i 3.6i +\fBafter append array binary +break case catch clock +close concat continue eof +error eval expr fblocked +fcopy fileevent flush for +foreach format gets global +history if incr info +interp join lappend lindex +linsert list llength lrange +lreplace lsearch lsort namespace +package pid proc puts +read regexp regsub rename +return scan seek set +split string subst switch +tell trace unset update +uplevel upvar variable vwait +while\fR +.DE +.VS "" BR +The following commands are hidden by \fBinterp create\fR when it +creates a safe interpreter: +.DS +.ta 1.2i 2.4i 3.6i +\fBcd exec exit fconfigure +file glob load open +pwd socket source vwait\fR +.DE +These commands can be recreated later as Tcl procedures or aliases, or +re-exposed by \fBinterp expose\fR. +.VE +.PP +In addition, the \fBenv\fR variable is not present in a safe interpreter, +so it cannot share environment variables with other interpreters. The +\fBenv\fR variable poses a security risk, because users can store +sensitive information in an environment variable. For example, the PGP +manual recommends storing the PGP private key protection password in +the environment variable \fIPGPPASS\fR. Making this variable available +to untrusted code executing in a safe interpreter would incur a +security risk. +.PP +If extensions are loaded into a safe interpreter, they may also restrict +their own functionality to eliminate unsafe commands. For a discussion of +management of extensions for safety see the manual entries for +\fBSafe\-Tcl\fR and the \fBload\fR Tcl command. + +.SH "ALIAS INVOCATION" +.PP +The alias mechanism has been carefully designed so that it can +be used safely when an untrusted script is executing +in a safe slave and the target of the alias is a trusted +master. The most important thing in guaranteeing safety is to +ensure that information passed from the slave to the master is +never evaluated or substituted in the master; if this were to +occur, it would enable an evil script in the slave to invoke +arbitrary functions in the master, which would compromise security. +.PP +When the source for an alias is invoked in the slave interpreter, the +usual Tcl substitutions are performed when parsing that command. +These substitutions are carried out in the source interpreter just +as they would be for any other command invoked in that interpreter. +The command procedure for the source command takes its arguments +and merges them with the \fItargetCmd\fR and \fIarg\fRs for the +alias to create a new array of arguments. If the words +of \fIsrcCmd\fR were ``\fIsrcCmd arg1 arg2 ... argN\fR'', +the new set of words will be +``\fItargetCmd arg arg ... arg arg1 arg2 ... argN\fR'', +where \fItargetCmd\fR and \fIarg\fRs are the values supplied when the +alias was created. \fITargetCmd\fR is then used to locate a command +procedure in the target interpreter, and that command procedure +is invoked with the new set of arguments. An error occurs if +there is no command named \fItargetCmd\fR in the target interpreter. +No additional substitutions are performed on the words: the +target command procedure is invoked directly, without +going through the normal Tcl evaluation mechanism. +Substitutions are thus performed on each word exactly once: +\fItargetCmd\fR and \fIargs\fR were substituted when parsing the command +that created the alias, and \fIarg1 - argN\fR are substituted when +the alias's source command is parsed in the source interpreter. +.PP +When writing the \fItargetCmd\fRs for aliases in safe interpreters, +it is very important that the arguments to that command never be +evaluated or substituted, since this would provide an escape +mechanism whereby the slave interpreter could execute arbitrary +code in the master. This in turn would compromise the security +of the system. + +.VS +.SH "HIDDEN COMMANDS" +.PP +Safe interpreters greatly restrict the functionality available to Tcl +programs executing within them. +Allowing the untrusted Tcl program to have direct access to this +functionality is unsafe, because it can be used for a variety of +attacks on the environment. +However, there are times when there is a legitimate need to use the +dangerous functionality in the context of the safe interpreter. For +example, sometimes a program must be \fBsource\fRd into the interpreter. +Another example is Tk, where windows are bound to the hierarchy of windows +for a specific interpreter; some potentially dangerous functions, e.g. +window management, must be performed on these windows within the +interpreter context. +.PP +The \fBinterp\fR command provides a solution to this problem in the form of +\fIhidden commands\fR. Instead of removing the dangerous commands entirely +from a safe interpreter, these commands are hidden so they become +unavailable to Tcl scripts executing in the interpreter. However, such +hidden commands can be invoked by any trusted ancestor of the safe +interpreter, in the context of the safe interpreter, using \fBinterp +invoke\fR. Hidden commands and exposed commands reside in separate name +spaces. It is possible to define a hidden command and an exposed command by +the same name within one interpreter. +.PP +Hidden commands in a slave interpreter can be invoked in the body of +procedures called in the master during alias invocation. For example, an +alias for \fBsource\fR could be created in a slave interpreter. When it is +invoked in the slave interpreter, a procedure is called in the master +interpreter to check that the operation is allowable (e.g. it asks to +source a file that the slave interpreter is allowed to access). The +procedure then it invokes the hidden \fBsource\fR command in the slave +interpreter to actually source in the contents of the file. Note that two +commands named \fBsource\fR exist in the slave interpreter: the alias, and +the hidden command. +.PP +Because a master interpreter may invoke a hidden command as part of +handling an alias invocation, great care must be taken to avoid evaluating +any arguments passed in through the alias invocation. +Otherwise, malicious slave interpreters could cause a trusted master +interpreter to execute dangerous commands on their behalf. See the section +on ALIAS INVOCATION for a more complete discussion of this topic. +To help avoid this problem, no substitutions or evaluations are +applied to arguments of \fBinterp invokehidden\fR. +.PP +Safe interpreters are not allowed to invoke hidden commands in themselves +or in their descendants. This prevents safe slaves from gaining access to +hidden functionality in themselves or their descendants. +.PP +The set of hidden commands in an interpreter can be manipulated by a trusted +interpreter using \fBinterp expose\fR and \fBinterp hide\fR. The \fBinterp +expose\fR command moves a hidden command to the +set of exposed commands in the interpreter identified by \fIpath\fR, +potentially renaming the command in the process. If an exposed command by +the targetted name already exists, the operation fails. Similarly, +\fBinterp hide\fR moves an exposed command to the set of hidden commands in +that interpreter. Safe interpreters are not allowed to move commands +between the set of hidden and exposed commands, in either themselves or +their descendants. +.PP +Currently, the names of hidden commands cannot contain namespace +qualifiers, and you must first rename a command in a namespace to the +global namespace before you can hide it. +Commands to be hidden by \fBinterp hide\fR are looked up in the global +namespace even if the current namespace is not the global one. This +prevents slaves from fooling a master interpreter into hiding the wrong +command, by making the current namespace be different from the global one. +.VE +.SH CREDITS +.PP +This mechanism is based on the Safe-Tcl prototype implemented +by Nathaniel Borenstein and Marshall Rose. + +.SH "SEE ALSO" +load(n), safe(n), Tcl_CreateSlave(3) + +.SH KEYWORDS +alias, master interpreter, safe interpreter, slave interpreter diff --git a/mk4/modtcl/tcl8.3.4/doc/join.n b/mk4/modtcl/tcl8.3.4/doc/join.n new file mode 100644 index 0000000..5e03b26 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/join.n @@ -0,0 +1,32 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: join.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH join n "" Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +join \- Create a string by joining together list elements +.SH SYNOPSIS +\fBjoin \fIlist \fR?\fIjoinString\fR? +.BE + +.SH DESCRIPTION +.PP +The \fIlist\fR argument must be a valid Tcl list. +This command returns the string +formed by joining all of the elements of \fIlist\fR together with +\fIjoinString\fR separating each adjacent pair of elements. +The \fIjoinString\fR argument defaults to a space character. + +.SH "SEE ALSO" +list(n), lappend(n) + +.SH KEYWORDS +element, join, list, separator diff --git a/mk4/modtcl/tcl8.3.4/doc/lappend.n b/mk4/modtcl/tcl8.3.4/doc/lappend.n new file mode 100644 index 0000000..64f4654 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/lappend.n @@ -0,0 +1,38 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: lappend.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH lappend n "" Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +lappend \- Append list elements onto a variable +.SH SYNOPSIS +\fBlappend \fIvarName \fR?\fIvalue value value ...\fR? +.BE + +.SH DESCRIPTION +.PP +This command treats the variable given by \fIvarName\fR as a list +and appends each of the \fIvalue\fR arguments to that list as a separate +element, with spaces between elements. +If \fIvarName\fR doesn't exist, it is created as a list with elements +given by the \fIvalue\fR arguments. +\fBLappend\fR is similar to \fBappend\fR except that the \fIvalue\fRs +are appended as list elements rather than raw text. +This command provides a relatively efficient way to build up +large lists. For example, ``\fBlappend a $b\fR'' is much +more efficient than ``\fBset a [concat $a [list $b]]\fR'' when +\fB$a\fR is long. + +.SH "SEE ALSO" +list(n), lindex(n), linsert(n), llength(n), lsort(n), lrange(n) + +.SH KEYWORDS +append, element, list, variable diff --git a/mk4/modtcl/tcl8.3.4/doc/library.n b/mk4/modtcl/tcl8.3.4/doc/library.n new file mode 100644 index 0000000..e2d22d6 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/library.n @@ -0,0 +1,311 @@ +'\" +'\" Copyright (c) 1991-1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: library.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +.so man.macros +.TH library n "8.0" Tcl "Tcl Built-In Commands" +.BS +.SH NAME +auto_execok, auto_import, auto_load, auto_mkindex, auto_mkindex_old, auto_qualify, auto_reset, tcl_findLibrary, parray, tcl_endOfWord, tcl_startOfNextWord, tcl_startOfPreviousWord, tcl_wordBreakAfter, tcl_wordBreakBefore \- standard library of Tcl procedures +.SH SYNOPSIS +.nf +\fBauto_execok \fIcmd\fR +\fBauto_import \fIpattern\fR +\fBauto_load \fIcmd\fR +\fBauto_mkindex \fIdir pattern pattern ...\fR +\fBauto_mkindex_old \fIdir pattern pattern ...\fR +\fBauto_qualify \fIcommand namespace\fR +\fBauto_reset\fR +\fBtcl_findLibrary \fIbasename version patch initScript enVarName varName\fR +\fBparray \fIarrayName\fR +.VS +\fBtcl_endOfWord \fIstr start\fR +\fBtcl_startOfNextWord \fIstr start\fR +\fBtcl_startOfPreviousWord \fIstr start\fR +\fBtcl_wordBreakAfter \fIstr start\fR +\fBtcl_wordBreakBefore \fIstr start\fR +.VE +.BE + +.SH INTRODUCTION +.PP +Tcl includes a library of Tcl procedures for commonly-needed functions. +The procedures defined in the Tcl library are generic ones suitable +for use by many different applications. +The location of the Tcl library is returned by the \fBinfo library\fR +command. +In addition to the Tcl library, each application will normally have +its own library of support procedures as well; the location of this +library is normally given by the value of the \fB$\fIapp\fB_library\fR +global variable, where \fIapp\fR is the name of the application. +For example, the location of the Tk library is kept in the variable +\fB$tk_library\fR. +.PP +To access the procedures in the Tcl library, an application should +source the file \fBinit.tcl\fR in the library, for example with +the Tcl command +.CS +\fBsource [file join [info library] init.tcl]\fR +.CE +If the library procedure \fBTcl_Init\fR is invoked from an application's +\fBTcl_AppInit\fR procedure, this happens automatically. +The code in \fBinit.tcl\fR will define the \fBunknown\fR procedure +and arrange for the other procedures to be loaded on-demand using +the auto-load mechanism defined below. + +.SH "COMMAND PROCEDURES" +.PP +The following procedures are provided in the Tcl library: +.TP +\fBauto_execok \fIcmd\fR +Determines whether there is an executable file or shell builtin +by the name \fIcmd\fR. If so, it returns a list of arguments to be +passed to \fBexec\fR to execute the executable file or shell builtin +named by \fIcmd\fR. If not, it returns an empty string. This command +examines the directories in the current search path (given by the PATH +environment variable) in its search for an executable file named +\fIcmd\fR. On Windows platforms, the search is expanded with the same +directories and file extensions as used by \fBexec\fR. \fBAuto_exec\fR +remembers information about previous searches in an array named +\fBauto_execs\fR; this avoids the path search in future calls for the +same \fIcmd\fR. The command \fBauto_reset\fR may be used to force +\fBauto_execok\fR to forget its cached information. +.TP +\fBauto_import \fIpattern\fR +\fBAuto_import\fR is invoked during \fBnamespace import\fR to see if +the imported commands specified by \fIpattern\fR reside in an +autoloaded library. If so, the commands are loaded so that they will +be available to the interpreter for creating the import links. If the +commands do not reside in an autoloaded library, \fBauto_import\fR +does nothing. The pattern matching is performed according to the +matching rules of \fBnamespace import\fR. +.TP +\fBauto_load \fIcmd\fR +This command attempts to load the definition for a Tcl command named +\fIcmd\fR. To do this, it searches an \fIauto-load path\fR, which is +a list of one or more directories. The auto-load path is given by the +global variable \fB$auto_path\fR if it exists. If there is no +\fB$auto_path\fR variable, then the TCLLIBPATH environment variable is +used, if it exists. Otherwise the auto-load path consists of just the +Tcl library directory. Within each directory in the auto-load path +there must be a file \fBtclIndex\fR that describes one or more +commands defined in that directory and a script to evaluate to load +each of the commands. The \fBtclIndex\fR file should be generated +with the \fBauto_mkindex\fR command. If \fIcmd\fR is found in an +index file, then the appropriate script is evaluated to create the +command. The \fBauto_load\fR command returns 1 if \fIcmd\fR was +successfully created. The command returns 0 if there was no index +entry for \fIcmd\fR or if the script didn't actually define \fIcmd\fR +(e.g. because index information is out of date). If an error occurs +while processing the script, then that error is returned. +\fBAuto_load\fR only reads the index information once and saves it in +the array \fBauto_index\fR; future calls to \fBauto_load\fR check for +\fIcmd\fR in the array rather than re-reading the index files. The +cached index information may be deleted with the command +\fBauto_reset\fR. This will force the next \fBauto_load\fR command to +reload the index database from disk. +.TP +\fBauto_mkindex \fIdir pattern pattern ...\fR +Generates an index suitable for use by \fBauto_load\fR. The command +searches \fIdir\fR for all files whose names match any of the +\fIpattern\fR arguments (matching is done with the \fBglob\fR +command), generates an index of all the Tcl command procedures defined +in all the matching files, and stores the index information in a file +named \fBtclIndex\fR in \fIdir\fR. If no pattern is given a pattern of +\fB*.tcl\fR will be assumed. For example, the command +.RS +.CS +\fBauto_mkindex foo *.tcl\fR +.CE +.LP +will read all the \fB.tcl\fR files in subdirectory \fBfoo\fR and +generate a new index file \fBfoo/tclIndex\fR. +.PP +\fBAuto_mkindex\fR parses the Tcl scripts by sourcing them into a +slave interpreter and monitoring the proc and namespace commands that +are executed. Extensions can use the (undocumented) +auto_mkindex_parser package to register other commands that can +contribute to the auto_load index. You will have to read through +auto.tcl to see how this works. +.PP +\fBAuto_mkindex_old\fR parses the Tcl scripts in a relatively +unsophisticated way: if any line contains the word \fBproc\fR +as its first characters then it is assumed to be a procedure +definition and the next word of the line is taken as the +procedure's name. +Procedure definitions that don't appear in this way (e.g. they +have spaces before the \fBproc\fR) will not be indexed. If your +script contains "dangerous" code, such as global initialization +code or procedure names with special characters like \fB$\fR, +\fB*\fR, \fB[\fR or \fB]\fR, you are safer using auto_mkindex_old. +.RE +.TP +\fBauto_reset\fR +Destroys all the information cached by \fBauto_execok\fR and +\fBauto_load\fR. This information will be re-read from disk the next +time it is needed. \fBAuto_reset\fR also deletes any procedures +listed in the auto-load index, so that fresh copies of them will be +loaded the next time that they're used. +.TP +\fBauto_qualify \fIcommand namespace\fR +Computes a list of fully qualified names for \fIcommand\fR. This list +mirrors the path a standard Tcl interpreter follows for command +lookups: first it looks for the command in the current namespace, and +then in the global namespace. Accordingly, if \fIcommand\fR is +relative and \fInamespace\fR is not \fB::\fR, the list returned has +two elements: \fIcommand\fR scoped by \fInamespace\fR, as if it were +a command in the \fInamespace\fR namespace; and \fIcommand\fR as if it +were a command in the global namespace. Otherwise, if either +\fIcommand\fR is absolute (it begins with \fB::\fR), or +\fInamespace\fR is \fB::\fR, the list contains only \fIcommand\fR as +if it were a command in the global namespace. +.RS +.PP +\fBAuto_qualify\fR is used by the auto-loading facilities in Tcl, both +for producing auto-loading indexes such as \fIpkgIndex.tcl\fR, and for +performing the actual auto-loading of functions at runtime. +.RE +.TP +\fBtcl_findLibrary \fIbasename version patch initScript enVarName varName\fR +This is a standard search procedure for use by extensions during +their initialization. They call this procedure to look for their +script library in several standard directories. +The last component of the name of the library directory is +normally \fIbasenameversion\fP +(e.g., tk8.0), but it might be "library" when in the build hierarchies. +The \fIinitScript\fR file will be sourced into the interpreter +once it is found. The directory in which this file is found is +stored into the global variable \fIvarName\fP. +If this variable is already defined (e.g., by C code during +application initialization) then no searching is done. +Otherwise the search looks in these directories: +the directory named by the environment variable \fIenVarName\fP; +relative to the Tcl library directory; +relative to the executable file in the standard installation +bin or bin/\fIarch\fP directory; +relative to the executable file in the current build tree; +relative to the executable file in a parallel build tree. +.TP +\fBparray \fIarrayName\fR +Prints on standard output the names and values of all the elements +in the array \fIarrayName\fR. +\fBArrayName\fR must be an array accessible to the caller of \fBparray\fR. +It may be either local or global. +.TP +\fBtcl_endOfWord \fIstr start\fR +.VS +Returns the index of the first end-of-word location that occurs after +a starting index \fIstart\fR in the string \fIstr\fR. An end-of-word +location is defined to be the first non-word character following the +first word character after the starting point. Returns -1 if there +are no more end-of-word locations after the starting point. See the +description of \fBtcl_wordchars\fR and \fBtcl_nonwordchars\fR below +for more details on how Tcl determines which characters are word +characters. +.TP +\fBtcl_startOfNextWord \fIstr start\fR +Returns the index of the first start-of-word location that occurs +after a starting index \fIstart\fR in the string \fIstr\fR. A +start-of-word location is defined to be the first word character +following a non-word character. Returns \-1 if there are no more +start-of-word locations after the starting point. +.TP +\fBtcl_startOfPreviousWord \fIstr start\fR +Returns the index of the first start-of-word location that occurs +before a starting index \fIstart\fR in the string \fIstr\fR. Returns +\-1 if there are no more start-of-word locations before the starting +point. +.TP +\fBtcl_wordBreakAfter \fIstr start\fR +Returns the index of the first word boundary after the starting index +\fIstart\fR in the string \fIstr\fR. Returns \-1 if there are no more +boundaries after the starting point in the given string. The index +returned refers to the second character of the pair that comprises a +boundary. +.TP +\fBtcl_wordBreakBefore \fIstr start\fR +Returns the index of the first word boundary before the starting index +\fIstart\fR in the string \fIstr\fR. Returns \-1 if there are no more +boundaries before the starting point in the given string. The index +returned refers to the second character of the pair that comprises a +boundary. +.VE + +.SH "VARIABLES" +.PP +The following global variables are defined or used by the procedures in +the Tcl library: +.TP +\fBauto_execs\fR +Used by \fBauto_execok\fR to record information about whether +particular commands exist as executable files. +.TP +\fBauto_index\fR +Used by \fBauto_load\fR to save the index information read from +disk. +.TP +\fBauto_noexec\fR +If set to any value, then \fBunknown\fR will not attempt to auto-exec +any commands. +.TP +\fBauto_noload\fR +If set to any value, then \fBunknown\fR will not attempt to auto-load +any commands. +.TP +\fBauto_path\fR +If set, then it must contain a valid Tcl list giving directories to +search during auto-load operations. +This variable is initialized during startup to contain, in order: +the directories listed in the TCLLIBPATH environment variable, +the directory named by the $tcl_library variable, +the parent directory of $tcl_library, +the directories listed in the $tcl_pkgPath variable. +.TP +\fBenv(TCL_LIBRARY)\fR +If set, then it specifies the location of the directory containing +library scripts (the value of this variable will be +assigned to the \fBtcl_library\fR variable and therefore returned by +the command \fBinfo library\fR). If this variable isn't set then +a default value is used. +.TP +\fBenv(TCLLIBPATH)\fR +If set, then it must contain a valid Tcl list giving directories to +search during auto-load operations. Directories must be specified in +Tcl format, using "/" as the path separator, regardless of platform. +This variable is only used when initializing the \fBauto_path\fR variable. +.TP +\fBtcl_nonwordchars\fR +.VS +This variable contains a regular expression that is used by routines +like \fBtcl_endOfWord\fR to identify whether a character is part of a +word or not. If the pattern matches a character, the character is +considered to be a non-word character. On Windows platforms, spaces, +tabs, and newlines are considered non-word characters. Under Unix, +everything but numbers, letters and underscores are considered +non-word characters. +.TP +\fBtcl_wordchars\fR +This variable contains a regular expression that is used by routines +like \fBtcl_endOfWord\fR to identify whether a character is part of a +word or not. If the pattern matches a character, the character is +considered to be a word character. On Windows platforms, words are +comprised of any character that is not a space, tab, or newline. Under +Unix, words are comprised of numbers, letters or underscores. +.VE +.TP +\fBunknown_pending\fR +Used by \fBunknown\fR to record the command(s) for which it is +searching. +It is used to detect errors where \fBunknown\fR recurses on itself +infinitely. +The variable is unset before \fBunknown\fR returns. + +.SH "SEE ALSO" +info(n), re_syntax(n) + +.SH KEYWORDS +auto-exec, auto-load, library, unknown, word, whitespace diff --git a/mk4/modtcl/tcl8.3.4/doc/license.terms b/mk4/modtcl/tcl8.3.4/doc/license.terms new file mode 100644 index 0000000..9df3e60 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/license.terms @@ -0,0 +1,39 @@ +This software is copyrighted by the Regents of the University of +California, Sun Microsystems, Inc., Scriptics Corporation, +and other parties. The following terms apply to all files associated +with the software unless explicitly disclaimed in individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, provided +that existing copyright notices are retained in all copies and that this +notice is included verbatim in any distributions. No written agreement, +license, or royalty fee is required for any of the authorized uses. +Modifications to this software may be copyrighted by their authors +and need not follow the licensing terms described here, provided that +the new terms are clearly indicated on the first page of each file where +they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE +IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE +NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR +MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" +in the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you +are acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. diff --git a/mk4/modtcl/tcl8.3.4/doc/lindex.n b/mk4/modtcl/tcl8.3.4/doc/lindex.n new file mode 100644 index 0000000..ebaa487 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/lindex.n @@ -0,0 +1,40 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: lindex.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH lindex n 8.2 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +lindex \- Retrieve an element from a list +.SH SYNOPSIS +\fBlindex \fIlist index\fR +.BE + +.SH DESCRIPTION +.PP +This command treats \fIlist\fR as a Tcl list and returns the +\fIindex\fR'th element from it (0 refers to the first element of the list). +In extracting the element, \fIlindex\fR observes the same rules +concerning braces and quotes and backslashes as the Tcl command +interpreter; however, variable +substitution and command substitution do not occur. +If \fIindex\fR is negative or greater than or equal to the number +of elements in \fIvalue\fR, then an empty +string is returned. +If \fIindex\fR has the value \fBend\fR, it refers to the last element +in the list, and \fBend\-\fIinteger\fR refers to the last element in +the list minus the specified integer offset. + +.SH "SEE ALSO" +list(n), lappend(n), linsert(n), llength(n), lsearch(n), lsort(n), +lrange(n), lreplace(n) + +.SH KEYWORDS +element, index, list diff --git a/mk4/modtcl/tcl8.3.4/doc/linsert.n b/mk4/modtcl/tcl8.3.4/doc/linsert.n new file mode 100644 index 0000000..f404773 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/linsert.n @@ -0,0 +1,36 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: linsert.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH linsert n 8.2 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +linsert \- Insert elements into a list +.SH SYNOPSIS +\fBlinsert \fIlist index element \fR?\fIelement element ...\fR? +.BE + +.SH DESCRIPTION +.PP +This command produces a new list from \fIlist\fR by inserting all of the +\fIelement\fR arguments just before the \fIindex\fRth element of +\fIlist\fR. Each \fIelement\fR argument will become a separate element of +the new list. If \fIindex\fR is less than or equal to zero, then the new +elements are inserted at the beginning of the list. If \fIindex\fR has the +value \fBend\fR, or if it is greater than or equal to the number of +elements in the list, then the new elements are appended to the list. +\fBend\-\fIinteger\fR refers to the last element in the list minus the +specified integer offset. + +.SH "SEE ALSO" +list(n), lappend(n), llength(n) + +.SH KEYWORDS +element, insert, list diff --git a/mk4/modtcl/tcl8.3.4/doc/list.n b/mk4/modtcl/tcl8.3.4/doc/list.n new file mode 100644 index 0000000..0f9c2fe --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/list.n @@ -0,0 +1,49 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: list.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH list n "" Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +list \- Create a list +.SH SYNOPSIS +\fBlist \fR?\fIarg arg ...\fR? +.BE + +.SH DESCRIPTION +.PP +This command returns a list comprised of all the \fIarg\fRs, +or an empty string if no \fIarg\fRs are specified. +Braces and backslashes get added as necessary, so that the \fBindex\fR command +may be used on the result to re-extract the original arguments, and also +so that \fBeval\fR may be used to execute the resulting list, with +\fIarg1\fR comprising the command's name and the other \fIarg\fRs comprising +its arguments. \fBList\fR produces slightly different results than +\fBconcat\fR: \fBconcat\fR removes one level of grouping before forming +the list, while \fBlist\fR works directly from the original arguments. +For example, the command +.CS +\fBlist a b {c d e} {f {g h}}\fR +.CE +will return +.CS +\fBa b {c d e} {f {g h}}\fR +.CE +while \fBconcat\fR with the same arguments will return +.CS +\fBa b c d e f {g h}\fR +.CE + +.SH "SEE ALSO" +lappend(n), lindex(n), linsert(n), llength(n), lsearch(n), lsort(n), +lrange(n), lreplace(n) + +.SH KEYWORDS +element, list diff --git a/mk4/modtcl/tcl8.3.4/doc/llength.n b/mk4/modtcl/tcl8.3.4/doc/llength.n new file mode 100644 index 0000000..fa84882 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/llength.n @@ -0,0 +1,29 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: llength.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH llength n "" Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +llength \- Count the number of elements in a list +.SH SYNOPSIS +\fBllength \fIlist\fR +.BE + +.SH DESCRIPTION +.PP +Treats \fIlist\fR as a list and returns a decimal string giving +the number of elements in it. + +.SH "SEE ALSO" +list(n), lindex(n), lrange(n) + +.SH KEYWORDS +element, list, length diff --git a/mk4/modtcl/tcl8.3.4/doc/load.n b/mk4/modtcl/tcl8.3.4/doc/load.n new file mode 100644 index 0000000..20835aa --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/load.n @@ -0,0 +1,135 @@ +'\" +'\" Copyright (c) 1995-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: load.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH load n 7.5 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +load \- Load machine code and initialize new commands. +.SH SYNOPSIS +\fBload \fIfileName\fR +.br +\fBload \fIfileName packageName\fR +.br +\fBload \fIfileName packageName interp\fR +.BE + +.SH DESCRIPTION +.PP +This command loads binary code from a file into the +application's address space and calls an initialization procedure +in the package to incorporate it into an interpreter. \fIfileName\fR +is the name of the file containing the code; its exact form varies +from system to system but on most systems it is a shared library, +such as a \fB.so\fR file under Solaris or a DLL under Windows. +\fIpackageName\fR is the name of the package, and is used to +compute the name of an initialization procedure. +\fIinterp\fR is the path name of the interpreter into which to load +the package (see the \fBinterp\fR manual entry for details); +if \fIinterp\fR is omitted, it defaults to the +interpreter in which the \fBload\fR command was invoked. +.PP +Once the file has been loaded into the application's address space, +one of two initialization procedures will be invoked in the new code. +Typically the initialization procedure will add new commands to a +Tcl interpreter. +The name of the initialization procedure is determined by +\fIpackageName\fR and whether or not the target interpreter +is a safe one. For normal interpreters the name of the initialization +procedure will have the form \fIpkg\fB_Init\fR, where \fIpkg\fR +is the same as \fIpackageName\fR except that the first letter is +converted to upper case and all other letters +are converted to lower case. For example, if \fIpackageName\fR is +\fBfoo\fR or \fBFOo\fR, the initialization procedure's name will +be \fBFoo_Init\fR. +.PP +If the target interpreter is a safe interpreter, then the name +of the initialization procedure will be \fIpkg\fB_SafeInit\fR +instead of \fIpkg\fB_Init\fR. +The \fIpkg\fB_SafeInit\fR function should be written carefully, so that it +initializes the safe interpreter only with partial functionality provided +by the package that is safe for use by untrusted code. For more information +on Safe\-Tcl, see the \fBsafe\fR manual entry. +.PP +The initialization procedure must match the following prototype: +.CS +typedef int Tcl_PackageInitProc(Tcl_Interp *\fIinterp\fR); +.CE +The \fIinterp\fR argument identifies the interpreter in which the +package is to be loaded. The initialization procedure must return +\fBTCL_OK\fR or \fBTCL_ERROR\fR to indicate whether or not it completed +successfully; in the event of an error it should set the interpreter's result +to point to an error message. The result of the \fBload\fR command +will be the result returned by the initialization procedure. +.PP +The actual loading of a file will only be done once for each \fIfileName\fR +in an application. If a given \fIfileName\fR is loaded into multiple +interpreters, then the first \fBload\fR will load the code and +call the initialization procedure; subsequent \fBload\fRs will +call the initialization procedure without loading the code again. +It is not possible to unload or reload a package. +.PP +The \fBload\fR command also supports packages that are statically +linked with the application, if those packages have been registered +by calling the \fBTcl_StaticPackage\fR procedure. +If \fIfileName\fR is an empty string, then \fIpackageName\fR must +be specified. +.PP +If \fIpackageName\fR is omitted or specified as an empty string, +Tcl tries to guess the name of the package. +This may be done differently on different platforms. +The default guess, which is used on most UNIX platforms, is to +take the last element of \fIfileName\fR, strip off the first +three characters if they are \fBlib\fR, and use any following +.VS +alphabetic and underline characters as the module name. +.VE +For example, the command \fBload libxyz4.2.so\fR uses the module +name \fBxyz\fR and the command \fBload bin/last.so {}\fR uses the +module name \fBlast\fR. +.VS "" br +.PP +If \fIfileName\fR is an empty string, then \fIpackageName\fR must +be specified. +The \fBload\fR command first searches for a statically loaded package +(one that has been registered by calling the \fBTcl_StaticPackage\fR +procedure) by that name; if one is found, it is used. +Otherwise, the \fBload\fR command searches for a dynamically loaded +package by that name, and uses it if it is found. If several +different files have been \fBload\fRed with different versions of +the package, Tcl picks the file that was loaded first. +.VE + +.SH "PORTABILITY ISSUES" +.TP +\fBWindows\fR\0\0\0\0\0 +. +When a load fails with "library not found" error, it is also possible +that a dependent library was not found. To see the dependent libraries, +type ``dumpbin -imports '' in a DOS console to see what the +library must import. +When loading a DLL in the current directory, Windows will ignore ``./'' as +a path specifier and use a search heuristic to find the DLL instead. +To avoid this, load the DLL with +.CS + load [file join [pwd] mylib.DLL] +.CE + +.SH BUGS +.PP +If the same file is \fBload\fRed by different \fIfileName\fRs, it will +be loaded into the process's address space multiple times. The +behavior of this varies from system to system (some systems may +detect the redundant loads, others may not). + +.SH "SEE ALSO" +\fBinfo sharedlibextension\fR, Tcl_StaticPackage(3), safe(n) + +.SH KEYWORDS +binary code, loading, safe interpreter, shared library diff --git a/mk4/modtcl/tcl8.3.4/doc/lrange.n b/mk4/modtcl/tcl8.3.4/doc/lrange.n new file mode 100644 index 0000000..de74553 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/lrange.n @@ -0,0 +1,42 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: lrange.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH lrange n 7.4 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +lrange \- Return one or more adjacent elements from a list +.SH SYNOPSIS +\fBlrange \fIlist first last\fR +.BE + +.SH DESCRIPTION +.PP +\fIList\fR must be a valid Tcl list. This command will +return a new list consisting of elements +\fIfirst\fR through \fIlast\fR, inclusive. +\fIFirst\fR or \fIlast\fR +may be \fBend\fR (or any abbreviation of it) to refer to the last +element of the list. +If \fIfirst\fR is less than zero, it is treated as if it were zero. +If \fIlast\fR is greater than or equal to the number of elements +in the list, then it is treated as if it were \fBend\fR. +If \fIfirst\fR is greater than \fIlast\fR then an empty string +is returned. +Note: ``\fBlrange \fIlist first first\fR'' does not always produce the +same result as ``\fBlindex \fIlist first\fR'' (although it often does +for simple fields that aren't enclosed in braces); it does, however, +produce exactly the same results as ``\fBlist [lindex \fIlist first\fB]\fR'' + +.SH "SEE ALSO" +lappend(n), lindex(n), linsert(n), list(n), llength(n), lreplace(n) + +.SH KEYWORDS +element, list, range, sublist diff --git a/mk4/modtcl/tcl8.3.4/doc/lreplace.n b/mk4/modtcl/tcl8.3.4/doc/lreplace.n new file mode 100644 index 0000000..bca9870 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/lreplace.n @@ -0,0 +1,51 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: lreplace.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH lreplace n 7.4 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +lreplace \- Replace elements in a list with new elements +.SH SYNOPSIS +\fBlreplace \fIlist first last \fR?\fIelement element ...\fR? +.BE + +.SH DESCRIPTION +.PP +\fBlreplace\fR returns a new list formed by replacing one or more elements of +\fIlist\fR with the \fIelement\fR arguments. +\fIfirst\fR and \fIlast\fR specify the first and last index of the +range of elements to replace. 0 refers to the first element of the +list, and \fBend\fR (or any abbreviation of it) may be used to refer +to the last element of the list. If \fIlist\fR is empty, then +\fIfirst\fR and \fIlast\fR are ignored. + +If \fIfirst\fR is less than zero, it is considered to refer to the +first element of the list. For non-empty lists, the element indicated +by \fIfirst\fR must exist. + +If \fIlast\fR is less than zero but greater than \fIfirst\fR, then any +specified elements will be prepended to the list. If \fIlast\fR is +less than \fIfirst\fR then no elements are deleted; the new elements +are simply inserted before \fIfirst\fR. + +The \fIelement\fR arguments specify zero or more new arguments to +be added to the list in place of those that were deleted. +Each \fIelement\fR argument will become a separate element of +the list. If no \fIelement\fR arguments are specified, then the elements +between \fIfirst\fR and \fIlast\fR are simply deleted. If \fIlist\fR +is empty, any \fIelement\fR arguments are added to the end of the list. + +.SH "SEE ALSO" +lappend(n), lindex(n), linsert(n), list(n), llength(n), lrange(n), +lsearch(n), lsort(n) + +.SH KEYWORDS +element, list, replace diff --git a/mk4/modtcl/tcl8.3.4/doc/lsearch.n b/mk4/modtcl/tcl8.3.4/doc/lsearch.n new file mode 100644 index 0000000..c37e904 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/lsearch.n @@ -0,0 +1,46 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: lsearch.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH lsearch n 7.0 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +lsearch \- See if a list contains a particular element +.SH SYNOPSIS +\fBlsearch \fR?\fImode\fR? \fIlist pattern\fR +.BE + +.SH DESCRIPTION +.PP +This command searches the elements of \fIlist\fR to see if one +of them matches \fIpattern\fR. +If so, the command returns the index of the first matching +element. +If not, the command returns \fB\-1\fR. +The \fImode\fR argument indicates how the elements of the list are to +be matched against \fIpattern\fR and it must have one of the following +values: +.TP +\fB\-exact\fR +The list element must contain exactly the same string as \fIpattern\fR. +.TP +\fB\-glob\fR +\fIPattern\fR is a glob-style pattern which is matched against each list +element using the same rules as the \fBstring match\fR command. +.TP +\fB\-regexp\fR +\fIPattern\fR is treated as a regular expression and matched against +each list element using the rules described in the \fBre_syntax\fR +reference page. +.PP +If \fImode\fR is omitted then it defaults to \fB\-glob\fR. + +.SH KEYWORDS +list, match, pattern, regular expression, search, string diff --git a/mk4/modtcl/tcl8.3.4/doc/lsort.n b/mk4/modtcl/tcl8.3.4/doc/lsort.n new file mode 100644 index 0000000..496256f --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/lsort.n @@ -0,0 +1,191 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" Copyright (c) 1999 Scriptics Corporation +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: lsort.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH lsort n 8.3 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +lsort \- Sort the elements of a list +.SH SYNOPSIS +\fBlsort \fR?\fIoptions\fR? \fIlist\fR +.BE + +.SH DESCRIPTION +.PP +This command sorts the elements of \fIlist\fR, returning a new +list in sorted order. The implementation of the \fBlsort\fR command +uses the merge\-sort algorithm which is a stable sort that has O(n log +n) performance characteristics. +.PP +By default ASCII sorting is used with the result returned in +increasing order. However, any of the following options may be +specified before \fIlist\fR to control the sorting process (unique +abbreviations are accepted): +.TP 20 +\fB\-ascii\fR +Use string comparison with ASCII collation order. This is the default. +.TP 20 +\fB\-dictionary\fR +Use dictionary-style comparison. This is the same as \fB\-ascii\fR +except (a) case is ignored except as a tie-breaker and (b) if two +strings contain embedded numbers, the numbers compare as integers, +not characters. For example, in \fB\-dictionary\fR mode, \fBbigBoy\fR +sorts between \fBbigbang\fR and \fBbigboy\fR, and \fBx10y\fR +sorts between \fBx9y\fR and \fBx11y\fR. +.TP 20 +\fB\-integer\fR +Convert list elements to integers and use integer comparison. +.TP 20 +\fB\-real\fR +Convert list elements to floating-point values and use floating comparison. +.TP 20 +\fB\-command\0\fIcommand\fR +Use \fIcommand\fR as a comparison command. +To compare two elements, evaluate a Tcl script consisting of +\fIcommand\fR with the two elements appended as additional +arguments. The script should return an integer less than, +equal to, or greater than zero if the first element is to +be considered less than, equal to, or greater than the second, +respectively. +.TP 20 +\fB\-increasing\fR +Sort the list in increasing order (``smallest'' items first). +This is the default. +.TP 20 +\fB\-decreasing\fR +Sort the list in decreasing order (``largest'' items first). +.TP 20 +\fB\-index\0\fIindex\fR +If this option is specified, each of the elements of \fIlist\fR must +itself be a proper Tcl sublist. Instead of sorting based on whole +sublists, \fBlsort\fR will extract the \fIindex\fR'th element from +each sublist and sort based on the given element. The keyword +\fBend\fP is allowed for the \fIindex\fP to sort on the last sublist +element, +.VS 8.3.4 +and \fBend-\fIindex\fR sorts on a sublist element offset from +the end. +.VE +For example, +.RS +.CS +lsort -integer -index 1 {{First 24} {Second 18} {Third 30}} +.CE +returns \fB{Second 18} {First 24} {Third 30}\fR, and +.VS 8.3.4 +'\" +'\" This example is from the test suite! +'\" +.CS +lsort -index end-1 {{a 1 e i} {b 2 3 f g} {c 4 5 6 d h}} +.CE +returns \fB{c 4 5 6 d h} {a 1 e i} {b 2 3 f g}\fR. +.VE +This option is much more efficient than using \fB\-command\fR +to achieve the same effect. +.RE +.TP 20 +\fB\-unique\fR +If this option is specified, then only the last set of duplicate +elements found in the list will be retained. Note that duplicates are +determined relative to the comparison used in the sort. Thus if +\fI-index 0\fR is used, \fB{1 a}\fR and \fB{1 b}\fR would be +considered duplicates and only the second element, \fB{1 b}\fR, would +be retained. + +.SH "NOTES" +.PP +The options to \fBlsort\fR only control what sort of comparison is +used, and do not necessarily constrain what the values themselves +actually are. This distinction is only noticeable when the list to be +sorted has fewer than two elements. +.PP +The \fBlsort\fR command is reentrant, meaning it is safe to use as +part of the implementation of a command used in the \fB\-command\fR +option. + +.SH "EXAMPLES" + +.PP +Sorting a list using ASCII sorting: +.CS +% lsort {a10 B2 b1 a1 a2} +B2 a1 a10 a2 b1 +.CE + +.PP +Sorting a list using Dictionary sorting: +.CS +% lsort -dictionary {a10 B2 b1 a1 a2} +a1 a2 a10 b1 B2 +.CE + +.PP +Sorting lists of integers: +.CS +% lsort -integer {5 3 1 2 11 4} +1 2 3 4 5 11 +% lsort -integer {1 2 0x5 7 0 4 -1} +-1 0 1 2 4 0x5 7 +.CE + +.PP +Sorting lists of floating-point numbers: +.CS +% lsort -real {5 3 1 2 11 4} +1 2 3 4 5 11 +% lsort -real {.5 0.07e1 0.4 6e-1} +0.4 .5 6e-1 0.07e1 +.CE + +.PP +Sorting using indices: +.CS +% # Note the space character before the c +% lsort {{a 5} { c 3} {b 4} {e 1} {d 2}} +{ c 3} {a 5} {b 4} {d 2} {e 1} +% lsort -index 0 {{a 5} { c 3} {b 4} {e 1} {d 2}} +{a 5} {b 4} { c 3} {d 2} {e 1} +% lsort -index 1 {{a 5} { c 3} {b 4} {e 1} {d 2}} +{e 1} {d 2} { c 3} {b 4} {a 5} +.CE + +.PP +Stripping duplicate values using sorting: +.CS +% lsort -unique {a b c a b c a b c} +a b c +.CE + +.PP +More complex sorting using a comparison function: +.CS +% proc compare {a b} { + set a0 [lindex $a 0] + set b0 [lindex $b 0] + if {$a0 < $b0} { + return -1 + } elseif {$a0 > $b0} { + return 1 + } + return [string compare [lindex $a 1] [lindex $b 1]] +} +% lsort -command compare \\ + {{3 apple} {0x2 carrot} {1 dingo} {2 banana}} +{1 dingo} {2 banana} {0x2 carrot} {3 apple} +.CE + +.SH "SEE ALSO" +lappend(n), lindex(n), linsert(n), list(n), llength(n), lrange(n), +lreplace(n), lsearch(n) + +.SH KEYWORDS +element, list, order, sort diff --git a/mk4/modtcl/tcl8.3.4/doc/man.macros b/mk4/modtcl/tcl8.3.4/doc/man.macros new file mode 100644 index 0000000..4fd1b4b --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/man.macros @@ -0,0 +1,236 @@ +'\" The definitions below are for supplemental macros used in Tcl/Tk +'\" manual entries. +'\" +'\" .AP type name in/out ?indent? +'\" Start paragraph describing an argument to a library procedure. +'\" type is type of argument (int, etc.), in/out is either "in", "out", +'\" or "in/out" to describe whether procedure reads or modifies arg, +'\" and indent is equivalent to second arg of .IP (shouldn't ever be +'\" needed; use .AS below instead) +'\" +'\" .AS ?type? ?name? +'\" Give maximum sizes of arguments for setting tab stops. Type and +'\" name are examples of largest possible arguments that will be passed +'\" to .AP later. If args are omitted, default tab stops are used. +'\" +'\" .BS +'\" Start box enclosure. From here until next .BE, everything will be +'\" enclosed in one large box. +'\" +'\" .BE +'\" End of box enclosure. +'\" +'\" .CS +'\" Begin code excerpt. +'\" +'\" .CE +'\" End code excerpt. +'\" +'\" .VS ?version? ?br? +'\" Begin vertical sidebar, for use in marking newly-changed parts +'\" of man pages. The first argument is ignored and used for recording +'\" the version when the .VS was added, so that the sidebars can be +'\" found and removed when they reach a certain age. If another argument +'\" is present, then a line break is forced before starting the sidebar. +'\" +'\" .VE +'\" End of vertical sidebar. +'\" +'\" .DS +'\" Begin an indented unfilled display. +'\" +'\" .DE +'\" End of indented unfilled display. +'\" +'\" .SO +'\" Start of list of standard options for a Tk widget. The +'\" options follow on successive lines, in four columns separated +'\" by tabs. +'\" +'\" .SE +'\" End of list of standard options for a Tk widget. +'\" +'\" .OP cmdName dbName dbClass +'\" Start of description of a specific option. cmdName gives the +'\" option's name as specified in the class command, dbName gives +'\" the option's name in the option database, and dbClass gives +'\" the option's class in the option database. +'\" +'\" .UL arg1 arg2 +'\" Print arg1 underlined, then print arg2 normally. +'\" +'\" RCS: @(#) $Id: man.macros,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +'\" # Set up traps and other miscellaneous stuff for Tcl/Tk man pages. +.if t .wh -1.3i ^B +.nr ^l \n(.l +.ad b +'\" # Start an argument description +.de AP +.ie !"\\$4"" .TP \\$4 +.el \{\ +. ie !"\\$2"" .TP \\n()Cu +. el .TP 15 +.\} +.ta \\n()Au \\n()Bu +.ie !"\\$3"" \{\ +\&\\$1 \\fI\\$2\\fP (\\$3) +.\".b +.\} +.el \{\ +.br +.ie !"\\$2"" \{\ +\&\\$1 \\fI\\$2\\fP +.\} +.el \{\ +\&\\fI\\$1\\fP +.\} +.\} +.. +'\" # define tabbing values for .AP +.de AS +.nr )A 10n +.if !"\\$1"" .nr )A \\w'\\$1'u+3n +.nr )B \\n()Au+15n +.\" +.if !"\\$2"" .nr )B \\w'\\$2'u+\\n()Au+3n +.nr )C \\n()Bu+\\w'(in/out)'u+2n +.. +.AS Tcl_Interp Tcl_CreateInterp in/out +'\" # BS - start boxed text +'\" # ^y = starting y location +'\" # ^b = 1 +.de BS +.br +.mk ^y +.nr ^b 1u +.if n .nf +.if n .ti 0 +.if n \l'\\n(.lu\(ul' +.if n .fi +.. +'\" # BE - end boxed text (draw box now) +.de BE +.nf +.ti 0 +.mk ^t +.ie n \l'\\n(^lu\(ul' +.el \{\ +.\" Draw four-sided box normally, but don't draw top of +.\" box if the box started on an earlier page. +.ie !\\n(^b-1 \{\ +\h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' +.\} +.el \}\ +\h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' +.\} +.\} +.fi +.br +.nr ^b 0 +.. +'\" # VS - start vertical sidebar +'\" # ^Y = starting y location +'\" # ^v = 1 (for troff; for nroff this doesn't matter) +.de VS +.if !"\\$2"" .br +.mk ^Y +.ie n 'mc \s12\(br\s0 +.el .nr ^v 1u +.. +'\" # VE - end of vertical sidebar +.de VE +.ie n 'mc +.el \{\ +.ev 2 +.nf +.ti 0 +.mk ^t +\h'|\\n(^lu+3n'\L'|\\n(^Yu-1v\(bv'\v'\\n(^tu+1v-\\n(^Yu'\h'-|\\n(^lu+3n' +.sp -1 +.fi +.ev +.\} +.nr ^v 0 +.. +'\" # Special macro to handle page bottom: finish off current +'\" # box/sidebar if in box/sidebar mode, then invoked standard +'\" # page bottom macro. +.de ^B +.ev 2 +'ti 0 +'nf +.mk ^t +.if \\n(^b \{\ +.\" Draw three-sided box if this is the box's first page, +.\" draw two sides but no top otherwise. +.ie !\\n(^b-1 \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c +.el \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c +.\} +.if \\n(^v \{\ +.nr ^x \\n(^tu+1v-\\n(^Yu +\kx\h'-\\nxu'\h'|\\n(^lu+3n'\ky\L'-\\n(^xu'\v'\\n(^xu'\h'|0u'\c +.\} +.bp +'fi +.ev +.if \\n(^b \{\ +.mk ^y +.nr ^b 2 +.\} +.if \\n(^v \{\ +.mk ^Y +.\} +.. +'\" # DS - begin display +.de DS +.RS +.nf +.sp +.. +'\" # DE - end display +.de DE +.fi +.RE +.sp +.. +'\" # SO - start of list of standard options +.de SO +.SH "STANDARD OPTIONS" +.LP +.nf +.ta 5.5c 11c +.ft B +.. +'\" # SE - end of list of standard options +.de SE +.fi +.ft R +.LP +See the \\fBoptions\\fR manual entry for details on the standard options. +.. +'\" # OP - start of full description for a single option +.de OP +.LP +.nf +.ta 4c +Command-Line Name: \\fB\\$1\\fR +Database Name: \\fB\\$2\\fR +Database Class: \\fB\\$3\\fR +.fi +.IP +.. +'\" # CS - begin code excerpt +.de CS +.RS +.nf +.ta .25i .5i .75i 1i +.. +'\" # CE - end code excerpt +.de CE +.fi +.RE +.. +.de UL +\\$1\l'|0\(ul'\\$2 +.. diff --git a/mk4/modtcl/tcl8.3.4/doc/memory.n b/mk4/modtcl/tcl8.3.4/doc/memory.n new file mode 100644 index 0000000..e815bb6 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/memory.n @@ -0,0 +1,80 @@ +'\" +'\" Copyright (c) 1992-1999 by Karl Lehenbauer and Mark Diekhans +'\" Copyright (c) 2000 by Scriptics Corporation. +'\" All rights reserved. +'\" +'\" RCS: @(#) $Id: memory.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH memory n 8.1 Tcl "Tcl Built-In Commands" +.BS +.SH NAME +memory \- Control Tcl memory debugging capabilities. +.SH SYNOPSIS +\fBmemory \fIoption \fR?\fIarg arg ...\fR? + +.SH DESCRIPTION +.PP +The \fBmemory\fR command gives the Tcl developer control of Tcl's memory +debugging capabilities. The memory command has several suboptions, which are +described below. It is only available when Tcl has been compiled with +memory debugging enabled (when \fBTCL_MEM_DEBUG\fR is defined at +compile time). +.TP +\fBmemory info\fR +Produces a report containing the total allocations and frees since +Tcl began, the current packets allocated (the current +number of calls to \fBckalloc\fR not met by a corresponding call +to \fBckfree\fR), the current bytes allocated, and the maximum number +of packets and bytes allocated. +.TP +\fBmemory trace [on|off]\fR +.br +Turns memory tracing on or off. When memory tracing is on, every call +to \fBckalloc\fR causes a line of trace information to be written to +\fIstderr\fR, consisting of the word \fIckalloc\fR, followed by the +address returned, the amount of memory allocated, and the C filename +and line number of the code performing the allocation. For example: +.CS +ckalloc 40e478 98 tclProc.c 1406 +.CE +Calls to \fBckfree\fR are traced in the same manner. +.TP +\fBmemory validate [on|off]\fR +Turns memory validation on or off. When memory validation is enabled, +on every call to \fBckalloc\fR or \fBckfree\fR, the guard zones are +checked for every piece of memory currently in existence that was +allocated by \fBckalloc\fR. This has a large performance impact and +should only be used when overwrite problems are strongly suspected. +The advantage of enabling memory validation is that a guard zone +overwrite can be detected on the first call to \fBckalloc\fR or +\fBckfree\fR after the overwrite occurred, rather than when the +specific memory with the overwritten guard zone(s) is freed, which may +occur long after the overwrite occurred. +.TP +\fBmemory trace_on_at_malloc\fR \fIcount\fR +Enable memory tracing after \fIcount\fR \fBckalloc\fR's have been performed. +For example, if you enter \fBmemory trace_on_at_malloc 100\fR, +after the 100th call to \fBckalloc\fR, memory trace information will begin +being displayed for all allocations and frees. Since there can be a lot +of memory activity before a problem occurs, judicious use of this option +can reduce the slowdown caused by tracing (and the amount of trace information +produced), if you can identify a number of allocations that occur before +the problem sets in. The current number of memory allocations that have +occurred since Tcl started is printed on a guard zone failure. +.TP +\fBmemory break_on_malloc\fR \fIcount\fR +After the \fBcount\fR allocations have been performed, \fBckalloc\fR's +output a message to this effect and that it is now attempting to enter +the C debugger. Tcl will then issue a \fISIGINT\fR signal against itself. +If you are running Tcl under a C debugger, it should then enter the debugger +command mode. +.TP +\fB memory display\fR \fIfile\fR +Write a list of all currently allocated memory to the specified file. + +.SH "SEE ALSO" +ckalloc, ckfree, Tcl_ValidateAllMemory, Tcl_DumpActiveMemory, TCL_MEM_DEBUG + +.SH KEYWORDS +memory, debug diff --git a/mk4/modtcl/tcl8.3.4/doc/msgcat.n b/mk4/modtcl/tcl8.3.4/doc/msgcat.n new file mode 100644 index 0000000..37c2a76 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/msgcat.n @@ -0,0 +1,244 @@ +'\" +'\" Copyright (c) 1998 Mark Harrison. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" SCCS: @(#) msgcat.n +'\" +.so man.macros +.TH "msgcat" n 8.1 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +msgcat \- Tcl message catalog +.SH SYNOPSIS +\fB::msgcat::mc \fIsrc-string\fR +.sp +\fB::msgcat::mclocale \fR?\fInewLocale\fR? +.sp +\fB::msgcat::mcpreferences\fR +.sp +\fB::msgcat::mcload \fIdirname\fR +.sp +\fB::msgcat::mcset \fIlocale src-string \fR?\fItranslate-string\fR? +.sp +\fB::msgcat::mcunknown \fIlocale src-string\fR +.BE + +.SH DESCRIPTION +.PP +The \fBmsgcat\fR package provides a set of functions +that can be used to manage multi-lingual user interfaces. +Text strings are defined in a ``message catalog'' which +is independent from the application, and +which can be edited or localized without modifying +the application source code. New languages +or locales are provided by adding a new file to +the message catalog. +.PP +Use of the message catalog is optional by any application +or package, but is encouraged if the application or package +wishes to be enabled for multi-lingual applications. + +.SH COMMANDS +.TP +\fB::msgcat::mc \fIsrc-string\fR ?\fIarg arg ...\fR? +Returns a translation of \fIsrc-string\fR according to the +user's current locale. If additional arguments past \fIsrc-string\fR +are given, the \fBformat\fR command is used to substitute the +additional arguments in the translation of \fIsrc-string\fR. + +\fB::msgcat::mc\fR will search the messages defined +in the current namespace for a translation of \fIsrc-string\fR; if +none is found, it will search in the parent of the current namespace, +and so on until it reaches the global namespace. If no translation +string exists, \fB::msgcat::mcunknown\fR is called and the string +returned from \fB::msgcat::mcunknown\fR is returned. +.PP +\fB::msgcat::mc\fR is the main function used to localize an +application. Instead of using an English string directly, an +applicaton can pass the English string through \fB::msgcat::mc\fR and +use the result. If an application is written for a single language in +this fashion, then it is easy to add support for additional languages +later simply by defining new message catalog entries. +.TP +\fB::msgcat::mclocale \fR?\fInewLocale\fR? +This function sets the locale to \fInewLocale\fR. If \fInewLocale\fR +is omitted, the current locale is returned, otherwise the current locale +is set to \fInewLocale\fR. +The initial locale defaults to the locale specified in +the user's environment. See \fBLOCALE AND SUBLOCALE SPECIFICATION\fR +below for a description of the locale string format. +.TP +\fB::msgcat::mcpreferences\fR +Returns an ordered list of the locales preferred by +the user, based on the user's language specification. +The list is ordered from most specific to least +preference. If the user has specified LANG=en_US_funky, +this procedure would return {en_US_funky en_US en}. +.TP +\fB::msgcat::mcload \fIdirname\fR +Searches the specified directory for files that match +the language specifications returned by \fB::msgcat::mcpreferences\fR. +Each file located is sourced. The file extension is ``.msg''. +The number of message files which matched the specification +and were loaded is returned. +.TP +\fB::msgcat::mcset \fIlocale src-string \fR?\fItranslate-string\fR? +Sets the translation for \fIsrc-string\fR to \fItranslate-string\fR +in the specified \fIlocale\fR. If \fItranslate-string\fR is not +specified, \fIsrc-string\fR is used for both. The function +returns \fItranslate-string\fR. +.TP +\fB::msgcat::mcunknown \fIlocale src-string\fR +This routine is called by \fB::msgcat::mc\fR in the case when +a translation for \fIsrc-string\fR is not defined in the +current locale. The default action is to return +\fIsrc-string\fR. This procedure can be redefined by the +application, for example to log error messages for each unknown +string. The \fB::msgcat::mcunknown\fR procedure is invoked at the +same stack context as the call to \fB::msgcat::mc\fR. The return vaue +of \fB::msgcat::mcunknown\fR is used as the return vaue for the call +to \fB::msgcat::mc\fR. + +.SH "LOCALE AND SUBLOCALE SPECIFICATION" +.PP +The locale is specified by a locale string. +The locale string consists of +a language code, an optional country code, and an optional +system-specific code, each separated by ``_''. The country and language +codes are specified in standards ISO-639 and ISO-3166. +For example, the locale ``en'' specifies English and + ``en_US'' specifes U.S. English. +.PP +The locale defaults to the value in \fBenv(LANG)\fR at the time the +\fBmsgcat\fR package is loaded. If \fBenv(LANG)\fR is not defined, then the +locale defaults to ``C''. +.PP +When a locale is specified by the user, a ``best match'' search is +performed during string translation. For example, if a user specifies +en_UK_Funky, the locales ``en_UK_Funky'', ``en_UK'', and ``en'' are +searched in order until a matching translation string is found. If no +translation string is available, then \fB::msgcat::unknown\fR is +called. + +.SH "NAMESPACES AND MESSAGE CATALOGS" +.PP +Strings stored in the message catalog are stored relative +to the namespace from which they were added. This allows +multiple packages to use the same strings without fear +of collisions with other packages. It also allows the +source string to be shorter and less prone to typographical +error. +.PP +For example, executing the code +.CS +mcset en hello "hello from ::" +namespace eval foo {mcset en hello "hello from ::foo"} +puts [mc hello] +namespace eval foo {puts [mc hello]} +.CE +will print +.CS +hello from :: +hello from ::foo +.CE +.PP +When searching for a translation of a message, the +message catalog will search first the current namespace, +then the parent of the current namespace, and so on until +the global namespace is reached. This allows child namespaces +to "inherit" messages from their parent namespace. +.PP +For example, executing the code +.CS +mcset en m1 ":: message1" +mcset en m2 ":: message2" +mcset en m3 ":: message3" +namespace eval ::foo { + mcset en m2 "::foo message2" + mcset en m3 "::foo message3" +} +namespace eval ::foo::bar { + mcset en m3 "::foo::bar message3" +} +puts "[mc m1]; [mc m2]; [mc m3]" +namespace eval ::foo {puts "[mc m1]; [mc m2]; [mc m3]"} +namespace eval ::foo::bar {puts "[mc m1]; [mc m2]; [mc m3]"} +.CE +will print +.CS +:: message1; :: message2; :: message3 +:: message1; ::foo message2; ::foo message3 +:: message1; ::foo message2; ::foo::bar message3 +.CE + +.SH "LOCATION AND FORMAT OF MESSAGE FILES" +.PP +Message files can be located in any directory, subject +to the following conditions: +.IP [1] +All message files for a package are in the same directory. +.IP [2] +The message file name is a locale specifier followed +by ``.msg''. For example: +.CS +es.msg -- spanish +en_UK.msg -- UK English +.CE +.IP [3] +The file contains a series of calls to mcset, setting the +necessary translation strings for the language. For example: +.CS +::msgcat::mcset es "Free Beer!" "Cerveza Gracias!" +.CE + +.SH "RECOMMENDED MESSAGE SETUP FOR PACKAGES" +.PP +If a package is installed into a subdirectory of the +\fBtcl_pkgPath\fR and loaded via \fBpackage require\fR, the +following procedure is recommended. +.IP [1] +During package installation, create a subdirectory +\fBmsgs\fR under your package directory. +.IP [2] +Copy your *.msg files into that directory. +.IP [3] + Add the following command to your package +initialization script: +.CS +# load language files, stored in msgs subdirectory +::msgcat::mcload [file join [file dirname [info script]] msgs] +.CE + +.SH "POSTITIONAL CODES FOR FORMAT AND SCAN COMMANDS" +.PP +It is possible that a message string used as an argument +to \fBformat\fR might have positionally dependent parameters that +might need to be repositioned. For example, it might be +syntactically desirable to rearrange the sentence structure +while translating. +.CS +format "We produced %d units in location %s" $num $city +format "In location %s we produced %d units" $city $num +.CE +.PP +This can be handled by using the positional +parameters: +.CS +format "We produced %1\\$d units in location %2\\$s" $num $city +format "In location %2\\$s we produced %1\\$d units" $num $city +.CE +.PP +Similarly, positional parameters can be used with \fBscan\fR to +extract values from internationalized strings. + +.SH CREDITS +.PP +The message catalog code was developed by Mark Harrison. + +.SH "SEE ALSO" +format(n), scan(n), namespace(n), package(n) +.SH KEYWORDS +internationalization, i18n, localization, l10n, message, text, translation diff --git a/mk4/modtcl/tcl8.3.4/doc/namespace.n b/mk4/modtcl/tcl8.3.4/doc/namespace.n new file mode 100644 index 0000000..bb749d2 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/namespace.n @@ -0,0 +1,566 @@ +'\" +'\" Copyright (c) 1993-1997 Bell Labs Innovations for Lucent Technologies +'\" Copyright (c) 1997 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: namespace.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH namespace n 8.0 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +namespace \- create and manipulate contexts for commands and variables +.SH SYNOPSIS +\fBnamespace \fR?\fIoption\fR? ?\fIarg ...\fR? +.BE + +.SH DESCRIPTION +.PP +The \fBnamespace\fR command lets you create, access, and destroy +separate contexts for commands and variables. +See the section \fBWHAT IS A NAMESPACE?\fR below +for a brief overview of namespaces. +The legal \fIoption\fR's are listed below. +Note that you can abbreviate the \fIoption\fR's. +.TP +\fBnamespace children \fR?\fInamespace\fR? ?\fIpattern\fR? +Returns a list of all child namespaces that belong to the +namespace \fInamespace\fR. +If \fInamespace\fR is not specified, +then the children are returned for the current namespace. +This command returns fully-qualified names, +which start with \fB::\fR. +If the optional \fIpattern\fR is given, +then this command returns only the names that match the glob-style pattern. +The actual pattern used is determined as follows: +a pattern that starts with \fB::\fR is used directly, +otherwise the namespace \fInamespace\fR +(or the fully-qualified name of the current namespace) +is prepended onto the the pattern. +.TP +\fBnamespace code \fIscript\fR +Captures the current namespace context for later execution +of the script \fIscript\fR. +It returns a new script in which \fIscript\fR has been wrapped +in a \fBnamespace code\fR command. +The new script has two important properties. +First, it can be evaluated in any namespace and will cause +\fIscript\fR to be evaluated in the current namespace +(the one where the \fBnamespace code\fR command was invoked). +Second, additional arguments can be appended to the resulting script +and they will be passed to \fIscript\fR as additional arguments. +For example, suppose the command +\fBset script [namespace code {foo bar}]\fR +is invoked in namespace \fB::a::b\fR. +Then \fBeval "$script x y"\fR +can be executed in any namespace (assuming the value of +\fBscript\fR has been passed in properly) +and will have the same effect as the command +\fBnamespace eval ::a::b {foo bar x y}\fR. +This command is needed because +extensions like Tk normally execute callback scripts +in the global namespace. +A scoped command captures a command together with its namespace context +in a way that allows it to be executed properly later. +See the section \fBSCOPED VALUES\fR for some examples +of how this is used to create callback scripts. +.TP +\fBnamespace current\fR +Returns the fully-qualified name for the current namespace. +The actual name of the global namespace is ``'' +(i.e., an empty string), +but this command returns \fB::\fR for the global namespace +as a convenience to programmers. +.TP +\fBnamespace delete \fR?\fInamespace namespace ...\fR? +Each namespace \fInamespace\fR is deleted +and all variables, procedures, and child namespaces +contained in the namespace are deleted. +If a procedure is currently executing inside the namespace, +the namespace will be kept alive until the procedure returns; +however, the namespace is marked to prevent other code from +looking it up by name. +If a namespace doesn't exist, this command returns an error. +If no namespace names are given, this command does nothing. +.TP +\fBnamespace eval\fR \fInamespace arg\fR ?\fIarg ...\fR? +Activates a namespace called \fInamespace\fR and evaluates some code +in that context. +If the namespace does not already exist, it is created. +If more than one \fIarg\fR argument is specified, +the arguments are concatenated together with a space between each one +in the same fashion as the \fBeval\fR command, +and the result is evaluated. +.br +.sp +If \fInamespace\fR has leading namespace qualifiers +and any leading namespaces do not exist, +they are automatically created. +.TP +\fBnamespace export \fR?\-\fBclear\fR? ?\fIpattern pattern ...\fR? +Specifies which commands are exported from a namespace. +The exported commands are those that can be later imported +into another namespace using a \fBnamespace import\fR command. +Both commands defined in a namespace and +commands the namespace has previously imported +can be exported by a namespace. +The commands do not have to be defined +at the time the \fBnamespace export\fR command is executed. +Each \fIpattern\fR may contain glob-style special characters, +but it may not include any namespace qualifiers. +That is, the pattern can only specify commands +in the current (exporting) namespace. +Each \fIpattern\fR is appended onto the namespace's list of export patterns. +If the \-\fBclear\fR flag is given, +the namespace's export pattern list is reset to empty before any +\fIpattern\fR arguments are appended. +If no \fIpattern\fRs are given and the \-\fBclear\fR flag isn't given, +this command returns the namespace's current export list. +.TP +\fBnamespace forget \fR?\fIpattern pattern ...\fR? +Removes previously imported commands from a namespace. +Each \fIpattern\fR is a qualified name such as +\fBfoo::x\fR or \fBa::b::p*\fR. +Qualified names contain \fB::\fRs and qualify a name +with the name of one or more namespaces. +Each \fIpattern\fR is qualified with the name of an exporting namespace +and may have glob-style special characters in the command name +at the end of the qualified name. +Glob characters may not appear in a namespace name. +This command first finds the matching exported commands. +It then checks whether any of those those commands +were previously imported by the current namespace. +If so, this command deletes the corresponding imported commands. +In effect, this un-does the action of a \fBnamespace import\fR command. +.TP +\fBnamespace import \fR?\fB\-force\fR? ?\fIpattern\fR \fIpattern ...\fR? +Imports commands into a namespace. +Each \fIpattern\fR is a qualified name like +\fBfoo::x\fR or \fBa::p*\fR. +That is, it includes the name of an exporting namespace +and may have glob-style special characters in the command name +at the end of the qualified name. +Glob characters may not appear in a namespace name. +All the commands that match a \fIpattern\fR string +and which are currently exported from their namespace +are added to the current namespace. +This is done by creating a new command in the current namespace +that points to the exported command in its original namespace; +when the new imported command is called, it invokes the exported command. +This command normally returns an error +if an imported command conflicts with an existing command. +However, if the \-\fBforce\fR option is given, +imported commands will silently replace existing commands. +The \fBnamespace import\fR command has snapshot semantics: +that is, only requested commands that are currently defined +in the exporting namespace are imported. +In other words, you can import only the commands that are in a namespace +at the time when the \fBnamespace import\fR command is executed. +If another command is defined and exported in this namespace later on, +it will not be imported. +.TP +\fBnamespace inscope\fR \fInamespace arg\fR ?\fIarg ...\fR? +Executes a script in the context of a particular namespace. +This command is not expected to be used directly by programmers; +calls to it are generated implicitly when applications +use \fBnamespace code\fR commands to create callback scripts +that the applications then register with, e.g., Tk widgets. +The \fBnamespace inscope\fR command is much like the \fBnamespace eval\fR +command except that it has \fBlappend\fR semantics +and the namespace must already exist. +It treats the first argument as a list, +and appends any arguments after the first +onto the end as proper list elements. +\fBnamespace inscope ::foo a x y z\fR +is equivalent to +\fBnamespace eval ::foo [concat a [list x y z]]\fR +This \fBlappend\fR semantics is important because many callback scripts +are actually prefixes. +.TP +\fBnamespace origin \fIcommand\fR +Returns the fully-qualified name of the original command +to which the imported command \fIcommand\fR refers. +When a command is imported into a namespace, +a new command is created in that namespace +that points to the actual command in the exporting namespace. +If a command is imported into a sequence of namespaces +\fIa, b,...,n\fR where each successive namespace +just imports the command from the previous namespace, +this command returns the fully-qualified name of the original command +in the first namespace, \fIa\fR. +If \fIcommand\fR does not refer to an imported command, +the command's own fully-qualified name is returned. +.TP +\fBnamespace parent\fR ?\fInamespace\fR? +Returns the fully-qualified name of the parent namespace +for namespace \fInamespace\fR. +If \fInamespace\fR is not specified, +the fully-qualified name of the current namespace's parent is returned. +.TP +\fBnamespace qualifiers\fR \fIstring\fR +Returns any leading namespace qualifiers for \fIstring\fR. +Qualifiers are namespace names separated by \fB::\fRs. +For the \fIstring\fR \fB::foo::bar::x\fR, +this command returns \fB::foo::bar\fR, +and for \fB::\fR it returns an empty string. +This command is the complement of the \fBnamespace tail\fR command. +Note that it does not check whether the +namespace names are, in fact, +the names of currently defined namespaces. +.TP +\fBnamespace tail\fR \fIstring\fR +Returns the simple name at the end of a qualified string. +Qualifiers are namespace names separated by \fB::\fRs. +For the \fIstring\fR \fB::foo::bar::x\fR, +this command returns \fBx\fR, +and for \fB::\fR it returns an empty string. +This command is the complement of the \fBnamespace qualifiers\fR command. +It does not check whether the namespace names are, in fact, +the names of currently defined namespaces. +.TP +\fBnamespace which\fR ?\-\fBcommand\fR? ?\-\fBvariable\fR? \fIname\fR +Looks up \fIname\fR as either a command or variable +and returns its fully-qualified name. +For example, if \fIname\fR does not exist in the current namespace +but does exist in the global namespace, +this command returns a fully-qualified name in the global namespace. +If the command or variable does not exist, +this command returns an empty string. If the variable has been +created but not defined, such as with the \fBvariable\fR command +or through a \fBtrace\fR on the variable, this command will return the +fully-qualified name of the variable. +If no flag is given, \fIname\fR is treated as a command name. +See the section \fBNAME RESOLUTION\fR below for an explanation of +the rules regarding name resolution. + +.SH "WHAT IS A NAMESPACE?" +.PP +A namespace is a collection of commands and variables. +It encapsulates the commands and variables to ensure that they +won't interfere with the commands and variables of other namespaces. +Tcl has always had one such collection, +which we refer to as the \fIglobal namespace\fR. +The global namespace holds all global variables and commands. +The \fBnamespace eval\fR command lets you create new namespaces. +For example, +.CS +\fBnamespace eval Counter { + namespace export bump + variable num 0 + + proc bump {} { + variable num + incr num + } +}\fR +.CE +creates a new namespace containing the variable \fBnum\fR and +the procedure \fBbump\fR. +The commands and variables in this namespace are separate from +other commands and variables in the same program. +If there is a command named \fBbump\fR in the global namespace, +for example, it will be different from the command \fBbump\fR +in the \fBCounter\fR namespace. +.PP +Namespace variables resemble global variables in Tcl. +They exist outside of the procedures in a namespace +but can be accessed in a procedure via the \fBvariable\fR command, +as shown in the example above. +.PP +Namespaces are dynamic. +You can add and delete commands and variables at any time, +so you can build up the contents of a +namespace over time using a series of \fBnamespace eval\fR commands. +For example, the following series of commands has the same effect +as the namespace definition shown above: +.CS +\fBnamespace eval Counter { + variable num 0 + proc bump {} { + variable num + return [incr num] + } +} +namespace eval Counter { + proc test {args} { + return $args + } +} +namespace eval Counter { + rename test "" +}\fR +.CE +Note that the \fBtest\fR procedure is added to the \fBCounter\fR namespace, +and later removed via the \fBrename\fR command. +.PP +Namespaces can have other namespaces within them, +so they nest hierarchically. +A nested namespace is encapsulated inside its parent namespace +and can not interfere with other namespaces. + +.SH "QUALIFIED NAMES" +.PP +Each namespace has a textual name such as +\fBhistory\fR or \fB::safe::interp\fR. +Since namespaces may nest, +qualified names are used to refer to +commands, variables, and child namespaces contained inside namespaces. +Qualified names are similar to the hierarchical path names for +Unix files or Tk widgets, +except that \fB::\fR is used as the separator +instead of \fB/\fR or \fB.\fR. +The topmost or global namespace has the name ``'' (i.e., an empty string), +although \fB::\fR is a synonym. +As an example, the name \fB::safe::interp::create\fR +refers to the command \fBcreate\fR in the namespace \fBinterp\fR +that is a child of of namespace \fB::safe\fR, +which in turn is a child of the global namespace \fB::\fR. +.PP +If you want to access commands and variables from another namespace, +you must use some extra syntax. +Names must be qualified by the namespace that contains them. +From the global namespace, +we might access the \fBCounter\fR procedures like this: +.CS +\fBCounter::bump 5 +Counter::Reset\fR +.CE +We could access the current count like this: +.CS +\fBputs "count = $Counter::num"\fR +.CE +When one namespace contains another, you may need more than one +qualifier to reach its elements. +If we had a namespace \fBFoo\fR that contained the namespace \fBCounter\fR, +you could invoke its \fBbump\fR procedure +from the global namespace like this: +.CS +\fBFoo::Counter::bump 3\fR +.CE +.PP +You can also use qualified names when you create and rename commands. +For example, you could add a procedure to the \fBFoo\fR +namespace like this: +.CS +\fBproc Foo::Test {args} {return $args}\fR +.CE +And you could move the same procedure to another namespace like this: +.CS +\fBrename Foo::Test Bar::Test\fR +.CE +.PP +There are a few remaining points about qualified names +that we should cover. +Namespaces have nonempty names except for the global namespace. +\fB::\fR is disallowed in simple command, variable, and namespace names +except as a namespace separator. +Extra \fB:\fRs in a qualified name are ignored; +that is, two or more \fB:\fRs are treated as a namespace separator. +A trailing \fB::\fR in a qualified variable or command name +refers to the variable or command named {}. +However, a trailing \fB::\fR in a qualified namespace name is ignored. + +.SH "NAME RESOLUTION" +.PP +In general, all Tcl commands that take variable and command names +support qualified names. +This means you can give qualified names to such commands as +\fBset\fR, \fBproc\fR, \fBrename\fR, and \fBinterp alias\fR. +If you provide a fully-qualified name that starts with a \fB::\fR, +there is no question about what command, variable, or namespace +you mean. +However, if the name does not start with a \fB::\fR +(i.e., is \fIrelative\fR), +Tcl follows a fixed rule for looking it up: +Command and variable names are always resolved +by looking first in the current namespace, +and then in the global namespace. +Namespace names, on the other hand, are always resolved +by looking in only the current namespace. +.PP +In the following example, +.CS +\fBset traceLevel 0 +namespace eval Debug { + printTrace $traceLevel +}\fR +.CE +Tcl looks for \fBtraceLevel\fR in the namespace \fBDebug\fR +and then in the global namespace. +It looks up the command \fBprintTrace\fR in the same way. +If a variable or command name is not found in either context, +the name is undefined. +To make this point absolutely clear, consider the following example: +.CS +\fBset traceLevel 0 +namespace eval Foo { + variable traceLevel 3 + + namespace eval Debug { + printTrace $traceLevel + } +}\fR +.CE +Here Tcl looks for \fBtraceLevel\fR first in the namespace \fBFoo::Debug\fR. +Since it is not found there, Tcl then looks for it +in the global namespace. +The variable \fBFoo::traceLevel\fR is completely ignored +during the name resolution process. +.PP +You can use the \fBnamespace which\fR command to clear up any question +about name resolution. +For example, the command: +.CS +\fBnamespace eval Foo::Debug {namespace which \-variable traceLevel}\fR +.CE +returns \fB::traceLevel\fR. +On the other hand, the command, +.CS +\fBnamespace eval Foo {namespace which \-variable traceLevel}\fR +.CE +returns \fB::Foo::traceLevel\fR. +.PP +As mentioned above, +namespace names are looked up differently +than the names of variables and commands. +Namespace names are always resolved in the current namespace. +This means, for example, +that a \fBnamespace eval\fR command that creates a new namespace +always creates a child of the current namespace +unless the new namespace name begins with a \fB::\fR. +.PP +Tcl has no access control to limit what variables, commands, +or namespaces you can reference. +If you provide a qualified name that resolves to an element +by the name resolution rule above, +you can access the element. +.PP +You can access a namespace variable +from a procedure in the same namespace +by using the \fBvariable\fR command. +Much like the \fBglobal\fR command, +this creates a local link to the namespace variable. +If necessary, it also creates the variable in the current namespace +and initializes it. +Note that the \fBglobal\fR command only creates links +to variables in the global namespace. +It is not necessary to use a \fBvariable\fR command +if you always refer to the namespace variable using an +appropriate qualified name. + +.SH "IMPORTING COMMANDS" +.PP +Namespaces are often used to represent libraries. +Some library commands are used so frequently +that it is a nuisance to type their qualified names. +For example, suppose that all of the commands in a package +like BLT are contained in a namespace called \fBBlt\fR. +Then you might access these commands like this: +.CS +\fBBlt::graph .g \-background red +Blt::table . .g 0,0\fR +.CE +If you use the \fBgraph\fR and \fBtable\fR commands frequently, +you may want to access them without the \fBBlt::\fR prefix. +You can do this by importing the commands into the current namespace, +like this: +.CS +\fBnamespace import Blt::*\fR +.CE +This adds all exported commands from the \fBBlt\fR namespace +into the current namespace context, so you can write code like this: +.CS +\fBgraph .g \-background red +table . .g 0,0\fR +.CE +The \fBnamespace import\fR command only imports commands +from a namespace that that namespace exported +with a \fBnamespace export\fR command. +.PP +Importing \fIevery\fR command from a namespace is generally +a bad idea since you don't know what you will get. +It is better to import just the specific commands you need. +For example, the command +.CS +\fBnamespace import Blt::graph Blt::table\fR +.CE +imports only the \fBgraph\fR and \fBtable\fR commands into the +current context. +.PP +If you try to import a command that already exists, you will get an +error. This prevents you from importing the same command from two +different packages. But from time to time (perhaps when debugging), +you may want to get around this restriction. You may want to +reissue the \fBnamespace import\fR command to pick up new commands +that have appeared in a namespace. In that case, you can use the +\fB\-force\fR option, and existing commands will be silently overwritten: +.CS +\fBnamespace import \-force Blt::graph Blt::table\fR +.CE +If for some reason, you want to stop using the imported commands, +you can remove them with an \fBnamespace forget\fR command, like this: +.CS +\fBnamespace forget Blt::*\fR +.CE +This searches the current namespace for any commands imported from \fBBlt\fR. +If it finds any, it removes them. Otherwise, it does nothing. +After this, the \fBBlt\fR commands must be accessed with the \fBBlt::\fR +prefix. +.PP +When you delete a command from the exporting namespace like this: +.CS +\fBrename Blt::graph ""\fR +.CE +the command is automatically removed from all namespaces that import it. + +.SH "EXPORTING COMMANDS" +You can export commands from a namespace like this: +.CS +\fBnamespace eval Counter { + namespace export bump reset + variable Num 0 + variable Max 100 + + proc bump {{by 1}} { + variable Num + incr Num $by + Check + return $Num + } + proc reset {} { + variable Num + set Num 0 + } + proc Check {} { + variable Num + variable Max + if {$Num > $Max} { + error "too high!" + } + } +}\fR +.CE +The procedures \fBbump\fR and \fBreset\fR are exported, +so they are included when you import from the \fBCounter\fR namespace, +like this: +.CS +\fBnamespace import Counter::*\fR +.CE +However, the \fBCheck\fR procedure is not exported, +so it is ignored by the import operation. +.PP +The \fBnamespace import\fR command only imports commands +that were declared as exported by their namespace. +The \fBnamespace export\fR command specifies what commands +may be imported by other namespaces. +If a \fBnamespace import\fR command specifies a command +that is not exported, the command is not imported. + +.SH "SEE ALSO" +variable(n) + +.SH KEYWORDS +exported, internal, variable diff --git a/mk4/modtcl/tcl8.3.4/doc/open.n b/mk4/modtcl/tcl8.3.4/doc/open.n new file mode 100644 index 0000000..b54729c --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/open.n @@ -0,0 +1,273 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: open.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH open n 7.6 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +open \- Open a file-based or command pipeline channel +.SH SYNOPSIS +.sp +\fBopen \fIfileName\fR +.br +\fBopen \fIfileName access\fR +.br +\fBopen \fIfileName access permissions\fR +.BE + +.SH DESCRIPTION +.PP +.VS +This command opens a file, serial port, or command pipeline and returns a +.VE +channel identifier that may be used in future invocations of commands like +\fBread\fR, \fBputs\fR, and \fBclose\fR. +If the first character of \fIfileName\fR is not \fB|\fR then +the command opens a file: +\fIfileName\fR gives the name of the file to open, and it must conform to the +conventions described in the \fBfilename\fR manual entry. +.PP +The \fIaccess\fR argument, if present, indicates the way in which the file +(or command pipeline) is to be accessed. +In the first form \fIaccess\fR may have any of the following values: +.TP 15 +\fBr\fR +Open the file for reading only; the file must already exist. This is the +default value if \fIaccess\fR is not specified. +.TP 15 +\fBr+\fR +Open the file for both reading and writing; the file must +already exist. +.TP 15 +\fBw\fR +Open the file for writing only. Truncate it if it exists. If it doesn't +exist, create a new file. +.TP 15 +\fBw+\fR +Open the file for reading and writing. Truncate it if it exists. +If it doesn't exist, create a new file. +.TP 15 +\fBa\fR +Open the file for writing only. If the file doesn't exist, +create a new empty file. +Set the initial access position to the end of the file. +.TP 15 +\fBa+\fR +Open the file for reading and writing. If the file doesn't exist, +create a new empty file. +Set the initial access position to the end of the file. +.PP +In the second form, \fIaccess\fR consists of a list of any of the +following flags, all of which have the standard POSIX meanings. +One of the flags must be either \fBRDONLY\fR, \fBWRONLY\fR or \fBRDWR\fR. +.TP 15 +\fBRDONLY\fR +Open the file for reading only. +.TP 15 +\fBWRONLY\fR +Open the file for writing only. +.TP 15 +\fBRDWR\fR +Open the file for both reading and writing. +.TP 15 +\fBAPPEND\fR +Set the file pointer to the end of the file prior to each write. +.TP 15 +\fBCREAT\fR +Create the file if it doesn't already exist (without this flag it +is an error for the file not to exist). +.TP 15 +\fBEXCL\fR +If \fBCREAT\fR is also specified, an error is returned if the +file already exists. +.TP 15 +\fBNOCTTY\fR +If the file is a terminal device, this flag prevents the file from +becoming the controlling terminal of the process. +.TP 15 +\fBNONBLOCK\fR +Prevents the process from blocking while opening the file, and +possibly in subsequent I/O operations. The exact behavior of +this flag is system- and device-dependent; its use is discouraged +(it is better to use the \fBfconfigure\fR command to put a file +in nonblocking mode). +For details refer to your system documentation on the \fBopen\fR system +call's \fBO_NONBLOCK\fR flag. +.TP 15 +\fBTRUNC\fR +If the file exists it is truncated to zero length. +.PP +If a new file is created as part of opening it, \fIpermissions\fR +(an integer) is used to set the permissions for the new file in +conjunction with the process's file mode creation mask. +\fIPermissions\fR defaults to 0666. +.PP +'\" Not versioned as advice applies to all recent versions of Tcl. +'\" Prior to that, Tcl didn't really support binary files anyway... +.VS +Note that if you are going to be reading or writing binary data from +the channel created by this command, you should use the +\fBfconfigure\fR command to change the \fB-translation\fR option of +the channel to \fBbinary\fR before transferring any binary data. This +is in contrast to the ``b'' character passed as part of the equivalent +of the \fIaccess\fR parameter to some versions of the C library +\fIfopen()\fR function. +.VE +.SH "COMMAND PIPELINES" +.PP +If the first character of \fIfileName\fR is ``|'' then the +remaining characters of \fIfileName\fR are treated as a list of arguments +that describe a command pipeline to invoke, in the same style as the +arguments for \fBexec\fR. +In this case, the channel identifier returned by \fBopen\fR may be used +to write to the command's input pipe or read from its output pipe, +depending on the value of \fIaccess\fR. +If write-only access is used (e.g. \fIaccess\fR is \fBw\fR), then +standard output for the pipeline is directed to the current standard +output unless overridden by the command. +If read-only access is used (e.g. \fIaccess\fR is \fBr\fR), +standard input for the pipeline is taken from the current standard +input unless overridden by the command. +.SH "SERIAL COMMUNICATIONS" +.VS +.PP +If \fIfileName\fR refers to a serial port, then the specified serial port +is opened and initialized in a platform-dependent manner. Acceptable +values for the \fIfileName\fR to use to open a serial port are described in +the PORTABILITY ISSUES section. + +.SH "CONFIGURATION OPTIONS" +The \fBfconfigure\fR command can be used to query and set the following +configuration option for open serial ports: +.TP +\fB\-mode \fIbaud\fB,\fIparity\fB,\fIdata\fB,\fIstop\fR +. +This option is a set of 4 comma-separated values: the baud rate, parity, +number of data bits, and number of stop bits for this serial port. The +\fIbaud\fR rate is a simple integer that specifies the connection speed. +\fIParity\fR is one of the following letters: \fBn\fR, \fBo\fR, \fBe\fR, +\fBm\fR, \fBs\fR; respectively signifying the parity options of ``none'', +``odd'', ``even'', ``mark'', or ``space''. \fIData\fR is the number of +data bits and should be an integer from 5 to 8, while \fIstop\fR is the +number of stop bits and should be the integer 1 or 2. +.TP +\fB\-pollinterval \fImsec\fR +. +This option, available only on Windows for serial ports, is used to +set the maximum time between polling for fileevents. This affects the +time interval between checking for events throughout the Tcl +interpreter (the smallest value always wins). Use this option only if +you want to poll the serial port more often than 10 msec (the default). +.TP +\fB\-lasterror\fR +. +This option is available only on Windows for serial ports, and is +query only (will only be reported when directly requested). +In case of a serial communication error, \fBread\fR or \fBputs\fR +returns a general Tcl file I/O error. +\fBfconfigure -lasterror\fR can be called to get a list +of error details (e.g. FRAME RXOVER). +.VE + +.VS +.SH "PORTABILITY ISSUES" +.sp +.TP +\fBWindows \fR(all versions) +. +Valid values for \fIfileName\fR to open a serial port are of the form +\fBcom\fIX\fB:\fR, where \fIX\fR is a number, generally from 1 to 4. +This notation only works for serial ports from 1 to 9, if the system +happens to have more than four. An attempt to open a serial port that +does not exist or has a number greater than 9 will fail. An alternate +form of opening serial ports is to use the filename \fB\e\e.\ecomX\fR, +where X is any number that corresponds to a serial port; please note +that this method is considerably slower on Windows 95 and Windows 98. +.TP +\fBWindows NT\fR +. +When running Tcl interactively, there may be some strange interactions +between the real console, if one is present, and a command pipeline that uses +standard input or output. If a command pipeline is opened for reading, some +of the lines entered at the console will be sent to the command pipeline and +some will be sent to the Tcl evaluator. If a command pipeline is opened for +writing, keystrokes entered into the console are not visible until the the +pipe is closed. This behavior occurs whether the command pipeline is +executing 16-bit or 32-bit applications. These problems only occur because +both Tcl and the child application are competing for the console at +the same time. If the command pipeline is started from a script, so that Tcl +is not accessing the console, or if the command pipeline does not use +standard input or output, but is redirected from or to a file, then the +above problems do not occur. +.TP +\fBWindows 95\fR +. +A command pipeline that executes a 16-bit DOS application cannot be opened +for both reading and writing, since 16-bit DOS applications that receive +standard input from a pipe and send standard output to a pipe run +synchronously. Command pipelines that do not execute 16-bit DOS +applications run asynchronously and can be opened for both reading and +writing. +.sp +When running Tcl interactively, there may be some strange interactions +between the real console, if one is present, and a command pipeline that uses +standard input or output. If a command pipeline is opened for reading from +a 32-bit application, some of the keystrokes entered at the console will be +sent to the command pipeline and some will be sent to the Tcl evaluator. If +a command pipeline is opened for writing to a 32-bit application, no output +is visible on the console until the the pipe is closed. These problems only +occur because both Tcl and the child application are competing for the +console at the same time. If the command pipeline is started from a script, +so that Tcl is not accessing the console, or if the command pipeline does +not use standard input or output, but is redirected from or to a file, then +the above problems do not occur. +.sp +Whether or not Tcl is running interactively, if a command pipeline is opened +for reading from a 16-bit DOS application, the call to \fBopen\fR will not +return until end-of-file has been received from the command pipeline's +standard output. If a command pipeline is opened for writing to a 16-bit DOS +application, no data will be sent to the command pipeline's standard output +until the pipe is actually closed. This problem occurs because 16-bit DOS +applications are run synchronously, as described above. +.TP +\fBMacintosh\fR +. +Opening a serial port is not currently implemented under Macintosh. +.sp +Opening a command pipeline is not supported under Macintosh, since +applications do not support the concept of standard input or output. +.TP +\fBUnix\fR\0\0\0\0\0\0\0 +. +Valid values for \fIfileName\fR to open a serial port are generally of the +form \fB/dev/tty\fIX\fR, where \fIX\fR is \fBa\fR or \fBb\fR, but the name +of any pseudo-file that maps to a serial port may be used. +.sp +When running Tcl interactively, there may be some strange interactions +between the console, if one is present, and a command pipeline that uses +standard input. If a command pipeline is opened for reading, some +of the lines entered at the console will be sent to the command pipeline and +some will be sent to the Tcl evaluator. This problem only occurs because +both Tcl and the child application are competing for the console at the +same time. If the command pipeline is started from a script, so that Tcl is +not accessing the console, or if the command pipeline does not use standard +input, but is redirected from a file, then the above problem does not occur. +.LP +See the PORTABILITY ISSUES section of the \fBexec\fR command for additional +information not specific to command pipelines about executing +applications on the various platforms + +.SH "SEE ALSO" +file(n), close(n), filename(n), fconfigure(n), gets(n), read(n), +puts(n), exec(n), fopen(1) + +.SH KEYWORDS +access mode, append, create, file, non-blocking, open, permissions, +pipeline, process, serial diff --git a/mk4/modtcl/tcl8.3.4/doc/package.n b/mk4/modtcl/tcl8.3.4/doc/package.n new file mode 100644 index 0000000..0ecf5ab --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/package.n @@ -0,0 +1,196 @@ +'\" +'\" Copyright (c) 1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: package.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH package n 7.5 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +package \- Facilities for package loading and version control +.SH SYNOPSIS +.nf +\fBpackage forget ?\fIpackage package ...\fR? +\fBpackage ifneeded \fIpackage version\fR ?\fIscript\fR? +\fBpackage names\fR +\fBpackage present \fR?\fB\-exact\fR? \fIpackage \fR?\fIversion\fR? +\fBpackage provide \fIpackage \fR?\fIversion\fR? +\fBpackage require \fR?\fB\-exact\fR? \fIpackage \fR?\fIversion\fR? +\fBpackage unknown \fR?\fIcommand\fR? +\fBpackage vcompare \fIversion1 version2\fR +\fBpackage versions \fIpackage\fR +\fBpackage vsatisfies \fIversion1 version2\fR +.fi +.BE + +.SH DESCRIPTION +.PP +This command keeps a simple database of the packages available for +use by the current interpreter and how to load them into the +interpreter. +It supports multiple versions of each package and arranges +for the correct version of a package to be loaded based on what +is needed by the application. +This command also detects and reports version clashes. +Typically, only the \fBpackage require\fR and \fBpackage provide\fR +commands are invoked in normal Tcl scripts; the other commands are used +primarily by system scripts that maintain the package database. +.PP +The behavior of the \fBpackage\fR command is determined by its first argument. +The following forms are permitted: +.TP +\fBpackage forget ?\fIpackage package ...\fR? +Removes all information about each specified package from this interpreter, +including information provided by both \fBpackage ifneeded\fR and +\fBpackage provide\fR. +.TP +\fBpackage ifneeded \fIpackage version\fR ?\fIscript\fR? +This command typically appears only in system configuration +scripts to set up the package database. +It indicates that a particular version of +a particular package is available if needed, and that the package +can be added to the interpreter by executing \fIscript\fR. +The script is saved in a database for use by subsequent +\fBpackage require\fR commands; typically, \fIscript\fR +sets up auto-loading for the commands in the package (or calls +\fBload\fR and/or \fBsource\fR directly), then invokes +\fBpackage provide\fR to indicate that the package is present. +There may be information in the database for several different +versions of a single package. +If the database already contains information for \fIpackage\fR +and \fIversion\fR, the new \fIscript\fR replaces the existing +one. +If the \fIscript\fR argument is omitted, the current script for +version \fIversion\fR of package \fIpackage\fR is returned, +or an empty string if no \fBpackage ifneeded\fR command has +been invoked for this \fIpackage\fR and \fIversion\fR. +.TP +\fBpackage names\fR +Returns a list of the names of all packages in the +interpreter for which a version has been provided (via +\fBpackage provide\fR) or for which a \fBpackage ifneeded\fR +script is available. +The order of elements in the list is arbitrary. +.TP +\fBpackage present \fR?\fB\-exact\fR? \fIpackage \fR?\fIversion\fR? +This command is equivalent to \fBpackage require\fR except that it +does not try and load the package if it is not already loaded. +.TP +\fBpackage provide \fIpackage \fR?\fIversion\fR? +This command is invoked to indicate that version \fIversion\fR +of package \fIpackage\fR is now present in the interpreter. +It is typically invoked once as part of an \fBifneeded\fR script, +and again by the package itself when it is finally loaded. +An error occurs if a different version of \fIpackage\fR has been +provided by a previous \fBpackage provide\fR command. +If the \fIversion\fR argument is omitted, then the command +returns the version number that is currently provided, or an +empty string if no \fBpackage provide\fR command has been +invoked for \fIpackage\fR in this interpreter. +.TP +\fBpackage require \fR?\fB\-exact\fR? \fIpackage \fR?\fIversion\fR? +This command is typically invoked by Tcl code that wishes to use +a particular version of a particular package. The arguments +indicate which package is wanted, and the command ensures that +a suitable version of the package is loaded into the interpreter. +If the command succeeds, it returns the version number that is +loaded; otherwise it generates an error. +If both the \fB\-exact\fR +switch and the \fIversion\fR argument are specified then only the +given version is acceptable. If \fB\-exact\fR is omitted but +\fIversion\fR is specified, then versions later than \fIversion\fR +are also acceptable as long as they have the same major version +number as \fIversion\fR. +If both \fB\-exact\fR and \fIversion\fR are omitted then any +version whatsoever is acceptable. +If a version of \fIpackage\fR has already been provided (by invoking +the \fBpackage provide\fR command), then its version number must +satisfy the criteria given by \fB\-exact\fR and \fIversion\fR and +the command returns immediately. +Otherwise, the command searches the database of information provided by +previous \fBpackage ifneeded\fR commands to see if an acceptable +version of the package is available. +If so, the script for the highest acceptable version number is invoked; +it must do whatever is necessary to load the package, +including calling \fBpackage provide\fR for the package. +If the \fBpackage ifneeded\fR database does not contain an acceptable +version of the package and a \fBpackage unknown\fR command has been +specified for the interpreter then that command is invoked; when +it completes, Tcl checks again to see if the package is now provided +or if there is a \fBpackage ifneeded\fR script for it. +If all of these steps fail to provide an acceptable version of the +package, then the command returns an error. +.TP +\fBpackage unknown \fR?\fIcommand\fR? +This command supplies a ``last resort'' command to invoke during +\fBpackage require\fR if no suitable version of a package can be found +in the \fBpackage ifneeded\fR database. +If the \fIcommand\fR argument is supplied, it contains the first part +of a command; when the command is invoked during a \fBpackage require\fR +command, Tcl appends two additional arguments giving the desired package +name and version. +For example, if \fIcommand\fR is \fBfoo bar\fR and later the command +\fBpackage require test 2.4\fR is invoked, then Tcl will execute +the command \fBfoo bar test 2.4\fR to load the package. +If no version number is supplied to the \fBpackage require\fR command, +then the version argument for the invoked command will be an empty string. +If the \fBpackage unknown\fR command is invoked without a \fIcommand\fR +argument, then the current \fBpackage unknown\fR script is returned, +or an empty string if there is none. +If \fIcommand\fR is specified as an empty string, then the current +\fBpackage unknown\fR script is removed, if there is one. +.TP +\fBpackage vcompare \fIversion1 version2\fR +Compares the two version numbers given by \fIversion1\fR and \fIversion2\fR. +Returns -1 if \fIversion1\fR is an earlier version than \fIversion2\fR, +0 if they are equal, and 1 if \fIversion1\fR is later than \fBversion2\fR. +.TP +\fBpackage versions \fIpackage\fR +Returns a list of all the version numbers of \fIpackage\fR +for which information has been provided by \fBpackage ifneeded\fR +commands. +.TP +\fBpackage vsatisfies \fIversion1 version2\fR +Returns 1 if scripts written for \fIversion2\fR will work unchanged +with \fIversion1\fR (i.e. \fIversion1\fR is equal to or greater +than \fIversion2\fR and they both have the same major version +number), 0 otherwise. + +.SH "VERSION NUMBERS" +.PP +Version numbers consist of one or more decimal numbers separated +by dots, such as 2 or 1.162 or 3.1.13.1. +The first number is called the major version number. +Larger numbers correspond to later versions of a package, with +leftmost numbers having greater significance. +For example, version 2.1 is later than 1.3 and version +3.4.6 is later than 3.3.5. +Missing fields are equivalent to zeroes: version 1.3 is the +same as version 1.3.0 and 1.3.0.0, so it is earlier than 1.3.1 or 1.3.0.2. +A later version number is assumed to be upwards compatible with +an earlier version number as long as both versions have the same +major version number. +For example, Tcl scripts written for version 2.3 of a package should +work unchanged under versions 2.3.2, 2.4, and 2.5.1. +Changes in the major version number signify incompatible changes: +if code is written to use version 2.1 of a package, it is not guaranteed +to work unmodified with either version 1.7.3 or version 3.1. + +.SH "PACKAGE INDICES" +.PP +The recommended way to use packages in Tcl is to invoke \fBpackage require\fR +and \fBpackage provide\fR commands in scripts, and use the procedure +\fBpkg_mkIndex\fR to create package index files. +Once you've done this, packages will be loaded automatically +in response to \fBpackage require\fR commands. +See the documentation for \fBpkg_mkIndex\fR for details. + +.SH "SEE ALSO" +msgcat(n), packagens(n), pkgMkIndex(n) + +.SH KEYWORDS +package, version diff --git a/mk4/modtcl/tcl8.3.4/doc/packagens.n b/mk4/modtcl/tcl8.3.4/doc/packagens.n new file mode 100644 index 0000000..18788f4 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/packagens.n @@ -0,0 +1,55 @@ +'\" +'\" Copyright (c) 1998-2000 by Scriptics Corporation. +'\" All rights reserved. +'\" +'\" RCS: @(#) $Id: packagens.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH pkg::create n 8.3 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +pkg::create \- Construct an appropriate \fBpackage ifneeded\fR +command for a given package specification +.SH SYNOPSIS +\fB::pkg::create \fI\-name packageName\fR \fI\-version packageVersion\fR ?\fI\-load filespec\fR? ... ?\fI\-source filespec\fR? ... +.BE + +.SH DESCRIPTION +.PP +\fB::pkg::create\fR is a utility procedure that is part of the standard Tcl +library. It is used to create an appropriate \fBpackage ifneeded\fR +command for a given package specification. It can be used to construct a +\fBpkgIndex.tcl\fR file for use with the \fBpackage\fR mechanism. + +.SH OPTIONS +The parameters supported are: +.TP +\fB\-name\fR\0\fIpackageName\fR +This parameter specifies the name of the package. It is required. +.TP +\fB\-version\fR\0\fIpackageVersion\fR +This parameter specifies the version of the package. It is required. +.TP +\fB\-load\fR\0\fIfilespec\fR +This parameter specifies a binary library that must be loaded with the +\fBload\fR command. \fIfilespec\fR is a list with two elements. The +first element is the name of the file to load. The second, optional +element is a list of commands supplied by loading that file. If the +list of procedures is empty or omitted, \fB::pkg::create\fR will +set up the library for direct loading (see \fBpkg_mkIndex\fR). Any +number of \fB\-load\fR parameters may be specified. +.TP +\fB\-source\fR\0\fIfilespec\fR +This parameter is similar to the \fB\-load\fR parameter, except that it +specifies a Tcl library that must be loaded with the +\fBsource\fR command. Any number of \fB\-source\fR parameters may be +specified. +.PP +At least one \fB\-load\fR or \fB\-source\fR paramter must be given. + +.SH "SEE ALSO" +package(n) + +.SH KEYWORDS +auto-load, index, package, version diff --git a/mk4/modtcl/tcl8.3.4/doc/pid.n b/mk4/modtcl/tcl8.3.4/doc/pid.n new file mode 100644 index 0000000..5a11f1f --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/pid.n @@ -0,0 +1,37 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: pid.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH pid n 7.0 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +pid \- Retrieve process id(s) +.SH SYNOPSIS +\fBpid \fR?\fIfileId\fR? +.BE + +.SH DESCRIPTION +.PP +If the \fIfileId\fR argument is given then it should normally +refer to a process pipeline created with the \fBopen\fR command. +In this case the \fBpid\fR command will return a list whose elements +are the process identifiers of all the processes in the pipeline, +in order. +The list will be empty if \fIfileId\fR refers to an open file +that isn't a process pipeline. +If no \fIfileId\fR argument is given then \fBpid\fR returns the process +identifier of the current process. +All process identifiers are returned as decimal strings. + +.SH "SEE ALSO" +exec(n), open(n) + +.SH KEYWORDS +file, pipeline, process identifier diff --git a/mk4/modtcl/tcl8.3.4/doc/pkgMkIndex.n b/mk4/modtcl/tcl8.3.4/doc/pkgMkIndex.n new file mode 100644 index 0000000..a2e963c --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/pkgMkIndex.n @@ -0,0 +1,243 @@ +'\" +'\" Copyright (c) 1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: pkgMkIndex.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH pkg_mkIndex n 8.3 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +pkg_mkIndex \- Build an index for automatic loading of packages +.SH SYNOPSIS +.nf +.VS 8.3.0 +\fBpkg_mkIndex ?\fI\-direct\fR? ?\fI\-lazy\fR? ?\fI\-load pkgPat\fR? ?\fI\-verbose\fR? \fIdir\fR ?\fIpattern pattern ...\fR? +.VE +.fi +.BE + +.SH DESCRIPTION +.PP +\fBPkg_mkIndex\fR is a utility procedure that is part of the standard +Tcl library. +It is used to create index files that allow packages to be loaded +automatically when \fBpackage require\fR commands are executed. +To use \fBpkg_mkIndex\fR, follow these steps: +.IP [1] +Create the package(s). +Each package may consist of one or more Tcl script files or binary files. +Binary files must be suitable for loading with the \fBload\fR command +with a single argument; for example, if the file is \fBtest.so\fR it must +be possible to load this file with the command \fBload test.so\fR. +Each script file must contain a \fBpackage provide\fR command to declare +the package and version number, and each binary file must contain +a call to \fBTcl_PkgProvide\fR. +.IP [2] +Create the index by invoking \fBpkg_mkIndex\fR. +The \fIdir\fR argument gives the name of a directory and each +\fIpattern\fR argument is a \fBglob\fR-style pattern that selects +script or binary files in \fIdir\fR. +.VS 8.0.3 +The default pattern is \fB*.tcl\fR and \fB*.[info sharedlibextension]\fR. +.VE +.br +\fBPkg_mkIndex\fR will create a file \fBpkgIndex.tcl\fR in \fIdir\fR +with package information about all the files given by the \fIpattern\fR +arguments. +It does this by loading each file into a slave +interpreter and seeing what packages +and new commands appear (this is why it is essential to have +\fBpackage provide\fR commands or \fBTcl_PkgProvide\fR calls +in the files, as described above). +If you have a package split among scripts and binary files, +or if you have dependencies among files, +you may have to use the \fB\-load\fP option +or adjust the order in which \fBpkg_mkIndex\fR processes +the files. See COMPLEX CASES below. + +.IP [3] +Install the package as a subdirectory of one of the directories given by +the \fBtcl_pkgPath\fR variable. If \fB$tcl_pkgPath\fR contains more +than one directory, machine-dependent packages (e.g., those that +contain binary shared libraries) should normally be installed +under the first directory and machine-independent packages (e.g., +those that contain only Tcl scripts) should be installed under the +second directory. +The subdirectory should include +the package's script and/or binary files as well as the \fBpkgIndex.tcl\fR +file. As long as the package is installed as a subdirectory of a +directory in \fB$tcl_pkgPath\fR it will automatically be found during +\fBpackage require\fR commands. +.br +If you install the package anywhere else, then you must ensure that +the directory containing the package is in the \fBauto_path\fR global variable +or an immediate subdirectory of one of the directories in \fBauto_path\fR. +\fBAuto_path\fR contains a list of directories that are searched +by both the auto-loader and the package loader; by default it +includes \fB$tcl_pkgPath\fR. +The package loader also checks all of the subdirectories of the +directories in \fBauto_path\fR. +You can add a directory to \fBauto_path\fR explicitly in your +application, or you can add the directory to your \fBTCLLIBPATH\fR +environment variable: if this environment variable is present, +Tcl initializes \fBauto_path\fR from it during application startup. +.IP [4] +Once the above steps have been taken, all you need to do to use a +package is to invoke \fBpackage require\fR. +For example, if versions 2.1, 2.3, and 3.1 of package \fBTest\fR +have been indexed by \fBpkg_mkIndex\fR, the command +\fBpackage require Test\fR will make version 3.1 available +and the command \fBpackage require \-exact Test 2.1\fR will +make version 2.1 available. +There may be many versions of a package in the various index files +in \fBauto_path\fR, but only one will actually be loaded in a given +interpreter, based on the first call to \fBpackage require\fR. +Different versions of a package may be loaded in different +interpreters. + +.SH OPTIONS +The optional switches are: +.TP 15 +\fB\-direct\fR +The generated index will implement direct loading of the package +upon \fBpackage require\fR. This is the default. +.TP 15 +\fB\-lazy\fR +The generated index will manage to delay loading the package until the +use of one of the commands provided by the package, instead of loading +it immediately upon \fBpackage require\fR. +.TP 15 +\fB\-load \fIpkgPat\fR +The index process will pre-load any packages that exist in the +current interpreter and match \fIpkgPat\fP into the slave interpreter used to +generate the index. The pattern match uses string match rules. +See COMPLEX CASES below. +.TP 15 +\fB\-verbose\fR +Generate output during the indexing process. Output is via +the \fBtclLog\fP procedure, which by default prints to stderr. +.TP 15 +\fB\-\-\fR +End of the flags, in case \fIdir\fP begins with a dash. + +.SH "PACKAGES AND THE AUTO-LOADER" +.PP +The package management facilities overlap somewhat with the auto-loader, +in that both arrange for files to be loaded on-demand. +However, package management is a higher-level mechanism that uses +the auto-loader for the last step in the loading process. +It is generally better to index a package with \fBpkg_mkIndex\fR +rather than \fBauto_mkindex\fR because the package mechanism provides +version control: several versions of a package can be made available +in the index files, with different applications using different +versions based on \fBpackage require\fR commands. +In contrast, \fBauto_mkindex\fR does not understand versions so +it can only handle a single version of each package. +It is probably not a good idea to index a given package with both +\fBpkg_mkIndex\fR and \fBauto_mkindex\fR. +If you use \fBpkg_mkIndex\fR to index a package, its commands cannot +be invoked until \fBpackage require\fR has been used to select a +version; in contrast, packages indexed with \fBauto_mkindex\fR +can be used immediately since there is no version control. + +.SH "HOW IT WORKS" +.PP +\fBPkg_mkIndex\fR depends on the \fBpackage unknown\fR command, +the \fBpackage ifneeded\fR command, and the auto-loader. +The first time a \fBpackage require\fR command is invoked, +the \fBpackage unknown\fR script is invoked. +This is set by Tcl initialization to a script that +evaluates all of the \fBpkgIndex.tcl\fR files in the +\fBauto_path\fR. +The \fBpkgIndex.tcl\fR files contain \fBpackage ifneeded\fR +commands for each version of each available package; these commands +invoke \fBpackage provide\fR commands to announce the +availability of the package, and they setup auto-loader +information to load the files of the package. +.VS 8.3 +If the \fI\-lazy\fR flag was provided when the \fBpkgIndex.tcl\fR +was generated, +.VE +a given file of a given version of a given package isn't +actually loaded until the first time one of its commands +is invoked. +Thus, after invoking \fBpackage require\fR you may +not see the package's commands in the interpreter, but you will be able +to invoke the commands and they will be auto-loaded. + +.VS 8.3 +.SH "DIRECT LOADING" +.PP +Some packages, for instance packages which use namespaces and export +commands or those which require special initialization, might select +that their package files be loaded immediately upon \fBpackage require\fR +instead of delaying the actual loading to the first use of one of the +package's command. This is the default mode when generating the package +index. It can be overridden by specifying the \fI\-lazy\fR argument. +.VE + +.SH "COMPLEX CASES" +Most complex cases of dependencies among scripts +and binary files, and packages being split among scripts and +binary files are handled OK. However, you may have to adjust +the order in which files are processed by \fBpkg_mkIndex\fR. +These issues are described in detail below. +.PP +If each script or file contains one package, and packages +are only contained in one file, then things are easy. +You simply specify all files to be indexed in any order +with some glob patterns. +.PP +In general, it is OK for scripts to have dependencies on other +packages. +If scripts contain \fBpackage require\fP commands, these are +stubbed out in the interpreter used to process the scripts, +so these do not cause problems. +If scripts call into other packages in global code, +these calls are handled by a stub \fBunknown\fP command. +However, if scripts make variable references to other package's +variables in global code, these will cause errors. That is +also bad coding style. +.PP +If binary files have dependencies on other packages, things +can become tricky because it is not possible to stub out +C-level API's such as \fBTcl_PkgRequire\fP API +when loading a binary file. +For example, suppose the BLT package requires Tk, and expresses +this with a call to \fBTcl_PkgRequire\fP in its \fBBlt_Init\fP routine. +To support this, you must run \fBpkg_mkIndex\fR in an interpreter that +has Tk loaded. You can achieve this with the +\fB\-load \fIpkgPat\fR option. If you specify this option, +\fBpkg_mkIndex\fR will load any packages listed by +\fBinfo loaded\fP and that match \fIpkgPat\fP +into the interpreter used to process files. +In most cases this will satisfy the \fBTcl_PkgRequire\fP calls +made by binary files. +.PP +If you are indexing two binary files and one depends on the other, +you should specify the one that has dependencies last. +This way the one without dependencies will get loaded and indexed, +and then the package it provides +will be available when the second file is processed. +You may also need to load the first package into the +temporary interpreter used to create the index by using +the \fB\-load\fP flag; +it won't hurt to specify package patterns that are not yet loaded. +.PP +If you have a package that is split across scripts and a binary file, +then you should avoid the \fB\-load\fP flag. The problem is that +if you load a package before computing the index it masks any +other files that provide part of the same package. +If you must use \fB\-load\fP, +then you must specify the scripts first; otherwise the package loaded from +the binary file may mask the package defined by the scripts. + +.SH "SEE ALSO" +package(n) + +.SH KEYWORDS +auto-load, index, package, version diff --git a/mk4/modtcl/tcl8.3.4/doc/proc.n b/mk4/modtcl/tcl8.3.4/doc/proc.n new file mode 100644 index 0000000..0509d70 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/proc.n @@ -0,0 +1,77 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: proc.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH proc n "" Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +proc \- Create a Tcl procedure +.SH SYNOPSIS +\fBproc \fIname args body\fR +.BE + +.SH DESCRIPTION +.PP +The \fBproc\fR command creates a new Tcl procedure named +\fIname\fR, replacing +any existing command or procedure there may have been by that name. +Whenever the new command is invoked, the contents of \fIbody\fR will +be executed by the Tcl interpreter. +Normally, \fIname\fR is unqualified +(does not include the names of any containing namespaces), +and the new procedure is created in the current namespace. +If \fIname\fR includes any namespace qualifiers, +the procedure is created in the specified namespace. +\fIArgs\fR specifies the formal arguments to the +procedure. It consists of a list, possibly empty, each of whose +elements specifies +one argument. Each argument specifier is also a list with either +one or two fields. If there is only a single field in the specifier +then it is the name of the argument; if there are two fields, then +the first is the argument name and the second is its default value. +.PP +When \fIname\fR is invoked a local variable +will be created for each of the formal arguments to the procedure; its +value will be the value of corresponding argument in the invoking command +or the argument's default value. +Arguments with default values need not be +specified in a procedure invocation. However, there must be enough +actual arguments for all the +formal arguments that don't have defaults, and there must not be any extra +actual arguments. There is one special case to permit procedures with +variable numbers of arguments. If the last formal argument has the name +\fBargs\fR, then a call to the procedure may contain more actual arguments +than the procedure has formals. In this case, all of the actual arguments +starting at the one that would be assigned to \fBargs\fR are combined into +a list (as if the \fBlist\fR command had been used); this combined value +is assigned to the local variable \fBargs\fR. +.PP +When \fIbody\fR is being executed, variable names normally refer to +local variables, which are created automatically when referenced and +deleted when the procedure returns. One local variable is automatically +created for each of the procedure's arguments. +Global variables can only be accessed by invoking +the \fBglobal\fR command or the \fBupvar\fR command. +Namespace variables can only be accessed by invoking +the \fBvariable\fR command or the \fBupvar\fR command. +.PP +The \fBproc\fR command returns an empty string. When a procedure is +invoked, the procedure's return value is the value specified in a +\fBreturn\fR command. If the procedure doesn't execute an explicit +\fBreturn\fR, then its return value is the value of the last command +executed in the procedure's body. +If an error occurs while executing the procedure +body, then the procedure-as-a-whole will return that same error. + +.SH "SEE ALSO" +info(n), unknown(n) + +.SH KEYWORDS +argument, procedure diff --git a/mk4/modtcl/tcl8.3.4/doc/puts.n b/mk4/modtcl/tcl8.3.4/doc/puts.n new file mode 100644 index 0000000..9f0d053 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/puts.n @@ -0,0 +1,69 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: puts.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH puts n 7.5 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +puts \- Write to a channel +.SH SYNOPSIS +\fBputs \fR?\fB\-nonewline\fR? ?\fIchannelId\fR? \fIstring\fR +.BE + +.SH DESCRIPTION +.PP +Writes the characters given by \fIstring\fR to the channel given +by \fIchannelId\fR. +\fIChannelId\fR must be a channel identifier such as returned from a +previous invocation of \fBopen\fR or \fBsocket\fR. It must have been opened +for output. If no \fIchannelId\fR is specified then it defaults to +\fBstdout\fR. \fBPuts\fR normally outputs a newline character after +\fIstring\fR, but this feature may be suppressed by specifying the +\fB\-nonewline\fR switch. +.PP +Newline characters in the output are translated by \fBputs\fR to +platform-specific end-of-line sequences according to the current +value of the \fB\-translation\fR option for the channel (for example, +on PCs newlines are normally replaced with carriage-return-linefeed +sequences; on Macintoshes newlines are normally replaced with +carriage-returns). +See the \fBfconfigure\fR manual entry for a discussion on ways in +which \fBfconfigure\fR will alter output. +.PP +Tcl buffers output internally, so characters written with \fBputs\fR +may not appear immediately on the output file or device; Tcl will +normally delay output until the buffer is full or the channel is +closed. +You can force output to appear immediately with the \fBflush\fR +command. +.PP +When the output buffer fills up, the \fBputs\fR command will normally +block until all the buffered data has been accepted for output by the +operating system. +If \fIchannelId\fR is in nonblocking mode then the \fBputs\fR command +will not block even if the operating system cannot accept the data. +Instead, Tcl continues to buffer the data and writes it in the +background as fast as the underlying file or device can accept it. +The application must use the Tcl event loop for nonblocking output +to work; otherwise Tcl never finds out that the file or device is +ready for more output data. +It is possible for an arbitrarily large amount of data to be +buffered for a channel in nonblocking mode, which could consume a +large amount of memory. +To avoid wasting memory, nonblocking I/O should normally +be used in an event-driven fashion with the \fBfileevent\fR command +(don't invoke \fBputs\fR unless you have recently been notified +via a file event that the channel is ready for more output data). + +.SH "SEE ALSO" +file(n), fileevent(n) + +.SH KEYWORDS +channel, newline, output, write diff --git a/mk4/modtcl/tcl8.3.4/doc/pwd.n b/mk4/modtcl/tcl8.3.4/doc/pwd.n new file mode 100644 index 0000000..c530b3d --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/pwd.n @@ -0,0 +1,28 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: pwd.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH pwd n "" Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +pwd \- Return the current working directory +.SH SYNOPSIS +\fBpwd\fR +.BE + +.SH DESCRIPTION +.PP +Returns the path name of the current working directory. + +.SH "SEE ALSO" +file(n), cd(n), glob(n), filename(n) + +.SH KEYWORDS +working directory diff --git a/mk4/modtcl/tcl8.3.4/doc/re_syntax.n b/mk4/modtcl/tcl8.3.4/doc/re_syntax.n new file mode 100644 index 0000000..0f1aaa3 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/re_syntax.n @@ -0,0 +1,932 @@ +'\" +'\" Copyright (c) 1998 Sun Microsystems, Inc. +'\" Copyright (c) 1999 Scriptics Corporation +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: re_syntax.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH re_syntax n "8.1" Tcl "Tcl Built-In Commands" +.BS +.SH NAME +re_syntax \- Syntax of Tcl regular expressions. +.BE + +.SH DESCRIPTION +.PP +A \fIregular expression\fR describes strings of characters. +It's a pattern that matches certain strings and doesn't match others. + +.SH "DIFFERENT FLAVORS OF REs" +Regular expressions (``RE''s), as defined by POSIX, come in two +flavors: \fIextended\fR REs (``EREs'') and \fIbasic\fR REs (``BREs''). +EREs are roughly those of the traditional \fIegrep\fR, while BREs are +roughly those of the traditional \fIed\fR. This implementation adds +a third flavor, \fIadvanced\fR REs (``AREs''), basically EREs with +some significant extensions. +.PP +This manual page primarily describes AREs. BREs mostly exist for +backward compatibility in some old programs; they will be discussed at +the end. POSIX EREs are almost an exact subset of AREs. Features of +AREs that are not present in EREs will be indicated. + +.SH "REGULAR EXPRESSION SYNTAX" +.PP +Tcl regular expressions are implemented using the package written by +Henry Spencer, based on the 1003.2 spec and some (not quite all) of +the Perl5 extensions (thanks, Henry!). Much of the description of +regular expressions below is copied verbatim from his manual entry. +.PP +An ARE is one or more \fIbranches\fR, +separated by `\fB|\fR', +matching anything that matches any of the branches. +.PP +A branch is zero or more \fIconstraints\fR or \fIquantified atoms\fR, +concatenated. +It matches a match for the first, followed by a match for the second, etc; +an empty branch matches the empty string. +.PP +A quantified atom is an \fIatom\fR possibly followed +by a single \fIquantifier\fR. +Without a quantifier, it matches a match for the atom. +The quantifiers, +and what a so-quantified atom matches, are: +.RS 2 +.TP 6 +\fB*\fR +a sequence of 0 or more matches of the atom +.TP +\fB+\fR +a sequence of 1 or more matches of the atom +.TP +\fB?\fR +a sequence of 0 or 1 matches of the atom +.TP +\fB{\fIm\fB}\fR +a sequence of exactly \fIm\fR matches of the atom +.TP +\fB{\fIm\fB,}\fR +a sequence of \fIm\fR or more matches of the atom +.TP +\fB{\fIm\fB,\fIn\fB}\fR +a sequence of \fIm\fR through \fIn\fR (inclusive) matches of the atom; +\fIm\fR may not exceed \fIn\fR +.TP +\fB*? +? ?? {\fIm\fB}? {\fIm\fB,}? {\fIm\fB,\fIn\fB}?\fR +\fInon-greedy\fR quantifiers, +which match the same possibilities, +but prefer the smallest number rather than the largest number +of matches (see MATCHING) +.RE +.PP +The forms using +\fB{\fR and \fB}\fR +are known as \fIbound\fRs. +The numbers +\fIm\fR and \fIn\fR are unsigned decimal integers +with permissible values from 0 to 255 inclusive. +.PP +An atom is one of: +.RS 2 +.TP 6 +\fB(\fIre\fB)\fR +(where \fIre\fR is any regular expression) +matches a match for +\fIre\fR, with the match noted for possible reporting +.TP +\fB(?:\fIre\fB)\fR +as previous, +but does no reporting +(a ``non-capturing'' set of parentheses) +.TP +\fB()\fR +matches an empty string, +noted for possible reporting +.TP +\fB(?:)\fR +matches an empty string, +without reporting +.TP +\fB[\fIchars\fB]\fR +a \fIbracket expression\fR, +matching any one of the \fIchars\fR (see BRACKET EXPRESSIONS for more detail) +.TP + \fB.\fR +matches any single character +.TP +\fB\e\fIk\fR +(where \fIk\fR is a non-alphanumeric character) +matches that character taken as an ordinary character, +e.g. \e\e matches a backslash character +.TP +\fB\e\fIc\fR +where \fIc\fR is alphanumeric +(possibly followed by other characters), +an \fIescape\fR (AREs only), +see ESCAPES below +.TP +\fB{\fR +when followed by a character other than a digit, +matches the left-brace character `\fB{\fR'; +when followed by a digit, it is the beginning of a +\fIbound\fR (see above) +.TP +\fIx\fR +where \fIx\fR is +a single character with no other significance, matches that character. +.RE +.PP +A \fIconstraint\fR matches an empty string when specific conditions +are met. +A constraint may not be followed by a quantifier. +The simple constraints are as follows; some more constraints are +described later, under ESCAPES. +.RS 2 +.TP 8 +\fB^\fR +matches at the beginning of a line +.TP +\fB$\fR +matches at the end of a line +.TP +\fB(?=\fIre\fB)\fR +\fIpositive lookahead\fR (AREs only), matches at any point +where a substring matching \fIre\fR begins +.TP +\fB(?!\fIre\fB)\fR +\fInegative lookahead\fR (AREs only), matches at any point +where no substring matching \fIre\fR begins +.RE +.PP +The lookahead constraints may not contain back references (see later), +and all parentheses within them are considered non-capturing. +.PP +An RE may not end with `\fB\e\fR'. + +.SH "BRACKET EXPRESSIONS" +A \fIbracket expression\fR is a list of characters enclosed in `\fB[\|]\fR'. +It normally matches any single character from the list (but see below). +If the list begins with `\fB^\fR', +it matches any single character +(but see below) \fInot\fR from the rest of the list. +.PP +If two characters in the list are separated by `\fB\-\fR', +this is shorthand +for the full \fIrange\fR of characters between those two (inclusive) in the +collating sequence, +e.g. +\fB[0\-9]\fR +in ASCII matches any decimal digit. +Two ranges may not share an +endpoint, so e.g. +\fBa\-c\-e\fR +is illegal. +Ranges are very collating-sequence-dependent, +and portable programs should avoid relying on them. +.PP +To include a literal +\fB]\fR +or +\fB\-\fR +in the list, +the simplest method is to +enclose it in +\fB[.\fR and \fB.]\fR +to make it a collating element (see below). +Alternatively, +make it the first character +(following a possible `\fB^\fR'), +or (AREs only) precede it with `\fB\e\fR'. +Alternatively, for `\fB\-\fR', +make it the last character, +or the second endpoint of a range. +To use a literal +\fB\-\fR +as the first endpoint of a range, +make it a collating element +or (AREs only) precede it with `\fB\e\fR'. +With the exception of these, some combinations using +\fB[\fR +(see next +paragraphs), and escapes, +all other special characters lose their +special significance within a bracket expression. +.PP +Within a bracket expression, a collating element (a character, +a multi-character sequence that collates as if it were a single character, +or a collating-sequence name for either) +enclosed in +\fB[.\fR and \fB.]\fR +stands for the +sequence of characters of that collating element. +The sequence is a single element of the bracket expression's list. +A bracket expression in a locale that has +multi-character collating elements +can thus match more than one character. +.VS 8.2 +So (insidiously), a bracket expression that starts with \fB^\fR +can match multi-character collating elements even if none of them +appear in the bracket expression! +(\fINote:\fR Tcl currently has no multi-character collating elements. +This information is only for illustration.) +.PP +For example, assume the collating sequence includes a \fBch\fR +multi-character collating element. +Then the RE \fB[[.ch.]]*c\fR (zero or more \fBch\fP's followed by \fBc\fP) +matches the first five characters of `\fBchchcc\fR'. +Also, the RE \fB[^c]b\fR matches all of `\fBchb\fR' +(because \fB[^c]\fR matches the multi-character \fBch\fR). +.VE 8.2 +.PP +Within a bracket expression, a collating element enclosed in +\fB[=\fR +and +\fB=]\fR +is an equivalence class, standing for the sequences of characters +of all collating elements equivalent to that one, including itself. +(If there are no other equivalent collating elements, +the treatment is as if the enclosing delimiters were `\fB[.\fR'\& +and `\fB.]\fR'.) +For example, if +\fBo\fR +and +\fB\o'o^'\fR +are the members of an equivalence class, +then `\fB[[=o=]]\fR', `\fB[[=\o'o^'=]]\fR', +and `\fB[o\o'o^']\fR'\& +are all synonymous. +An equivalence class may not be an endpoint +of a range. +.VS 8.2 +(\fINote:\fR +Tcl currently implements only the Unicode locale. +It doesn't define any equivalence classes. +The examples above are just illustrations.) +.VE 8.2 +.PP +Within a bracket expression, the name of a \fIcharacter class\fR enclosed +in +\fB[:\fR +and +\fB:]\fR +stands for the list of all characters +(not all collating elements!) +belonging to that +class. +Standard character classes are: +.PP +.RS +.ne 5 +.nf +.ta 3c +\fBalpha\fR A letter. +\fBupper\fR An upper-case letter. +\fBlower\fR A lower-case letter. +\fBdigit\fR A decimal digit. +\fBxdigit\fR A hexadecimal digit. +\fBalnum\fR An alphanumeric (letter or digit). +\fBprint\fR An alphanumeric (same as alnum). +\fBblank\fR A space or tab character. +\fBspace\fR A character producing white space in displayed text. +\fBpunct\fR A punctuation character. +\fBgraph\fR A character with a visible representation. +\fBcntrl\fR A control character. +.fi +.RE +.PP +A locale may provide others. +.VS 8.2 +(Note that the current Tcl implementation has only one locale: +the Unicode locale.) +.VE 8.2 +A character class may not be used as an endpoint of a range. +.PP +There are two special cases of bracket expressions: +the bracket expressions +\fB[[:<:]]\fR +and +\fB[[:>:]]\fR +are constraints, matching empty strings at +the beginning and end of a word respectively. +'\" note, discussion of escapes below references this definition of word +A word is defined as a sequence of +word characters +that is neither preceded nor followed by +word characters. +A word character is an +\fIalnum\fR +character +or an underscore +(\fB_\fR). +These special bracket expressions are deprecated; +users of AREs should use constraint escapes instead (see below). +.SH ESCAPES +Escapes (AREs only), which begin with a +\fB\e\fR +followed by an alphanumeric character, +come in several varieties: +character entry, class shorthands, constraint escapes, and back references. +A +\fB\e\fR +followed by an alphanumeric character but not constituting +a valid escape is illegal in AREs. +In EREs, there are no escapes: +outside a bracket expression, +a +\fB\e\fR +followed by an alphanumeric character merely stands for that +character as an ordinary character, +and inside a bracket expression, +\fB\e\fR +is an ordinary character. +(The latter is the one actual incompatibility between EREs and AREs.) +.PP +Character-entry escapes (AREs only) exist to make it easier to specify +non-printing and otherwise inconvenient characters in REs: +.RS 2 +.TP 5 +\fB\ea\fR +alert (bell) character, as in C +.TP +\fB\eb\fR +backspace, as in C +.TP +\fB\eB\fR +synonym for +\fB\e\fR +to help reduce backslash doubling in some +applications where there are multiple levels of backslash processing +.TP +\fB\ec\fIX\fR +(where X is any character) the character whose +low-order 5 bits are the same as those of +\fIX\fR, +and whose other bits are all zero +.TP +\fB\ee\fR +the character whose collating-sequence name +is `\fBESC\fR', +or failing that, the character with octal value 033 +.TP +\fB\ef\fR +formfeed, as in C +.TP +\fB\en\fR +newline, as in C +.TP +\fB\er\fR +carriage return, as in C +.TP +\fB\et\fR +horizontal tab, as in C +.TP +\fB\eu\fIwxyz\fR +(where +\fIwxyz\fR +is exactly four hexadecimal digits) +the Unicode character +\fBU+\fIwxyz\fR +in the local byte ordering +.TP +\fB\eU\fIstuvwxyz\fR +(where +\fIstuvwxyz\fR +is exactly eight hexadecimal digits) +reserved for a somewhat-hypothetical Unicode extension to 32 bits +.TP +\fB\ev\fR +vertical tab, as in C +are all available. +.TP +\fB\ex\fIhhh\fR +(where +\fIhhh\fR +is any sequence of hexadecimal digits) +the character whose hexadecimal value is +\fB0x\fIhhh\fR +(a single character no matter how many hexadecimal digits are used). +.TP +\fB\e0\fR +the character whose value is +\fB0\fR +.TP +\fB\e\fIxy\fR +(where +\fIxy\fR +is exactly two octal digits, +and is not a +\fIback reference\fR (see below)) +the character whose octal value is +\fB0\fIxy\fR +.TP +\fB\e\fIxyz\fR +(where +\fIxyz\fR +is exactly three octal digits, +and is not a +back reference (see below)) +the character whose octal value is +\fB0\fIxyz\fR +.RE +.PP +Hexadecimal digits are `\fB0\fR'-`\fB9\fR', `\fBa\fR'-`\fBf\fR', +and `\fBA\fR'-`\fBF\fR'. +Octal digits are `\fB0\fR'-`\fB7\fR'. +.PP +The character-entry escapes are always taken as ordinary characters. +For example, +\fB\e135\fR +is +\fB]\fR +in ASCII, +but +\fB\e135\fR +does not terminate a bracket expression. +Beware, however, that some applications (e.g., C compilers) interpret +such sequences themselves before the regular-expression package +gets to see them, which may require doubling (quadrupling, etc.) the `\fB\e\fR'. +.PP +Class-shorthand escapes (AREs only) provide shorthands for certain commonly-used +character classes: +.RS 2 +.TP 10 +\fB\ed\fR +\fB[[:digit:]]\fR +.TP +\fB\es\fR +\fB[[:space:]]\fR +.TP +\fB\ew\fR +\fB[[:alnum:]_]\fR +(note underscore) +.TP +\fB\eD\fR +\fB[^[:digit:]]\fR +.TP +\fB\eS\fR +\fB[^[:space:]]\fR +.TP +\fB\eW\fR +\fB[^[:alnum:]_]\fR +(note underscore) +.RE +.PP +Within bracket expressions, `\fB\ed\fR', `\fB\es\fR', +and `\fB\ew\fR'\& +lose their outer brackets, +and `\fB\eD\fR', `\fB\eS\fR', +and `\fB\eW\fR'\& +are illegal. +.VS 8.2 +(So, for example, \fB[a-c\ed]\fR is equivalent to \fB[a-c[:digit:]]\fR. +Also, \fB[a-c\eD]\fR, which is equivalent to \fB[a-c^[:digit:]]\fR, is illegal.) +.VE 8.2 +.PP +A constraint escape (AREs only) is a constraint, +matching the empty string if specific conditions are met, +written as an escape: +.RS 2 +.TP 6 +\fB\eA\fR +matches only at the beginning of the string +(see MATCHING, below, for how this differs from `\fB^\fR') +.TP +\fB\em\fR +matches only at the beginning of a word +.TP +\fB\eM\fR +matches only at the end of a word +.TP +\fB\ey\fR +matches only at the beginning or end of a word +.TP +\fB\eY\fR +matches only at a point that is not the beginning or end of a word +.TP +\fB\eZ\fR +matches only at the end of the string +(see MATCHING, below, for how this differs from `\fB$\fR') +.TP +\fB\e\fIm\fR +(where +\fIm\fR +is a nonzero digit) a \fIback reference\fR, see below +.TP +\fB\e\fImnn\fR +(where +\fIm\fR +is a nonzero digit, and +\fInn\fR +is some more digits, +and the decimal value +\fImnn\fR +is not greater than the number of closing capturing parentheses seen so far) +a \fIback reference\fR, see below +.RE +.PP +A word is defined as in the specification of +\fB[[:<:]]\fR +and +\fB[[:>:]]\fR +above. +Constraint escapes are illegal within bracket expressions. +.PP +A back reference (AREs only) matches the same string matched by the parenthesized +subexpression specified by the number, +so that (e.g.) +\fB([bc])\e1\fR +matches +\fBbb\fR +or +\fBcc\fR +but not `\fBbc\fR'. +The subexpression must entirely precede the back reference in the RE. +Subexpressions are numbered in the order of their leading parentheses. +Non-capturing parentheses do not define subexpressions. +.PP +There is an inherent historical ambiguity between octal character-entry +escapes and back references, which is resolved by heuristics, +as hinted at above. +A leading zero always indicates an octal escape. +A single non-zero digit, not followed by another digit, +is always taken as a back reference. +A multi-digit sequence not starting with a zero is taken as a back +reference if it comes after a suitable subexpression +(i.e. the number is in the legal range for a back reference), +and otherwise is taken as octal. +.SH "METASYNTAX" +In addition to the main syntax described above, there are some special +forms and miscellaneous syntactic facilities available. +.PP +Normally the flavor of RE being used is specified by +application-dependent means. +However, this can be overridden by a \fIdirector\fR. +If an RE of any flavor begins with `\fB***:\fR', +the rest of the RE is an ARE. +If an RE of any flavor begins with `\fB***=\fR', +the rest of the RE is taken to be a literal string, +with all characters considered ordinary characters. +.PP +An ARE may begin with \fIembedded options\fR: +a sequence +\fB(?\fIxyz\fB)\fR +(where +\fIxyz\fR +is one or more alphabetic characters) +specifies options affecting the rest of the RE. +These supplement, and can override, +any options specified by the application. +The available option letters are: +.RS 2 +.TP 3 +\fBb\fR +rest of RE is a BRE +.TP 3 +\fBc\fR +case-sensitive matching (usual default) +.TP 3 +\fBe\fR +rest of RE is an ERE +.TP 3 +\fBi\fR +case-insensitive matching (see MATCHING, below) +.TP 3 +\fBm\fR +historical synonym for +\fBn\fR +.TP 3 +\fBn\fR +newline-sensitive matching (see MATCHING, below) +.TP 3 +\fBp\fR +partial newline-sensitive matching (see MATCHING, below) +.TP 3 +\fBq\fR +rest of RE is a literal (``quoted'') string, all ordinary characters +.TP 3 +\fBs\fR +non-newline-sensitive matching (usual default) +.TP 3 +\fBt\fR +tight syntax (usual default; see below) +.TP 3 +\fBw\fR +inverse partial newline-sensitive (``weird'') matching (see MATCHING, below) +.TP 3 +\fBx\fR +expanded syntax (see below) +.RE +.PP +Embedded options take effect at the +\fB)\fR +terminating the sequence. +They are available only at the start of an ARE, +and may not be used later within it. +.PP +In addition to the usual (\fItight\fR) RE syntax, in which all characters are +significant, there is an \fIexpanded\fR syntax, +available in all flavors of RE +with the \fB-expanded\fR switch, or in AREs with the embedded x option. +In the expanded syntax, +white-space characters are ignored +and all characters between a +\fB#\fR +and the following newline (or the end of the RE) are ignored, +permitting paragraphing and commenting a complex RE. +There are three exceptions to that basic rule: +.RS 2 +.PP +a white-space character or `\fB#\fR' preceded by `\fB\e\fR' is retained +.PP +white space or `\fB#\fR' within a bracket expression is retained +.PP +white space and comments are illegal within multi-character symbols +like the ARE `\fB(?:\fR' or the BRE `\fB\e(\fR' +.RE +.PP +Expanded-syntax white-space characters are blank, tab, newline, and +.VS 8.2 +any character that belongs to the \fIspace\fR character class. +.VE 8.2 +.PP +Finally, in an ARE, +outside bracket expressions, the sequence `\fB(?#\fIttt\fB)\fR' +(where +\fIttt\fR +is any text not containing a `\fB)\fR') +is a comment, +completely ignored. +Again, this is not allowed between the characters of +multi-character symbols like `\fB(?:\fR'. +Such comments are more a historical artifact than a useful facility, +and their use is deprecated; +use the expanded syntax instead. +.PP +\fINone\fR of these metasyntax extensions is available if the application +(or an initial +\fB***=\fR +director) +has specified that the user's input be treated as a literal string +rather than as an RE. +.SH MATCHING +In the event that an RE could match more than one substring of a given +string, +the RE matches the one starting earliest in the string. +If the RE could match more than one substring starting at that point, +its choice is determined by its \fIpreference\fR: +either the longest substring, or the shortest. +.PP +Most atoms, and all constraints, have no preference. +A parenthesized RE has the same preference (possibly none) as the RE. +A quantified atom with quantifier +\fB{\fIm\fB}\fR +or +\fB{\fIm\fB}?\fR +has the same preference (possibly none) as the atom itself. +A quantified atom with other normal quantifiers (including +\fB{\fIm\fB,\fIn\fB}\fR +with +\fIm\fR +equal to +\fIn\fR) +prefers longest match. +A quantified atom with other non-greedy quantifiers (including +\fB{\fIm\fB,\fIn\fB}?\fR +with +\fIm\fR +equal to +\fIn\fR) +prefers shortest match. +A branch has the same preference as the first quantified atom in it +which has a preference. +An RE consisting of two or more branches connected by the +\fB|\fR +operator prefers longest match. +.PP +Subject to the constraints imposed by the rules for matching the whole RE, +subexpressions also match the longest or shortest possible substrings, +based on their preferences, +with subexpressions starting earlier in the RE taking priority over +ones starting later. +Note that outer subexpressions thus take priority over +their component subexpressions. +.PP +Note that the quantifiers +\fB{1,1}\fR +and +\fB{1,1}?\fR +can be used to force longest and shortest preference, respectively, +on a subexpression or a whole RE. +.PP +Match lengths are measured in characters, not collating elements. +An empty string is considered longer than no match at all. +For example, +\fBbb*\fR +matches the three middle characters of `\fBabbbc\fR', +\fB(week|wee)(night|knights)\fR +matches all ten characters of `\fBweeknights\fR', +when +\fB(.*).*\fR +is matched against +\fBabc\fR +the parenthesized subexpression +matches all three characters, and +when +\fB(a*)*\fR +is matched against +\fBbc\fR +both the whole RE and the parenthesized +subexpression match an empty string. +.PP +If case-independent matching is specified, +the effect is much as if all case distinctions had vanished from the +alphabet. +When an alphabetic that exists in multiple cases appears as an +ordinary character outside a bracket expression, it is effectively +transformed into a bracket expression containing both cases, +so that +\fBx\fR +becomes `\fB[xX]\fR'. +When it appears inside a bracket expression, all case counterparts +of it are added to the bracket expression, so that +\fB[x]\fR +becomes +\fB[xX]\fR +and +\fB[^x]\fR +becomes `\fB[^xX]\fR'. +.PP +If newline-sensitive matching is specified, \fB.\fR +and bracket expressions using +\fB^\fR +will never match the newline character +(so that matches will never cross newlines unless the RE +explicitly arranges it) +and +\fB^\fR +and +\fB$\fR +will match the empty string after and before a newline +respectively, in addition to matching at beginning and end of string +respectively. +ARE +\fB\eA\fR +and +\fB\eZ\fR +continue to match beginning or end of string \fIonly\fR. +.PP +If partial newline-sensitive matching is specified, +this affects \fB.\fR +and bracket expressions +as with newline-sensitive matching, but not +\fB^\fR +and `\fB$\fR'. +.PP +If inverse partial newline-sensitive matching is specified, +this affects +\fB^\fR +and +\fB$\fR +as with +newline-sensitive matching, +but not \fB.\fR +and bracket expressions. +This isn't very useful but is provided for symmetry. +.SH "LIMITS AND COMPATIBILITY" +No particular limit is imposed on the length of REs. +Programs intended to be highly portable should not employ REs longer +than 256 bytes, +as a POSIX-compliant implementation can refuse to accept such REs. +.PP +The only feature of AREs that is actually incompatible with +POSIX EREs is that +\fB\e\fR +does not lose its special +significance inside bracket expressions. +All other ARE features use syntax which is illegal or has +undefined or unspecified effects in POSIX EREs; +the +\fB***\fR +syntax of directors likewise is outside the POSIX +syntax for both BREs and EREs. +.PP +Many of the ARE extensions are borrowed from Perl, but some have +been changed to clean them up, and a few Perl extensions are not present. +Incompatibilities of note include `\fB\eb\fR', `\fB\eB\fR', +the lack of special treatment for a trailing newline, +the addition of complemented bracket expressions to the things +affected by newline-sensitive matching, +the restrictions on parentheses and back references in lookahead constraints, +and the longest/shortest-match (rather than first-match) matching semantics. +.PP +The matching rules for REs containing both normal and non-greedy quantifiers +have changed since early beta-test versions of this package. +(The new rules are much simpler and cleaner, +but don't work as hard at guessing the user's real intentions.) +.PP +Henry Spencer's original 1986 \fIregexp\fR package, +still in widespread use (e.g., in pre-8.1 releases of Tcl), +implemented an early version of today's EREs. +There are four incompatibilities between \fIregexp\fR's near-EREs +(`RREs' for short) and AREs. +In roughly increasing order of significance: +.PP +.RS +In AREs, +\fB\e\fR +followed by an alphanumeric character is either an +escape or an error, +while in RREs, it was just another way of writing the +alphanumeric. +This should not be a problem because there was no reason to write +such a sequence in RREs. +.PP +\fB{\fR +followed by a digit in an ARE is the beginning of a bound, +while in RREs, +\fB{\fR +was always an ordinary character. +Such sequences should be rare, +and will often result in an error because following characters +will not look like a valid bound. +.PP +In AREs, +\fB\e\fR +remains a special character within `\fB[\|]\fR', +so a literal +\fB\e\fR +within +\fB[\|]\fR +must be written `\fB\e\e\fR'. +\fB\e\e\fR +also gives a literal +\fB\e\fR +within +\fB[\|]\fR +in RREs, +but only truly paranoid programmers routinely doubled the backslash. +.PP +AREs report the longest/shortest match for the RE, +rather than the first found in a specified search order. +This may affect some RREs which were written in the expectation that +the first match would be reported. +(The careful crafting of RREs to optimize the search order for fast +matching is obsolete (AREs examine all possible matches +in parallel, and their performance is largely insensitive to their +complexity) but cases where the search order was exploited to deliberately +find a match which was \fInot\fR the longest/shortest will need rewriting.) +.RE + +.SH "BASIC REGULAR EXPRESSIONS" +BREs differ from EREs in several respects. `\fB|\fR', `\fB+\fR', +and +\fB?\fR +are ordinary characters and there is no equivalent +for their functionality. +The delimiters for bounds are +\fB\e{\fR +and `\fB\e}\fR', +with +\fB{\fR +and +\fB}\fR +by themselves ordinary characters. +The parentheses for nested subexpressions are +\fB\e(\fR +and `\fB\e)\fR', +with +\fB(\fR +and +\fB)\fR +by themselves ordinary characters. +\fB^\fR +is an ordinary character except at the beginning of the +RE or the beginning of a parenthesized subexpression, +\fB$\fR +is an ordinary character except at the end of the +RE or the end of a parenthesized subexpression, +and +\fB*\fR +is an ordinary character if it appears at the beginning of the +RE or the beginning of a parenthesized subexpression +(after a possible leading `\fB^\fR'). +Finally, +single-digit back references are available, +and +\fB\e<\fR +and +\fB\e>\fR +are synonyms for +\fB[[:<:]]\fR +and +\fB[[:>:]]\fR +respectively; +no other escapes are available. + +.SH "SEE ALSO" +RegExp(3), regexp(n), regsub(n), lsearch(n), switch(n), text(n) + +.SH KEYWORDS +match, regular expression, string diff --git a/mk4/modtcl/tcl8.3.4/doc/read.n b/mk4/modtcl/tcl8.3.4/doc/read.n new file mode 100644 index 0000000..4682981 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/read.n @@ -0,0 +1,58 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: read.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH read n 8.1 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +read \- Read from a channel +.SH SYNOPSIS +\fBread \fR?\fB\-nonewline\fR? \fIchannelId\fR +.sp +\fBread \fIchannelId numChars\fR +.BE + +.SH DESCRIPTION +.PP +In the first form, the \fBread\fR command reads all of the data from +\fIchannelId\fR up to the end of the file. +If the \fB\-nonewline\fR switch is specified then the last character +of the file is discarded if it is a newline. +.VS 8.1 +In the second form, the extra argument specifies how many characters to +read. Exactly that many characters will be read and returned, unless +there are fewer than \fInumChars\fR left in the file; in this case +all the remaining characters are returned. If the channel is +configured to use a multi-byte encoding, then the number of characters +read may not be the same as the number of bytes read. +.PP +If \fIchannelId\fR is in nonblocking mode, the command may not read as +many characters as requested: once all available input has been read, +the command will return the data that is available rather than +blocking for more input. If the channel is configured to use a +multi-byte encoding, then there may actually be some bytes remaining +in the internal buffers that do not form a complete character. These +bytes will not be returned until a complete character is available or +end-of-file is reached. +.VE 8.1 +The \fB\-nonewline\fR switch is ignored if the command returns +before reaching the end of the file. +.PP +\fBRead\fR translates end-of-line sequences in the input into +newline characters according to the \fB\-translation\fR option +for the channel. +See the \fBfconfigure\fR manual entry for a discussion on ways in +which \fBfconfigure\fR will alter input. + +.SH "SEE ALSO" +file(n), eof(n), fblocked(n), fconfigure(n) + +.SH KEYWORDS +blocking, channel, end of line, end of file, nonblocking, read, translation, encoding diff --git a/mk4/modtcl/tcl8.3.4/doc/regexp.n b/mk4/modtcl/tcl8.3.4/doc/regexp.n new file mode 100644 index 0000000..e62db12 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/regexp.n @@ -0,0 +1,133 @@ +'\" +'\" Copyright (c) 1998 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: regexp.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH regexp n 8.3 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +regexp \- Match a regular expression against a string + +.SH SYNOPSIS +\fBregexp \fR?\fIswitches\fR? \fIexp string \fR?\fImatchVar\fR? ?\fIsubMatchVar subMatchVar ...\fR? +.BE + +.SH DESCRIPTION +.PP +Determines whether the regular expression \fIexp\fR matches part or +all of \fIstring\fR and returns 1 if it does, 0 if it doesn't, unless +\fB-inline\fR is specified (see below). +(Regular expression matching is described in the \fBre_syntax\fR +reference page.) +.LP +If additional arguments are specified after \fIstring\fR then they +are treated as the names of variables in which to return +information about which part(s) of \fIstring\fR matched \fIexp\fR. +\fIMatchVar\fR will be set to the range of \fIstring\fR that +matched all of \fIexp\fR. The first \fIsubMatchVar\fR will contain +the characters in \fIstring\fR that matched the leftmost parenthesized +subexpression within \fIexp\fR, the next \fIsubMatchVar\fR will +contain the characters that matched the next parenthesized +subexpression to the right in \fIexp\fR, and so on. +.PP +If the initial arguments to \fBregexp\fR start with \fB\-\fR then +they are treated as switches. The following switches are +currently supported: +.TP 15 +\fB\-about\fR +Instead of attempting to match the regular expression, returns a list +containing information about the regular expression. The first +element of the list is a subexpression count. The second element is a +list of property names that describe various attributes of the regular +expression. This switch is primarily intended for debugging purposes. +.TP 15 +\fB\-expanded\fR +Enables use of the expanded regular expression syntax where +whitespace and comments are ignored. This is the same as specifying +the \fB(?x)\fR embedded option (see METASYNTAX, below). +.TP 15 +\fB\-indices\fR +Changes what is stored in the \fIsubMatchVar\fRs. +Instead of storing the matching characters from \fIstring\fR, +each variable +will contain a list of two decimal strings giving the indices +in \fIstring\fR of the first and last characters in the matching +range of characters. +.TP 15 +\fB\-line\fR +Enables newline-sensitive matching. By default, newline is a +completely ordinary character with no special meaning. With this +flag, `[^' bracket expressions and `.' never match newline, `^' +matches an empty string after any newline in addition to its normal +function, and `$' matches an empty string before any newline in +addition to its normal function. This flag is equivalent to +specifying both \fB\-linestop\fR and \fB\-lineanchor\fR, or the +\fB(?n)\fR embedded option (see METASYNTAX, below). +.TP 15 +\fB\-linestop\fR +Changes the behavior of `[^' bracket expressions and `.' so that they +stop at newlines. This is the same as specifying the \fB(?p)\fR +embedded option (see METASYNTAX, below). +.TP 15 +\fB\-lineanchor\fR +Changes the behavior of `^' and `$' (the ``anchors'') so they match the +beginning and end of a line respectively. This is the same as +specifying the \fB(?w)\fR embedded option (see METASYNTAX, below). +.TP 15 +\fB\-nocase\fR +Causes upper-case characters in \fIstring\fR to be treated as +lower case during the matching process. +.VS 8.3 +.TP 15 +\fB\-all\fR +Causes the regular expression to be matched as many times as possible +in the string, returning the total number of matches found. If this +is specified with match variables, they will continue information for +the last match only. +.TP 15 +\fB\-inline\fR +Causes the command to return, as a list, the data that would otherwise +be placed in match variables. When using \fB-inline\fR, +match variables may not be specified. If used with \fB-all\fR, the +list will be concatenated at each iteration, such that a flat list is +always returned. For each match iteration, the command will append the +overall match data, plus one element for each subexpression in the +regular expression. Examples are: +.CS + regexp -inline -- {\\w(\\w)} " inlined " + => {in n} + regexp -all -inline -- {\\w(\\w)} " inlined " + => {in n li i ne e} +.CE +.TP 15 +\fB\-start\fR \fIindex\fR +Specifies a character index offset into the string to start +matching the regular expression at. When using this switch, `^' +will not match the beginning of the line, and \\A will still +match the start of the string at \fIindex\fR. If \fB\-indices\fR +is specified, the indices will be indexed starting from the +absolute beginning of the input string. +\fIindex\fR will be constrained to the bounds of the input string. +.VE 8.3 +.TP 15 +\fB\-\|\-\fR +Marks the end of switches. The argument following this one will +be treated as \fIexp\fR even if it starts with a \fB\-\fR. +.PP +If there are more \fIsubMatchVar\fR's than parenthesized +subexpressions within \fIexp\fR, or if a particular subexpression +in \fIexp\fR doesn't match the string (e.g. because it was in a +portion of the expression that wasn't matched), then the corresponding +\fIsubMatchVar\fR will be set to ``\fB\-1 \-1\fR'' if \fB\-indices\fR +has been specified or to an empty string otherwise. + +.SH "SEE ALSO" +re_syntax(n), regsub(n) + +.SH KEYWORDS +match, regular expression, string diff --git a/mk4/modtcl/tcl8.3.4/doc/registry.n b/mk4/modtcl/tcl8.3.4/doc/registry.n new file mode 100644 index 0000000..98a107e --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/registry.n @@ -0,0 +1,168 @@ +'\" +'\" Copyright (c) 1997 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: registry.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH registry n 8.0 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +registry \- Manipulate the Windows registry +.SH SYNOPSIS +.sp +\fBpackage require registry 1.0\fR +.sp +\fBregistry \fIoption\fR \fIkeyName\fR ?\fIarg arg ...\fR? +.BE + +.SH DESCRIPTION +.PP +The \fBregistry\fR package provides a general set of operations for +manipulating the Windows registry. The package implements the +\fBregistry\fR Tcl command. This command is only supported on the +Windows platform. Warning: this command should be used with caution +as a corrupted registry can leave your system in an unusable state. +.PP +\fIKeyName\fR is the name of a registry key. Registry keys must be +one of the following forms: +.IP +\fB\e\e\fIhostname\fB\e\fIrootname\fB\e\fIkeypath\fR +.IP +\fIrootname\fB\e\fIkeypath\fR +.IP +\fIrootname\fR +.PP +\fIHostname\fR specifies the name of any valid Windows +host that exports its registry. The \fIrootname\fR component must be +one of \fBHKEY_LOCAL_MACHINE\fR, \fBHKEY_USERS\fR, +.VS +\fBHKEY_CLASSES_ROOT\fR, \fBHKEY_CURRENT_USER\fR, +\fBHKEY_CURRENT_CONFIG\fR, \fBHKEY_PERFORMANCE_DATA\fR, or +\fBHKEY_DYN_DATA\fR. The \fIkeypath\fR can be one or more +.VE +registry key names separated by backslash (\fB\e\fR) characters. +.PP +\fIOption\fR indicates what to do with the registry key name. Any +unique abbreviation for \fIoption\fR is acceptable. The valid options +are: +.TP +\fBregistry delete \fIkeyName\fR ?\fIvalueName\fR? +. +If the optional \fIvalueName\fR argument is present, the specified +value under \fIkeyName\fR will be deleted from the registry. If the +optional \fIvalueName\fR is omitted, the specified key and any subkeys +or values beneath it in the registry heirarchy will be deleted. If +the key could not be deleted then an error is generated. If the key +did not exist, the command has no effect. +.TP +\fBregistry get \fIkeyName valueName\fR +. +Returns the data associated with the value \fIvalueName\fR under the key +\fIkeyName\fR. If either the key or the value does not exist, then an +error is generated. For more details on the format of the returned +data, see SUPPORTED TYPES, below. +.TP +\fBregistry keys \fIkeyName\fR ?\fIpattern\fR? +. +If \fIpattern\fR isn't specified, returns a list of names of all the +subkeys of \fIkeyName\fR. If \fIpattern\fR is specified, only those +names matching \fIpattern\fR are returned. Matching is determined +using the same rules as for \fBstring\fR \fBmatch\fR. If the +specified \fIkeyName\fR does not exist, then an error is generated. +.TP +\fBregistry set \fIkeyName\fR ?\fIvalueName data \fR?\fItype\fR?? +. +If \fIvalueName\fR isn't specified, creates the key \fIkeyName\fR if +it doesn't already exist. If \fIvalueName\fR is specified, creates +the key \fIkeyName\fR and value \fIvalueName\fR if necessary. The +contents of \fIvalueName\fR are set to \fIdata\fR with the type +indicated by \fItype\fR. If \fItype\fR isn't specified, the type +\fBsz\fR is assumed. For more details on the data and type arguments, +see SUPPORTED TYPES below. +.TP +\fBregistry type \fIkeyName valueName\fR +. +Returns the type of the value \fIvalueName\fR in the key +\fIkeyName\fR. For more information on the possible types, see +SUPPORTED TYPES, below. +.TP +\fBregistry values \fIkeyName\fR ?\fIpattern\fR? +. +If \fIpattern\fR isn't specified, returns a list of names of all the +values of \fIkeyName\fR. If \fIpattern\fR is specified, only those +names matching \fIpattern\fR are returned. Matching is determined +using the same rules as for \fBstring\fR \fBmatch\fR. + +.SH "SUPPORTED TYPES" +Each value under a key in the registry contains some data of a +particular type in a type-specific representation. The \fBregistry\fR +command converts between this internal representation and one that can +be manipulated by Tcl scripts. In most cases, the data is simply +returned as a Tcl string. The type indicates the intended use for the +data, but does not actually change the representation. For some +types, the \fBregistry\fR command returns the data in a different form to +make it easier to manipulate. The following types are recognized by the +registry command: +.TP 17 +\fBbinary\fR +. +The registry value contains arbitrary binary data. The data is represented +exactly in Tcl, including any embedded nulls. +.TP +\fBnone\fR +. +The registry value contains arbitrary binary data with no defined +type. The data is represented exactly in Tcl, including any embedded +nulls. +.TP +\fBsz\fR +. +The registry value contains a null-terminated string. The data is +represented in Tcl as a string. +.TP +\fBexpand_sz\fR +. +The registry value contains a null-terminated string that contains +unexpanded references to environment variables in the normal Windows +style (for example, "%PATH%"). The data is represented in Tcl as a +string. +.TP +\fBdword\fR +. +The registry value contains a little-endian 32-bit number. The data is +represented in Tcl as a decimal string. +.TP +\fBdword_big_endian\fR +. +The registry value contains a big-endian 32-bit number. The data is +represented in Tcl as a decimal string. +.TP +\fBlink\fR +. +The registry value contains a symbolic link. The data is represented +exactly in Tcl, including any embedded nulls. +.TP +\fBmulti_sz\fR +. +The registry value contains an array of null-terminated strings. The +data is represented in Tcl as a list of strings. +.TP +\fBresource_list\fR +. +The registry value contains a device-driver resource list. The data +is represented exactly in Tcl, including any embedded nulls. +.PP +In addition to the symbolically named types listed above, unknown +types are identified using a 32-bit integer that corresponds to the +type code returned by the system interfaces. In this case, the data +is represented exactly in Tcl, including any embedded nulls. + +.SH "PORTABILITY ISSUES" +The registry command is only available on Windows. + +.SH KEYWORDS +registry diff --git a/mk4/modtcl/tcl8.3.4/doc/regsub.n b/mk4/modtcl/tcl8.3.4/doc/regsub.n new file mode 100644 index 0000000..f8c8ec4 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/regsub.n @@ -0,0 +1,112 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" Copyright (c) 2000 Scriptics Corporation. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: regsub.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH regsub n 8.3 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +regsub \- Perform substitutions based on regular expression pattern matching +.SH SYNOPSIS +\fBregsub \fR?\fIswitches\fR? \fIexp string subSpec varName\fR +.BE + +.SH DESCRIPTION +.PP +This command matches the regular expression \fIexp\fR against +\fIstring\fR, +and it copies \fIstring\fR to the variable whose name is +given by \fIvarName\fR. +(Regular expression matching is described in the \fBre_syntax\fR +reference page.) +If there is a match, then while copying \fIstring\fR to \fIvarName\fR +the portion of \fIstring\fR that +matched \fIexp\fR is replaced with \fIsubSpec\fR. +If \fIsubSpec\fR contains a ``&'' or ``\e0'', then it is replaced +in the substitution with the portion of \fIstring\fR that +matched \fIexp\fR. +If \fIsubSpec\fR contains a ``\e\fIn\fR'', where \fIn\fR is a digit +between 1 and 9, then it is replaced in the substitution with +the portion of \fIstring\fR that matched the \fIn\fR-th +parenthesized subexpression of \fIexp\fR. +Additional backslashes may be used in \fIsubSpec\fR to prevent special +interpretation of ``&'' or ``\e0'' or ``\e\fIn\fR'' or +backslash. +The use of backslashes in \fIsubSpec\fR tends to interact badly +with the Tcl parser's use of backslashes, so it's generally +safest to enclose \fIsubSpec\fR in braces if it includes +backslashes. +.LP +If the initial arguments to \fBregexp\fR start with \fB\-\fR then +they are treated as switches. The following switches are +currently supported: +.TP 10 +\fB\-all\fR +All ranges in \fIstring\fR that match \fIexp\fR are found and +substitution is performed for each of these ranges. +Without this switch only the first +matching range is found and substituted. +If \fB\-all\fR is specified, then ``&'' and ``\e\fIn\fR'' +sequences are handled for each substitution using the information +from the corresponding match. +.TP 15 +\fB\-expanded\fR +Enables use of the expanded regular expression syntax where +whitespace and comments are ignored. This is the same as specifying +the \fB(?x)\fR embedded option (see METASYNTAX, below). +.TP 15 +\fB\-line\fR +Enables newline-sensitive matching. By default, newline is a +completely ordinary character with no special meaning. With this +flag, `[^' bracket expressions and `.' never match newline, `^' +matches an empty string after any newline in addition to its normal +function, and `$' matches an empty string before any newline in +addition to its normal function. This flag is equivalent to +specifying both \fB\-linestop\fR and \fB\-lineanchor\fR, or the +\fB(?n)\fR embedded option (see METASYNTAX, below). +.TP 15 +\fB\-linestop\fR +Changes the behavior of `[^' bracket expressions and `.' so that they +stop at newlines. This is the same as specifying the \fB(?p)\fR +embedded option (see METASYNTAX, below). +.TP 15 +\fB\-lineanchor\fR +Changes the behavior of `^' and `$' (the ``anchors'') so they match the +beginning and end of a line respectively. This is the same as +specifying the \fB(?w)\fR embedded option (see METASYNTAX, below). +.TP 10 +\fB\-nocase\fR +Upper-case characters in \fIstring\fR will be converted to lower-case +before matching against \fIexp\fR; however, substitutions specified +by \fIsubSpec\fR use the original unconverted form of \fIstring\fR. +.VS 8.3 +.TP 10 +\fB\-start\fR \fIindex\fR +Specifies a character index offset into the string to start +matching the regular expression at. When using this switch, `^' +will not match the beginning of the line, and \\A will still +match the start of the string at \fIindex\fR. +\fIindex\fR will be constrained to the bounds of the input string. +.VE 8.3 +.TP 10 +\fB\-\|\-\fR +Marks the end of switches. The argument following this one will +be treated as \fIexp\fR even if it starts with a \fB\-\fR. +.PP +The command returns a count of the number of matching ranges that +were found and replaced. +See the manual entry for \fBregexp\fR for details on the interpretation +of regular expressions. + +.SH "SEE ALSO" +regexp(n), re_syntax(n) + +.SH KEYWORDS +match, pattern, regular expression, substitute diff --git a/mk4/modtcl/tcl8.3.4/doc/rename.n b/mk4/modtcl/tcl8.3.4/doc/rename.n new file mode 100644 index 0000000..ca66617 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/rename.n @@ -0,0 +1,35 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1997 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: rename.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH rename n "" Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +rename \- Rename or delete a command +.SH SYNOPSIS +\fBrename \fIoldName newName\fR +.BE + +.SH DESCRIPTION +.PP +Rename the command that used to be called \fIoldName\fR so that it +is now called \fInewName\fR. +If \fInewName\fR is an empty string then \fIoldName\fR is deleted. +\fIoldName\fR and \fInewName\fR may include namespace qualifiers +(names of containing namespaces). +If a command is renamed into a different namespace, +future invocations of it will execute in the new namespace. +The \fBrename\fR command returns an empty string as result. + +.SH "SEE ALSO" +namespace(n), proc(n) + +.SH KEYWORDS +command, delete, namespace, rename diff --git a/mk4/modtcl/tcl8.3.4/doc/resource.n b/mk4/modtcl/tcl8.3.4/doc/resource.n new file mode 100644 index 0000000..06cfffc --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/resource.n @@ -0,0 +1,155 @@ +'\" +'\" Copyright (c) 1997 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" RCS: @(#) $Id: resource.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH resource n 8.0 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +resource \- Manipulate Macintosh resources +.SH SYNOPSIS +\fBresource \fIoption\fR ?\fIarg arg ...\fR? +.BE + +.SH DESCRIPTION +.PP +The \fBresource\fR command provides some generic operations for +dealing with Macintosh resources. This command is only supported on +the Macintosh platform. Each Macintosh file consists of two +\fIforks\fR: a \fIdata\fR fork and a \fIresource\fR fork. You use the +normal open, puts, close, etc. commands to manipulate the data fork. +You must use this command, however, to interact with the resource +fork. \fIOption\fR indicates what resource command to perform. Any +unique abbreviation for \fIoption\fR is acceptable. The valid options +are: +.TP +\fBresource close \fIrsrcRef\fR +Closes the given resource reference (obtained from \fBresource +open\fR). Resources from that resource file will no longer be +available. +.TP +\fBresource delete\fR ?\fIoptions\fR? \fIresourceType\fR +This command will delete the resource specified by \fIoptions\fR and +type \fIresourceType\fR (see RESOURCE TYPES below). The options +give you several ways to specify the resource to be deleted. +.RS +.TP +\fB\-id\fR \fIresourceId\fR +If the \fB-id\fR option is given the id \fIresourceId\fR (see RESOURCE +IDS below) is used to specify the resource to be deleted. The id must +be a number - to specify a name use the \fB\-name\fR option. +.TP +\fB\-name\fR \fIresourceName\fR +If \fB-name\fR is specified, the resource named +\fIresourceName\fR will be deleted. If the \fB-id\fR is also +provided, then there must be a resource with BOTH this name and +this id. If no name is provided, then the id will be used regardless +of the name of the actual resource. +.TP +\fB\-file\fR \fIresourceRef\fR +If the \fB-file\fR option is specified then the resource will be +deleted from the file pointed to by \fIresourceRef\fR. Otherwise the +first resource with the given \fIresourceName\fR and or +\fIresourceId\fR which is found on the resource file path will be +deleted. To inspect the file path, use the \fIresource files\fR command. +.RE +.TP +\fBresource files ?\fIresourceRef\fR? +If \fIresourceRef\fRis not provided, this command returns a Tcl list +of the resource references for all the currently open resource files. +The list is in the normal Macintosh search order for resources. If +\fIresourceRef\fR is specified, the command will +return the path to the file whose resource fork is represented by that +token. +.TP +\fBresource list \fIresourceType\fR ?\fIresourceRef\fR? +List all of the resources ids of type \fIresourceType\fR (see RESOURCE +TYPES below). If \fIresourceRef\fR is specified then the command will +limit the search to that particular resource file. Otherwise, all +resource files currently opened by the application will be searched. +A Tcl list of either the resource name's or resource id's of the found +resources will be returned. See the RESOURCE IDS section below for +more details about what a resource id is. +.TP +\fBresource open \fIfileName\fR ?\fIaccess\fR? +Open the resource for the file \fIfileName\fR. Standard file access +permissions may also be specified (see the manual entry for \fBopen\fR +for details). A resource reference (\fIresourceRef\fR) is returned +that can be used by the other resource commands. An error can occur +if the file doesn't exist or the file does not have a resource fork. +However, if you open the file with write permissions the file and/or +resource fork will be created instead of generating an error. +.TP +\fBresource read \fIresourceType\fR \fIresourceId\fR ?\fIresourceRef\fR? +Read the entire resource of type \fIresourceType\fR (see RESOURCE +TYPES below) and the name or id of \fIresourceId\fR (see RESOURCE IDS +below) into memory and return the result. If \fIresourceRef\fR is +specified we limit our search to that resource file, otherwise we +search all open resource forks in the application. It is important to +note that most Macintosh resource use a binary format and the data +returned from this command may have embedded NULLs or other non-ASCII +data. +.TP +\fBresource types ?\fIresourceRef\fR? +This command returns a Tcl list of all resource types (see RESOURCE +TYPES below) found in the resource file pointed to by +\fIresourceRef\fR. If \fIresourceRef\fR is not specified it will +return all the resource types found in every resource file currently +opened by the application. +.TP +\fBresource write\fR ?\fIoptions\fR? \fIresourceType\fR \fIdata\fR +This command will write the passed in \fIdata\fR as a new resource of +type \fIresourceType\fR (see RESOURCE TYPES below). Several options +are available that describe where and how the resource is stored. +.RS +.TP +\fB\-id\fR \fIresourceId\fR +If the \fB-id\fR option is given the id \fIresourceId\fR (see RESOURCE +IDS below) is used for the new resource, otherwise a unique id will be +generated that will not conflict with any existing resource. However, +the id must be a number - to specify a name use the \fB\-name\fR option. +.TP +\fB\-name\fR \fIresourceName\fR +If \fB-name\fR is specified the resource will be named +\fIresourceName\fR, otherwise it will have the empty string as the +name. +.TP +\fB\-file\fR \fIresourceRef\fR +If the \fB-file\fR option is specified then the resource will be +written in the file pointed to by \fIresourceRef\fR, otherwise the +most resently open resource will be used. +.TP +\fB\-force\fR +If the target resource already exists, then by default Tcl will not +overwrite it, but raise an error instead. Use the -force flag to +force overwriting the extant resource. +.RE + +.SH "RESOURCE TYPES" +Resource types are defined as a four character string that is then +mapped to an underlying id. For example, \fBTEXT\fR refers to the +Macintosh resource type for text. The type \fBSTR#\fR is a list of +counted strings. All Macintosh resources must be of some type. See +Macintosh documentation for a more complete list of resource types +that are commonly used. + +.SH "RESOURCE IDS" +For this command the notion of a resource id actually refers to two +ideas in Macintosh resources. Every place you can use a resource Id +you can use either the resource name or a resource number. Names are +always searched or returned in preference to numbers. For example, +the \fBresource list\fR command will return names if they exist or +numbers if the name is NULL. + +.SH "PORTABILITY ISSUES" +The resource command is only available on Macintosh. + +.SH "SEE ALSO" +open(n) + +.SH KEYWORDS +open, resource diff --git a/mk4/modtcl/tcl8.3.4/doc/return.n b/mk4/modtcl/tcl8.3.4/doc/return.n new file mode 100644 index 0000000..edaeabd --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/return.n @@ -0,0 +1,92 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: return.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH return n 7.0 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +return \- Return from a procedure +.SH SYNOPSIS +\fBreturn \fR?\fB\-code \fIcode\fR? ?\fB\-errorinfo \fIinfo\fR? ?\fB\-errorcode\fI code\fR? ?\fIstring\fR? +.BE + +.SH DESCRIPTION +.PP +Return immediately from the current procedure +(or top-level command or \fBsource\fR command), +with \fIstring\fR as the return value. If \fIstring\fR is not specified then +an empty string will be returned as result. + +.SH "EXCEPTIONAL RETURNS" +.PP +In the usual case where the \fB\-code\fR option isn't +specified the procedure will return normally (its completion +code will be TCL_OK). +However, the \fB\-code\fR option may be used to generate an +exceptional return from the procedure. +\fICode\fR may have any of the following values: +.TP 10 +\fBok\fR +Normal return: same as if the option is omitted. +.TP 10 +\fBerror\fR +Error return: same as if the \fBerror\fR command were used to +terminate the procedure, except for handling of \fBerrorInfo\fR +and \fBerrorCode\fR variables (see below). +.TP 10 +\fBreturn\fR +The current procedure will return with a completion code of +TCL_RETURN, so that the procedure that invoked it will return +also. +.TP 10 +\fBbreak\fR +The current procedure will return with a completion code of +TCL_BREAK, which will terminate the innermost nested loop in +the code that invoked the current procedure. +.TP 10 +\fBcontinue\fR +The current procedure will return with a completion code of +TCL_CONTINUE, which will terminate the current iteration of +the innermost nested loop in the code that invoked the current +procedure. +.TP 10 +\fIvalue\fR +\fIValue\fR must be an integer; it will be returned as the +completion code for the current procedure. +.LP +The \fB\-code\fR option is rarely used. +It is provided so that procedures that implement +new control structures can reflect exceptional conditions back to +their callers. +.PP +Two additional options, \fB\-errorinfo\fR and \fB\-errorcode\fR, +may be used to provide additional information during error +returns. +These options are ignored unless \fIcode\fR is \fBerror\fR. +.PP +The \fB\-errorinfo\fR option specifies an initial stack +trace for the \fBerrorInfo\fR variable; if it is not specified then +the stack trace left in \fBerrorInfo\fR will include the call to +the procedure and higher levels on the stack but it will not include +any information about the context of the error within the procedure. +Typically the \fIinfo\fR value is supplied from the value left +in \fBerrorInfo\fR after a \fBcatch\fR command trapped an error within +the procedure. +.PP +If the \fB\-errorcode\fR option is specified then \fIcode\fR provides +a value for the \fBerrorCode\fR variable. +If the option is not specified then \fBerrorCode\fR will +default to \fBNONE\fR. + +.SH "SEE ALSO" +break(n), continue(n), error(n), proc(n) + +.SH KEYWORDS +break, continue, error, procedure, return diff --git a/mk4/modtcl/tcl8.3.4/doc/safe.n b/mk4/modtcl/tcl8.3.4/doc/safe.n new file mode 100644 index 0000000..86aa245 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/safe.n @@ -0,0 +1,350 @@ +'\" +'\" Copyright (c) 1995-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: safe.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH "Safe Tcl" n 8.0 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +Safe\ Base \- A mechanism for creating and manipulating safe interpreters. +.SH SYNOPSIS +\fB::safe::interpCreate\fR ?\fIslave\fR? ?\fIoptions...\fR? +.sp +\fB::safe::interpInit\fR \fIslave\fR ?\fIoptions...\fR? +.sp +\fB::safe::interpConfigure\fR \fIslave\fR ?\fIoptions...\fR? +.sp +\fB::safe::interpDelete\fR \fIslave\fR +.sp +\fB::safe::interpAddToAccessPath\fR \fIslave\fR \fIdirectory\fR +.sp +\fB::safe::interpFindInAccessPath\fR \fIslave\fR \fIdirectory\fR +.sp +\fB::safe::setLogCmd\fR ?\fIcmd arg...\fR? +.SH OPTIONS +.PP +?\fB\-accessPath\fR \fIpathList\fR? +?\fB\-statics\fR \fIboolean\fR? ?\fB\-noStatics\fR? +?\fB\-nested\fR \fIboolean\fR? ?\fB\-nestedLoadOk\fR? +?\fB\-deleteHook\fR \fIscript\fR? +.BE + +.SH DESCRIPTION +Safe Tcl is a mechanism for executing untrusted Tcl scripts +safely and for providing mediated access by such scripts to +potentially dangerous functionality. +.PP +The Safe Base ensures that untrusted Tcl scripts cannot harm the +hosting application. +The Safe Base prevents integrity and privacy attacks. Untrusted Tcl +scripts are prevented from corrupting the state of the hosting +application or computer. Untrusted scripts are also prevented from +disclosing information stored on the hosting computer or in the +hosting application to any party. +.PP +The Safe Base allows a master interpreter to create safe, restricted +interpreters that contain a set of predefined aliases for the \fBsource\fR, +\fBload\fR, \fBfile\fR, \fBencoding\fR, and \fBexit\fR commands and +are able to use the auto-loading and package mechanisms. +.PP +No knowledge of the file system structure is leaked to the +safe interpreter, because it has access only to a virtualized path +containing tokens. When the safe interpreter requests to source a file, it +uses the token in the virtual path as part of the file name to source; the +master interpreter transparently +translates the token into a real directory name and executes the +requested operation (see the section \fBSECURITY\fR below for details). +Different levels of security can be selected by using the optional flags +of the commands described below. +.PP +All commands provided in the master interpreter by the Safe Base reside in +the \fBsafe\fR namespace: + +.SH COMMANDS +The following commands are provided in the master interpreter: +.TP +\fB::safe::interpCreate\fR ?\fIslave\fR? ?\fIoptions...\fR? +Creates a safe interpreter, installs the aliases described in the section +\fBALIASES\fR and initializes the auto-loading and package mechanism as +specified by the supplied \fBoptions\fR. +See the \fBOPTIONS\fR section below for a description of the +optional arguments. +If the \fIslave\fR argument is omitted, a name will be generated. +\fB::safe::interpCreate\fR always returns the interpreter name. +.TP +\fB::safe::interpInit\fR \fIslave\fR ?\fIoptions...\fR? +This command is similar to \fBinterpCreate\fR except it that does not +create the safe interpreter. \fIslave\fR must have been created by some +other means, like \fBinterp create \-safe\fR. +.TP +\fB::safe::interpConfigure\fR \fIslave\fR ?\fIoptions...\fR? +If no \fIoptions\fR are given, returns the settings for all options for the +named safe interpreter as a list of options and their current values +for that \fIslave\fR. +If a single additional argument is provided, +it will return a list of 2 elements \fIname\fR and \fIvalue\fR where +\fIname\fR is the full name of that option and \fIvalue\fR the current value +for that option and the \fIslave\fR. +If more than two additional arguments are provided, it will reconfigure the +safe interpreter and change each and only the provided options. +See the section on \fBOPTIONS\fR below for options description. +Example of use: +.RS +.CS +# Create a new interp with the same configuration as "$i0" : +set i1 [eval safe::interpCreate [safe::interpConfigure $i0]] +# Get the current deleteHook +set dh [safe::interpConfigure $i0 \-del] +# Change (only) the statics loading ok attribute of an interp +# and its deleteHook (leaving the rest unchanged) : +safe::interpConfigure $i0 \-delete {foo bar} \-statics 0 ; +.CE +.RE +.TP +\fB::safe::interpDelete\fR \fIslave\fR +Deletes the safe interpreter and cleans up the corresponding +master interpreter data structures. +If a \fIdeleteHook\fR script was specified for this interpreter it is +evaluated before the interpreter is deleted, with the name of the +interpreter as an additional argument. +.TP +\fB::safe::interpFindInAccessPath\fR \fIslave\fR \fIdirectory\fR +This command finds and returns the token for the real directory +\fIdirectory\fR in the safe interpreter's current virtual access path. +It generates an error if the directory is not found. +Example of use: +.RS +.CS +$slave eval [list set tk_library [::safe::interpFindInAccessPath $name $tk_library]] +.CE +.RE +.TP +\fB::safe::interpAddToAccessPath\fR \fIslave\fR \fIdirectory\fR +This command adds \fIdirectory\fR to the virtual path maintained for the +safe interpreter in the master, and returns the token that can be used in +the safe interpreter to obtain access to files in that directory. +If the directory is already in the virtual path, it only returns the token +without adding the directory to the virtual path again. +Example of use: +.RS +.CS +$slave eval [list set tk_library [::safe::interpAddToAccessPath $name $tk_library]] +.CE +.RE +.TP +\fB::safe::setLogCmd\fR ?\fIcmd arg...\fR? +This command installs a script that will be called when interesting +life cycle events occur for a safe interpreter. +When called with no arguments, it returns the currently installed script. +When called with one argument, an empty string, the currently installed +script is removed and logging is turned off. +The script will be invoked with one additional argument, a string +describing the event of interest. +The main purpose is to help in debugging safe interpreters. +Using this facility you can get complete error messages while the safe +interpreter gets only generic error messages. +This prevents a safe interpreter from seeing messages about failures +and other events that might contain sensitive information such as real +directory names. +.RS +Example of use: +.CS +::safe::setLogCmd puts stderr +.CE +Below is the output of a sample session in which a safe interpreter +attempted to source a file not found in its virtual access path. +Note that the safe interpreter only received an error message saying that +the file was not found: +.CS +NOTICE for slave interp10 : Created +NOTICE for slave interp10 : Setting accessPath=(/foo/bar) staticsok=1 nestedok=0 deletehook=() +NOTICE for slave interp10 : auto_path in interp10 has been set to {$p(:0:)} +ERROR for slave interp10 : /foo/bar/init.tcl: no such file or directory +.CE +.RE + +.SH OPTIONS +The following options are common to +\fB::safe::interpCreate\fR, \fB::safe::interpInit\fR, +and \fB::safe::interpConfigure\fR. +Any option name can be abbreviated to its minimal +non-ambiguous name. +Option names are not case sensitive. +.TP +\fB\-accessPath\fR \fIdirectoryList\fR +This option sets the list of directories from which the safe interpreter +can \fBsource\fR and \fBload\fR files. +If this option is not specified, or if it is given as the +empty list, the safe interpreter will use the same directories as its +master for auto-loading. +See the section \fBSECURITY\fR below for more detail about virtual paths, +tokens and access control. +.TP +\fB\-statics\fR \fIboolean\fR +This option specifies if the safe interpreter will be allowed +to load statically linked packages (like \fBload {} Tk\fR). +The default value is \fBtrue\fR : +safe interpreters are allowed to load statically linked packages. +.TP +\fB\-noStatics\fR +This option is a convenience shortcut for \fB-statics false\fR and +thus specifies that the safe interpreter will not be allowed +to load statically linked packages. +.TP +\fB\-nested\fR \fIboolean\fR +This option specifies if the safe interpreter will be allowed +to load packages into its own sub-interpreters. +The default value is \fBfalse\fR : +safe interpreters are not allowed to load packages into +their own sub-interpreters. +.TP +\fB\-nestedLoadOk\fR +This option is a convenience shortcut for \fB-nested true\fR and +thus specifies the safe interpreter will be allowed +to load packages into its own sub-interpreters. +.TP +\fB\-deleteHook\fR \fIscript\fR +When this option is given an non empty \fIscript\fR, it will be +evaluated in the master with the name of +the safe interpreter as an additional argument +just before actually deleting the safe interpreter. +Giving an empty value removes any currently installed deletion hook +script for that safe interpreter. +The default value (\fB{}\fR) is not to have any deletion call back. +.SH ALIASES +The following aliases are provided in a safe interpreter: +.TP +\fBsource\fR \fIfileName\fR +The requested file, a Tcl source file, is sourced into the safe interpreter +if it is found. +The \fBsource\fR alias can only source files from directories in +the virtual path for the safe interpreter. The \fBsource\fR alias requires +the safe interpreter to +use one of the token names in its virtual path to denote the directory in +which the file to be sourced can be found. +See the section on \fBSECURITY\fR for more discussion of restrictions on +valid filenames. +.TP +\fBload\fR \fIfileName\fR +The requested file, a shared object file, is dynamically loaded into the +safe interpreter if it is found. +The filename must contain a token name mentioned in the virtual path for +the safe interpreter for it to be found successfully. +Additionally, the shared object file must contain a safe entry point; see +the manual page for the \fBload\fR command for more details. +.TP +\fBfile\fR ?\fIsubCmd args...\fR? +The \fBfile\fR alias provides access to a safe subset of the subcommands of +the \fBfile\fR command; it allows only \fBdirname\fR, \fBjoin\fR, +\fBextension\fR, \fBroot\fR, \fBtail\fR, \fBpathname\fR and \fBsplit\fR +subcommands. For more details on what these subcommands do see the manual +page for the \fBfile\fR command. +.TP +\fBencoding\fR ?\fIsubCmd args...\fR? +The \fBenconding\fR alias provides access to a safe subset of the +subcommands of the \fBencoding\fR command; it disallows setting of +the system encoding, but allows all other subcommands including +\fBsystem\fR to check the current encoding. +.TP +\fBexit\fR +The calling interpreter is deleted and its computation is stopped, but the +Tcl process in which this interpreter exists is not terminated. + +.SH SECURITY +The Safe Base does not attempt to completely prevent annoyance and +denial of service attacks. These forms of attack prevent the +application or user from temporarily using the computer to perform +useful work, for example by consuming all available CPU time or +all available screen real estate. +These attacks, while aggravating, are deemed to be of lesser importance +in general than integrity and privacy attacks that the Safe Base +is to prevent. +.PP +The commands available in a safe interpreter, in addition to +the safe set as defined in \fBinterp\fR manual page, are mediated aliases +for \fBsource\fR, \fBload\fR, \fBexit\fR, and safe subsets of +\fBfile\fR and \fBencoding\fR. The safe interpreter can also auto-load +code and it can request that packages be loaded. +.PP +Because some of these commands access the local file system, there is a +potential for information leakage about its directory structure. +To prevent this, commands that take file names as arguments in a safe +interpreter use tokens instead of the real directory names. +These tokens are translated to the real directory name while a request to, +e.g., source a file is mediated by the master interpreter. +This virtual path system is maintained in the master interpreter for each safe +interpreter created by \fB::safe::interpCreate\fR or initialized by +\fB::safe::interpInit\fR and +the path maps tokens accessible in the safe interpreter into real path +names on the local file system thus preventing safe interpreters +from gaining knowledge about the +structure of the file system of the host on which the interpreter is +executing. +The only valid file names arguments +for the \fBsource\fR and \fBload\fR aliases provided to the slave +are path in the form of +\fB[file join \fR\fItoken filename\fR\fB]\fR (ie, when using the +native file path formats: \fItoken\fR\fB/\fR\fIfilename\fR +on Unix, \fItoken\fR\fB\\\fIfilename\fR on Windows, +and \fItoken\fR\fB:\fR\fIfilename\fR on the Mac), +where \fItoken\fR is representing one of the directories +of the \fIaccessPath\fR list and \fIfilename\fR is +one file in that directory (no sub directories access are allowed). +.PP +When a token is used in a safe interpreter in a request to source or +load a file, the token is checked and +translated to a real path name and the file to be +sourced or loaded is located on the file system. +The safe interpreter never gains knowledge of the actual path name under +which the file is stored on the file system. +.PP +To further prevent potential information leakage from sensitive files that +are accidentally included in the set of files that can be sourced by a safe +interpreter, the \fBsource\fR alias restricts access to files +meeting the following constraints: the file name must +fourteen characters or shorter, must not contain more than one dot ("\fB.\fR"), +must end up with the extension \fB.tcl\fR or be called \fBtclIndex\fR. +.PP +Each element of the initial access path +list will be assigned a token that will be set in +the slave \fBauto_path\fR and the first element of that list will be set as +the \fBtcl_library\fR for that slave. +.PP +If the access path argument is not given or is the empty list, +the default behavior is to let the slave access the same packages +as the master has access to (Or to be more precise: +only packages written in Tcl (which by definition can't be dangerous +as they run in the slave interpreter) and C extensions that +provides a Safe_Init entry point). For that purpose, the master's +\fBauto_path\fR will be used to construct the slave access path. +In order that the slave successfully loads the Tcl library files +(which includes the auto-loading mechanism itself) the \fBtcl_library\fR will be +added or moved to the first position if necessary, in the +slave access path, so the slave +\fBtcl_library\fR will be the same as the master's (its real +path will still be invisible to the slave though). +In order that auto-loading works the same for the slave and +the master in this by default case, the first-level +sub directories of each directory in the master \fBauto_path\fR will +also be added (if not already included) to the slave access path. +You can always specify a more +restrictive path for which sub directories will never be searched by +explicitly specifying your directory list with the \fB\-accessPath\fR flag +instead of relying on this default mechanism. +.PP +When the \fIaccessPath\fR is changed after the first creation or +initialization (ie through \fBinterpConfigure -accessPath \fR\fIlist\fR), +an \fBauto_reset\fR is automatically evaluated in the safe interpreter +to synchronize its \fBauto_index\fR with the new token list. + +.SH "SEE ALSO" +interp(n), library(n), load(n), package(n), source(n), unknown(n) + +.SH KEYWORDS +alias, auto\-loading, auto_mkindex, load, master interpreter, safe +interpreter, slave interpreter, source diff --git a/mk4/modtcl/tcl8.3.4/doc/scan.n b/mk4/modtcl/tcl8.3.4/doc/scan.n new file mode 100644 index 0000000..5418300 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/scan.n @@ -0,0 +1,195 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" Copyright (c) 2000 Scriptics Corporation. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: scan.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH scan n 8.3 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +scan \- Parse string using conversion specifiers in the style of sscanf +.SH SYNOPSIS +\fBscan \fIstring format \fR?\fIvarName varName ...\fR? +.BE + +.SH INTRODUCTION +.PP +This command parses fields from an input string in the same fashion as the +ANSI C \fBsscanf\fR procedure and returns a count of the number of +conversions performed, or -1 if the end of the input string is reached +before any conversions have been performed. \fIString\fR gives the input +to be parsed and \fIformat\fR indicates how to parse it, using \fB%\fR +conversion specifiers as in \fBsscanf\fR. Each \fIvarName\fR gives the +name of a variable; when a field is scanned from \fIstring\fR the result is +converted back into a string and assigned to the corresponding variable. +.VS 8.3 +If no \fIvarName\fR variables are specified, then \fBscan\fR works in an +inline manner, returning the data that would otherwise be stored in the +variables as a list. In the inline case, an empty string is returned when +the end of the input string is reached before any conversions have been +performed. +.VE 8.3 + +.SH "DETAILS ON SCANNING" +.PP +\fBScan\fR operates by scanning \fIstring\fR and \fIformat\fR together. +If the next character in \fIformat\fR is a blank or tab then it +matches any number of white space characters in \fIstring\fR (including +zero). +Otherwise, if it isn't a \fB%\fR character then it +must match the next character of \fIstring\fR. +When a \fB%\fR is encountered in \fIformat\fR, it indicates +the start of a conversion specifier. +A conversion specifier contains up to four fields after the \fB%\fR: +a \fB*\fR, which indicates that the converted value is to be discarded +instead of assigned to a variable; a XPG3 position specifier; a number +indicating a maximum field width; and a conversion character. +All of these fields are optional except for the conversion character. +The fields that are present must appear in the order given above. +.PP +When \fBscan\fR finds a conversion specifier in \fIformat\fR, it +first skips any white-space characters in \fIstring\fR (unless the +specifier is \fB[\fR or \fBc\fR). +Then it converts the next input characters according to the +conversion specifier and stores the result in the variable given +by the next argument to \fBscan\fR. +.PP +If the \fB%\fR is followed by a decimal number and a \fB$\fR, as in +``\fB%2$d\fR'', then the variable to use is not taken from the next +sequential argument. Instead, it is taken from the argument indicated +by the number, where 1 corresponds to the first \fIvarName\fR. If +there are any positional specifiers in \fIformat\fR then all of the +specifiers must be positional. Every \fIvarName\fR on the argument +list must correspond to exactly one conversion specifier or an error +is generated, or in the inline case, any position can be specified +at most once and the empty positions will be filled in with empty strings. +.PP +The following conversion characters are supported: +.TP 10 +\fBd\fR +The input field must be a decimal integer. +It is read in and the value is stored in the variable as a decimal string. +.TP 10 +\fBo\fR +The input field must be an octal integer. It is read in and the +value is stored in the variable as a decimal string. +.VS 8.4 +If the value exceeds MAX_INT (017777777777 on platforms using 32-bit +integers), it will be truncated to a signed integer. Hence, 037777777777 +will appear as -1 on a 32-bit machine. +.VE 8.4 +.TP 10 +\fBx\fR +The input field must be a hexadecimal integer. It is read in +and the value is stored in the variable as a decimal string. +.VS 8.4 +If the value exceeds MAX_INT (0x7FFFFFFF on platforms using 32-bit +integers), it will be truncated to a signed integer. Hence, 0xFFFFFFFF +will appear as -1 on a 32-bit machine. +.VE 8.4 +.TP 10 +\fBu\fR +The input field must be a decimal integer. The value is stored in the +variable as an unsigned decimal integer string. +.TP 10 +\fBi\fR +The input field must be an integer. The base (i.e. decimal, octal, or +hexadecimal) is determined in the same fashion as described in +\fBexpr\fR. The value is stored in the variable as a decimal string. +.TP 10 +\fBc\fR +A single character is read in and its binary value is stored in +the variable as a decimal string. +Initial white space is not skipped in this case, so the input +field may be a white-space character. +This conversion is different from the ANSI standard in that the +input field always consists of a single character and no field +width may be specified. +.TP 10 +\fBs\fR +The input field consists of all the characters up to the next +white-space character; the characters are copied to the variable. +.TP 10 +\fBe\fR or \fBf\fR or \fBg\fR +The input field must be a floating-point number consisting +of an optional sign, a string of decimal digits possibly +containing a decimal point, and an optional exponent consisting +of an \fBe\fR or \fBE\fR followed by an optional sign and a string of +decimal digits. +It is read in and stored in the variable as a floating-point string. +.TP 10 +\fB[\fIchars\fB]\fR +The input field consists of any number of characters in +\fIchars\fR. +The matching string is stored in the variable. +If the first character between the brackets is a \fB]\fR then +it is treated as part of \fIchars\fR rather than the closing +bracket for the set. +If \fIchars\fR +contains a sequence of the form \fIa\fB\-\fIb\fR then any +character between \fIa\fR and \fIb\fR (inclusive) will match. +If the first or last character between the brackets is a \fB\-\fR, then +it is treated as part of \fIchars\fR rather than indicating a range. +.TP 10 +\fB[^\fIchars\fB]\fR +The input field consists of any number of characters not in +\fIchars\fR. +The matching string is stored in the variable. +If the character immediately following the \fB^\fR is a \fB]\fR then it is +treated as part of the set rather than the closing bracket for +the set. +If \fIchars\fR +contains a sequence of the form \fIa\fB\-\fIb\fR then any +character between \fIa\fR and \fIb\fR (inclusive) will be excluded +from the set. +If the first or last character between the brackets is a \fB\-\fR, then +it is treated as part of \fIchars\fR rather than indicating a range. +.TP 10 +\fBn\fR +No input is consumed from the input string. Instead, the total number +of chacters scanned from the input string so far is stored in the variable. +.LP +The number of characters read from the input for a conversion is the +largest number that makes sense for that particular conversion (e.g. +as many decimal digits as possible for \fB%d\fR, as +many octal digits as possible for \fB%o\fR, and so on). +The input field for a given conversion terminates either when a +white-space character is encountered or when the maximum field +width has been reached, whichever comes first. +If a \fB*\fR is present in the conversion specifier +then no variable is assigned and the next scan argument is not consumed. + +.SH "DIFFERENCES FROM ANSI SSCANF" +.PP +The behavior of the \fBscan\fR command is the same as the behavior of +the ANSI C \fBsscanf\fR procedure except for the following differences: +.IP [1] +\fB%p\fR conversion specifier is not currently supported. +.IP [2] +For \fB%c\fR conversions a single character value is +converted to a decimal string, which is then assigned to the +corresponding \fIvarName\fR; +no field width may be specified for this conversion. +.IP [3] +The \fBl\fR, \fBh\fR, and \fBL\fR modifiers are ignored; integer +values are always converted as if there were no modifier present +and real values are always converted as if the \fBl\fR modifier +were present (i.e. type \fBdouble\fR is used for the internal +representation). +.IP [4] +.VS 8.3 +If the end of the input string is reached before any conversions have been +performed and no variables are given, and empty string is returned. +.VE 8.3 + +.SH "SEE ALSO" +format(n), sscanf(3) + +.SH KEYWORDS +conversion specifier, parse, scan diff --git a/mk4/modtcl/tcl8.3.4/doc/seek.n b/mk4/modtcl/tcl8.3.4/doc/seek.n new file mode 100644 index 0000000..739837c --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/seek.n @@ -0,0 +1,64 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: seek.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH seek n 8.1 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +seek \- Change the access position for an open channel +.SH SYNOPSIS +\fBseek \fIchannelId offset \fR?\fIorigin\fR? +.BE + +.SH DESCRIPTION +.PP +Changes the current access position for \fIchannelId\fR. +\fIChannelId\fR must be a channel identifier such as returned from a +previous invocation of \fBopen\fR or \fBsocket\fR. +The \fIoffset\fR and \fIorigin\fR +arguments specify the position at which the next read or write will occur +for \fIchannelId\fR. \fIOffset\fR must be an integer (which may be +negative) and \fIorigin\fR must be one of the following: +.TP 10 +\fBstart\fR +The new access position will be \fIoffset\fR bytes from the start +of the underlying file or device. +.TP 10 +\fBcurrent\fR +The new access position will be \fIoffset\fR bytes from the current +access position; a negative \fIoffset\fR moves the access position +backwards in the underlying file or device. +.TP 10 +\fBend\fR +The new access position will be \fIoffset\fR bytes from the end of +the file or device. A negative \fIoffset\fR places the access position +before the end of file, and a positive \fIoffset\fR places the access +position after the end of file. +.LP +The \fIorigin\fR argument defaults to \fBstart\fR. +.PP +The command flushes all buffered output for the channel before the command +returns, even if the channel is in nonblocking mode. +It also discards any buffered and unread input. +This command returns an empty string. +An error occurs if this command is applied to channels whose underlying +file or device does not support seeking. +.PP +.VS 8.1 +Note that \fIoffset\fR values are byte offsets, not character +offsets. Both \fBseek\fR and \fBtell\fR operate in terms of bytes, +not characters, unlike \fBread\fR. +.VE 8.1 + +.SH "SEE ALSO" +file(n), open(n), close(n), gets(n), tell(n) + +.SH KEYWORDS +access position, file, seek diff --git a/mk4/modtcl/tcl8.3.4/doc/set.n b/mk4/modtcl/tcl8.3.4/doc/set.n new file mode 100644 index 0000000..9cae246 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/set.n @@ -0,0 +1,51 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: set.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH set n "" Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +set \- Read and write variables +.SH SYNOPSIS +\fBset \fIvarName \fR?\fIvalue\fR? +.BE + +.SH DESCRIPTION +.PP +Returns the value of variable \fIvarName\fR. +If \fIvalue\fR is specified, then set +the value of \fIvarName\fR to \fIvalue\fR, creating a new variable +if one doesn't already exist, and return its value. +If \fIvarName\fR contains an open parenthesis and ends with a +close parenthesis, then it refers to an array element: the characters +before the first open parenthesis are the name of the array, +and the characters between the parentheses are the index within the array. +Otherwise \fIvarName\fR refers to a scalar variable. +Normally, \fIvarName\fR is unqualified +(does not include the names of any containing namespaces), +and the variable of that name in the current namespace is read or written. +If \fIvarName\fR includes namespace qualifiers +(in the array name if it refers to an array element), +the variable in the specified namespace is read or written. +.PP +If no procedure is active, +then \fIvarName\fR refers to a namespace variable +(global variable if the current namespace is the global namespace). +If a procedure is active, then \fIvarName\fR refers to a parameter +or local variable of the procedure unless the \fBglobal\fR command +was invoked to declare \fIvarName\fR to be global, +or unless a \fBvariable\fR command +was invoked to declare \fIvarName\fR to be a namespace variable. + +.SH "SEE ALSO" +expr(n), proc(n), trace(n), unset(n) + +.SH KEYWORDS +read, write, variable diff --git a/mk4/modtcl/tcl8.3.4/doc/socket.n b/mk4/modtcl/tcl8.3.4/doc/socket.n new file mode 100644 index 0000000..145a632 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/socket.n @@ -0,0 +1,134 @@ +'\" +'\" Copyright (c) 1996 Sun Microsystems, Inc. +'\" Copyright (c) 1998-1999 by Scriptics Corporation. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: socket.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +.so man.macros +.TH socket n 8.0 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +socket \- Open a TCP network connection +.SH SYNOPSIS +.sp +\fBsocket \fR?\fIoptions\fR? \fIhost port\fR +.sp +\fBsocket\fR \fB\-server \fIcommand\fR ?\fIoptions\fR? \fIport\fR +.BE + +.SH DESCRIPTION +.PP +This command opens a network socket and returns a channel +identifier that may be used in future invocations of commands like +\fBread\fR, \fBputs\fR and \fBflush\fR. +At present only the TCP network protocol is supported; future +releases may include support for additional protocols. +The \fBsocket\fR command may be used to open either the client or +server side of a connection, depending on whether the \fB\-server\fR +switch is specified. + +.SH "CLIENT SOCKETS" +.PP +If the \fB\-server\fR option is not specified, then the client side of a +connection is opened and the command returns a channel identifier +that can be used for both reading and writing. +\fIPort\fR and \fIhost\fR specify a port +to connect to; there must be a server accepting connections on +this port. \fIPort\fR is an integer port number and \fIhost\fR +is either a domain-style name such as \fBwww.sunlabs.com\fR or +a numerical IP address such as \fB127.0.0.1\fR. +Use \fIlocalhost\fR to refer to the host on which the command is invoked. +.PP +The following options may also be present before \fIhost\fR +to specify additional information about the connection: +.TP +\fB\-myaddr\fI addr\fR +\fIAddr\fR gives the domain-style name or numerical IP address of +the client-side network interface to use for the connection. +This option may be useful if the client machine has multiple network +interfaces. If the option is omitted then the client-side interface +will be chosen by the system software. +.TP +\fB\-myport\fI port\fR +\fIPort\fR specifies an integer port number to use for the client's +side of the connection. If this option is omitted, the client's +port number will be chosen at random by the system software. +.TP +\fB\-async\fR +The \fB\-async\fR option will cause the client socket to be connected +asynchronously. This means that the socket will be created immediately but +may not yet be connected to the server, when the call to \fBsocket\fR +returns. When a \fBgets\fR or \fBflush\fR is done on the socket before the +connection attempt succeeds or fails, if the socket is in blocking mode, the +operation will wait until the connection is completed or fails. If the +socket is in nonblocking mode and a \fBgets\fR or \fBflush\fR is done on +the socket before the connection attempt succeeds or fails, the operation +returns immediately and \fBfblocked\fR on the socket returns 1. + +.SH "SERVER SOCKETS" +.PP +If the \fB\-server\fR option is specified then the new socket +will be a server for the port given by \fIport\fR. +Tcl will automatically accept connections to the given port. +For each connection Tcl will create a new channel that may be used to +communicate with the client. Tcl then invokes \fIcommand\fR +with three additional arguments: the name of the new channel, the +address, in network address notation, of the client's host, and +the client's port number. +.PP +The following additional option may also be specified before \fIhost\fR: +.TP +\fB\-myaddr\fI addr\fR +\fIAddr\fR gives the domain-style name or numerical IP address of +the server-side network interface to use for the connection. +This option may be useful if the server machine has multiple network +interfaces. If the option is omitted then the server socket is bound +to the special address INADDR_ANY so that it can accept connections from +any interface. +.PP +Server channels cannot be used for input or output; their sole use is to +accept new client connections. The channels created for each incoming +client connection are opened for input and output. Closing the server +channel shuts down the server so that no new connections will be +accepted; however, existing connections will be unaffected. +.PP +Server sockets depend on the Tcl event mechanism to find out when +new connections are opened. If the application doesn't enter the +event loop, for example by invoking the \fBvwait\fR command or +calling the C procedure \fBTcl_DoOneEvent\fR, then no connections +will be accepted. + +.SH "CONFIGURATION OPTIONS" +The \fBfconfigure\fR command can be used to query several readonly +configuration options for socket channels: +.VS 8.0.5 +.TP +\fB\-error\fR +This option gets the current error status of the given socket. This +is useful when you need to determine if an asynchronous connect +operation succeeded. If there was an error, the error message is +returned. If there was no error, an empty string is returned. +.VE 8.0.5 +.TP +\fB\-sockname\fR +This option returns a list of three elements, the address, the host name +and the port number for the socket. If the host name cannot be computed, +the second element is identical to the address, the first element of the +list. +.TP +\fB\-peername\fR +This option is not supported by server sockets. For client and accepted +sockets, this option returns a list of three elements; these are the +address, the host name and the port to which the peer socket is connected +or bound. If the host name cannot be computed, the second element of the +list is identical to the address, its first element. +.PP + +.SH "SEE ALSO" +flush(n), open(n), read(n) + +.SH KEYWORDS +bind, channel, connection, domain name, host, network address, socket, tcp diff --git a/mk4/modtcl/tcl8.3.4/doc/source.n b/mk4/modtcl/tcl8.3.4/doc/source.n new file mode 100644 index 0000000..7567fdf --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/source.n @@ -0,0 +1,44 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: source.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH source n "" Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +source \- Evaluate a file or resource as a Tcl script +.SH SYNOPSIS +\fBsource \fIfileName\fR +.sp +\fBsource\fR \fB\-rsrc \fIresourceName \fR?\fIfileName\fR? +.sp +\fBsource\fR \fB\-rsrcid \fIresourceId \fR?\fIfileName\fR? +.BE + +.SH DESCRIPTION +.PP +This command takes the contents of the specified file or resource +and passes it to the Tcl interpreter as a text script. The return +value from \fBsource\fR is the return value of the last command +executed in the script. If an error occurs in evaluating the contents +of the script then the \fBsource\fR command will return that error. +If a \fBreturn\fR command is invoked from within the script then the +remainder of the file will be skipped and the \fBsource\fR command +will return normally with the result from the \fBreturn\fR command. + +The \fI\-rsrc\fR and \fI\-rsrcid\fR forms of this command are only +available on Macintosh computers. These versions of the command +allow you to source a script from a \fBTEXT\fR resource. You may specify +what \fBTEXT\fR resource to source by either name or id. By default Tcl +searches all open resource files, which include the current +application and any loaded C extensions. Alternatively, you may +specify the \fIfileName\fR where the \fBTEXT\fR resource can be found. + +.SH KEYWORDS +file, script diff --git a/mk4/modtcl/tcl8.3.4/doc/split.n b/mk4/modtcl/tcl8.3.4/doc/split.n new file mode 100644 index 0000000..87157d4 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/split.n @@ -0,0 +1,47 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: split.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH split n "" Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +split \- Split a string into a proper Tcl list +.SH SYNOPSIS +\fBsplit \fIstring \fR?\fIsplitChars\fR? +.BE + +.SH DESCRIPTION +.PP +Returns a list created by splitting \fIstring\fR at each character +that is in the \fIsplitChars\fR argument. +Each element of the result list will consist of the +characters from \fIstring\fR that lie between instances of the +characters in \fIsplitChars\fR. +Empty list elements will be generated if \fIstring\fR contains +adjacent characters in \fIsplitChars\fR, or if the first or last +character of \fIstring\fR is in \fIsplitChars\fR. +If \fIsplitChars\fR is an empty string then each character of +\fIstring\fR becomes a separate element of the result list. +\fISplitChars\fR defaults to the standard white-space characters. +For example, +.CS +\fBsplit "comp.unix.misc" .\fR +.CE +returns \fB"comp unix misc"\fR and +.CS +\fBsplit "Hello world" {}\fR +.CE +returns \fB"H e l l o { } w o r l d"\fR. + +.SH "SEE ALSO" +join(n), list(n), string(n) + +.SH KEYWORDS +list, split, string diff --git a/mk4/modtcl/tcl8.3.4/doc/string.n b/mk4/modtcl/tcl8.3.4/doc/string.n new file mode 100644 index 0000000..298212c --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/string.n @@ -0,0 +1,341 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: string.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH string n 8.1 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +string \- Manipulate strings +.SH SYNOPSIS +\fBstring \fIoption arg \fR?\fIarg ...?\fR +.BE + +.SH DESCRIPTION +.PP +Performs one of several string operations, depending on \fIoption\fR. +The legal \fIoption\fRs (which may be abbreviated) are: +.VS 8.1 +.TP +\fBstring bytelength \fIstring\fR +Returns a decimal string giving the number of bytes used to represent +\fIstring\fR in memory. Because UTF\-8 uses one to three bytes to +represent Unicode characters, the byte length will not be the same as +the character length in general. The cases where a script cares about +the byte length are rare. In almost all cases, you should use the +\fBstring length\fR operation. Refer to the \fBTcl_NumUtfChars\fR +manual entry for more details on the UTF\-8 representation. +.TP +\fBstring compare\fR ?\fB\-nocase\fR? ?\fB\-length int\fR? \fIstring1 string2\fR +.VE 8.1 +Perform a character-by-character comparison of strings \fIstring1\fR and +\fIstring2\fR. Returns +\-1, 0, or 1, depending on whether \fIstring1\fR is lexicographically +less than, equal to, or greater than \fIstring2\fR. +.VS 8.1 +If \fB\-length\fR is specified, then only the first \fIlength\fR characters +are used in the comparison. If \fB\-length\fR is negative, it is +ignored. If \fB\-nocase\fR is specified, then the strings are +compared in a case-insensitive manner. +.TP +\fBstring equal\fR ?\fB\-nocase\fR? ?\fB-length int\fR? \fIstring1 string2\fR +Perform a character-by-character comparison of strings +\fIstring1\fR and \fIstring2\fR. Returns 1 if \fIstring1\fR and +\fIstring2\fR are identical, or 0 when not. If \fB\-length\fR is +specified, then only the first \fIlength\fR characters are used in the +comparison. If \fB\-length\fR is negative, it is ignored. If +\fB\-nocase\fR is specified, then the strings are compared in a +case-insensitive manner. +.TP +\fBstring first \fIstring1 string2\fR ?\fIstartIndex\fR? +.VE 8.1 +Search \fIstring2\fR for a sequence of characters that exactly match +the characters in \fIstring1\fR. If found, return the index of the +first character in the first such match within \fIstring2\fR. If not +found, return \-1. +.VS 8.1 +If \fIstartIndex\fR is specified (in any of the forms accepted by the +\fBindex\fR method), then the search is constrained to start with the +character in \fIstring2\fR specified by the index. For example, +.RS +.CS +\fBstring first a 0a23456789abcdef 5\fR +.CE +will return \fB10\fR, but +.CS +\fBstring first a 0123456789abcdef 11\fR +.CE +will return \fB\-1\fR. +.RE +.VE 8.1 +.TP +\fBstring index \fIstring charIndex\fR +Returns the \fIcharIndex\fR'th character of the \fIstring\fR +argument. A \fIcharIndex\fR of 0 corresponds to the first +character of the string. +.VS 8.1 +\fIcharIndex\fR may be specified as +follows: +.RS +.IP \fIinteger\fR 10 +The char specified at this integral index +.IP \fBend\fR 10 +The last char of the string. +.IP \fBend\-\fIinteger\fR 10 +The last char of the string minus the specified integer +offset (e.g. \fBend\-1\fR would refer to the "c" in "abcd"). +.PP +.VE 8.1 +If \fIcharIndex\fR is less than 0 or greater than +or equal to the length of the string then an empty string is +returned. +.VS 8.1 +.RE +.TP +\fBstring is \fIclass\fR ?\fB\-strict\fR? ?\fB\-failindex \fIvarname\fR? \fIstring\fR +Returns 1 if \fIstring\fR is a valid member of the specified character +class, otherwise returns 0. If \fB\-strict\fR is specified, then an +empty string returns 0, otherwise and empty string will return 1 on +any class. If \fB\-failindex\fR is specified, then if the function +returns 0, the index in the string where the class was no longer valid +will be stored in the variable named \fIvarname\fR. The \fIvarname\fR +will not be set if the function returns 1. The following character classes +are recognized (the class name can be abbreviated): +.RS +.IP \fBalnum\fR 10 +Any Unicode alphabet or digit character. +.IP \fBalpha\fR 10 +Any Unicode alphabet character. +.IP \fBascii\fR 10 +Any character with a value less than \\u0080 (those that +are in the 7\-bit ascii range). +.IP \fBboolean\fR 10 +Any of the forms allowed to \fBTcl_GetBoolean\fR. +.IP \fBcontrol\fR 10 +Any Unicode control character. +.IP \fBdigit\fR 10 +Any Unicode digit character. Note that this includes characters +outside of the [0\-9] range. +.IP \fBdouble\fR 10 +Any of the valid forms for a double in Tcl, with optional surrounding +whitespace. In case of under/overflow in the value, 0 is returned +and the \fIvarname\fR will contain \-1. +.IP \fBfalse\fR 10 +Any of the forms allowed to \fBTcl_GetBoolean\fR where the value is false. +.IP \fBgraph\fR 10 +Any Unicode printing character, except space. +.IP \fBinteger\fR 10 +Any of the valid forms for an integer in Tcl, with optional surrounding +whitespace. In case of under/overflow in the value, 0 is returned +and the \fIvarname\fR will contain \-1. +.IP \fBlower\fR 10 +Any Unicode lower case alphabet character. +.IP \fBprint\fR 10 +Any Unicode printing character, including space. +.IP \fBpunct\fR 10 +Any Unicode punctuation character. +.IP \fBspace\fR 10 +Any Unicode space character. +.IP \fBtrue\fR 10 +Any of the forms allowed to \fBTcl_GetBoolean\fR where the value is true. +.IP \fBupper\fR 10 +Any upper case alphabet character in the Unicode character set. +.IP \fBwordchar\fR 10 +Any Unicode word character. That is any alphanumeric character, +and any Unicode connector punctuation characters (e.g. underscore). +.IP \fBxdigit\fR 10 +Any hexadecimal digit character ([0\-9A\-Fa\-f]). +.PP +In the case of \fBboolean\fR, \fBtrue\fR and \fBfalse\fR, if the +function will return 0, then the \fIvarname\fR will always be set to 0, +due to the varied nature of a valid boolean value. +.RE +.TP +\fBstring last \fIstring1 string2\fR ?\fIstartIndex\fR? +.VE 8.1 +Search \fIstring2\fR for a sequence of characters that exactly match +the characters in \fIstring1\fR. If found, return the index of the +first character in the last such match within \fIstring2\fR. If there +is no match, then return \-1. +.VS 8.1 +If \fIstartIndex\fR is specified (in any of the forms accepted by the +\fBindex\fR method), then only the characters in \fIstring2\fR at or before the +specified \fIstartIndex\fR will be considered by the search. For example, +.RS +.CS +\fBstring last a 0a23456789abcdef 15\fR +.CE +will return \fB10\fR, but +.CS +\fBstring last a 0a23456789abcdef 9\fR +.CE +will return \fB1\fR. +.RE +.VE 8.1 +.TP +\fBstring length \fIstring\fR +Returns a decimal string giving the number of characters in +\fIstring\fR. Note that this is not necessarily the same as the +number of bytes used to store the string. +.VS 8.1 +.TP +\fBstring map\fR ?\fB\-nocase\fR? \fIcharMap string\fR +Replaces characters in \fIstring\fR based on the key-value pairs in +\fIcharMap\fR. \fIcharMap\fR is a list of \fIkey value key value\fR ... +as in the form returned by \fBarray get\fR. Each instance of a +key in the string will be replaced with its corresponding value. If +\fB\-nocase\fR is specified, then matching is done without regard to +case differences. Both \fIkey\fR and \fIvalue\fR may be multiple +characters. Replacement is done in an ordered manner, so the key appearing +first in the list will be checked first, and so on. \fIstring\fR is +only iterated over once, so earlier key replacements will have no +affect for later key matches. For example, +.RS +.CS +\fBstring map {abc 1 ab 2 a 3 1 0} 1abcaababcabababc\fR +.CE +will return the string \fB01321221\fR. +.RE +.TP +\fBstring match\fR ?\fB\-nocase\fR? \fIpattern\fR \fIstring\fR +.VE 8.1 +See if \fIpattern\fR matches \fIstring\fR; return 1 if it does, 0 +if it doesn't. +.VS 8.1 +If \fB\-nocase\fR is specified, then the pattern attempts to match +against the string in a case insensitive manner. +.VE 8.1 +For the two strings to match, their contents +must be identical except that the following special sequences +may appear in \fIpattern\fR: +.RS +.IP \fB*\fR 10 +Matches any sequence of characters in \fIstring\fR, +including a null string. +.IP \fB?\fR 10 +Matches any single character in \fIstring\fR. +.IP \fB[\fIchars\fB]\fR 10 +Matches any character in the set given by \fIchars\fR. If a sequence +of the form +\fIx\fB\-\fIy\fR appears in \fIchars\fR, then any character +between \fIx\fR and \fIy\fR, inclusive, will match. +.VS 8.1 +When used with \fB\-nocase\fR, the end points of the range are converted +to lower case first. Whereas {[A\-z]} matches '_' when matching +case-sensitively ('_' falls between the 'Z' and 'a'), with \fB\-nocase\fR +this is considered like {[A\-Za\-z]} (and probably what was meant in the +first place). +.VE 8.1 +.IP \fB\e\fIx\fR 10 +Matches the single character \fIx\fR. This provides a way of +avoiding the special interpretation of the characters +\fB*?[]\e\fR in \fIpattern\fR. +.RE +.TP +\fBstring range \fIstring first last\fR +Returns a range of consecutive characters from \fIstring\fR, starting +with the character whose index is \fIfirst\fR and ending with the +character whose index is \fIlast\fR. An index of 0 refers to the +.VS 8.1 +first character of the string. \fIfirst\fR and \fIlast\fR may be +specified as for the \fBindex\fR method. +.VE 8.1 +If \fIfirst\fR is less than zero then it is treated as if it were zero, and +if \fIlast\fR is greater than or equal to the length of the string then +it is treated as if it were \fBend\fR. If \fIfirst\fR is greater than +\fIlast\fR then an empty string is returned. +.VS 8.1 +.TP +\fBstring repeat \fIstring count\fR +Returns \fIstring\fR repeated \fIcount\fR number of times. +.TP +\fBstring replace \fIstring first last\fR ?\fInewstring\fR? +Removes a range of consecutive characters from \fIstring\fR, starting +with the character whose index is \fIfirst\fR and ending with the +character whose index is \fIlast\fR. An index of 0 refers to the +first character of the string. \fIFirst\fR and \fIlast\fR may be +specified as for the \fBindex\fR method. If \fInewstring\fR is +specified, then it is placed in the removed character range. +If \fIfirst\fR is less than zero then it is treated as if it were zero, and +if \fIlast\fR is greater than or equal to the length of the string then +it is treated as if it were \fBend\fR. If \fIfirst\fR is greater than +\fIlast\fR or the length of the initial string, or \fIlast\fR is less +than 0, then the initial string is returned untouched. +.TP +\fBstring tolower \fIstring\fR ?\fIfirst\fR? ?\fIlast\fR? +Returns a value equal to \fIstring\fR except that all upper (or title) case +letters have been converted to lower case. If \fIfirst\fR is specified, it +refers to the first char index in the string to start modifying. If +\fIlast\fR is specified, it refers to the char index in the string to stop +at (inclusive). \fIfirst\fR and \fIlast\fR may be +specified as for the \fBindex\fR method. +.TP +\fBstring totitle \fIstring\fR ?\fIfirst\fR? ?\fIlast\fR? +Returns a value equal to \fIstring\fR except that the first character +in \fIstring\fR is converted to its Unicode title case variant (or upper +case if there is no title case variant) and the rest of the string is +converted to lower case. If \fIfirst\fR is specified, it +refers to the first char index in the string to start modifying. If +\fIlast\fR is specified, it refers to the char index in the string to stop +at (inclusive). \fIfirst\fR and \fIlast\fR may be +specified as for the \fBindex\fR method. +.TP +\fBstring toupper \fIstring\fR ?\fIfirst\fR? ?\fIlast\fR? +Returns a value equal to \fIstring\fR except that all lower (or title) case +letters have been converted to upper case. If \fIfirst\fR is specified, it +refers to the first char index in the string to start modifying. If +\fIlast\fR is specified, it refers to the char index in the string to stop +at (inclusive). \fIfirst\fR and \fIlast\fR may be specified as for the +\fBindex\fR method. +.VE 8.1 +.TP +\fBstring trim \fIstring\fR ?\fIchars\fR? +Returns a value equal to \fIstring\fR except that any leading +or trailing characters from the set given by \fIchars\fR are +removed. +If \fIchars\fR is not specified then white space is removed +(spaces, tabs, newlines, and carriage returns). +.TP +\fBstring trimleft \fIstring\fR ?\fIchars\fR? +Returns a value equal to \fIstring\fR except that any +leading characters from the set given by \fIchars\fR are +removed. +If \fIchars\fR is not specified then white space is removed +(spaces, tabs, newlines, and carriage returns). +.TP +\fBstring trimright \fIstring\fR ?\fIchars\fR? +Returns a value equal to \fIstring\fR except that any +trailing characters from the set given by \fIchars\fR are +removed. +If \fIchars\fR is not specified then white space is removed +(spaces, tabs, newlines, and carriage returns). +.VS 8.1 +.TP +\fBstring wordend \fIstring charIndex\fR +Returns the index of the character just after the last one in the word +containing character \fIcharIndex\fR of \fIstring\fR. \fIcharIndex\fR +may be specified as for the \fBindex\fR method. A word is +considered to be any contiguous range of alphanumeric (Unicode letters +or decimal digits) or underscore (Unicode connector punctuation) +characters, or any single character other than these. +.TP +\fBstring wordstart \fIstring charIndex\fR +Returns the index of the first character in the word containing +character \fIcharIndex\fR of \fIstring\fR. \fIcharIndex\fR may be +specified as for the \fBindex\fR method. A word is considered to be any +contiguous range of alphanumeric (Unicode letters or decimal digits) +or underscore (Unicode connector punctuation) characters, or any +single character other than these. +.VE 8.1 + +.SH "SEE ALSO" +expr(n), list(n) + +.SH KEYWORDS +case conversion, compare, index, match, pattern, string, word, equal, ctype diff --git a/mk4/modtcl/tcl8.3.4/doc/subst.n b/mk4/modtcl/tcl8.3.4/doc/subst.n new file mode 100644 index 0000000..4ce227e --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/subst.n @@ -0,0 +1,51 @@ +'\" +'\" Copyright (c) 1994 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: subst.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH subst n 7.4 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +subst \- Perform backslash, command, and variable substitutions +.SH SYNOPSIS +\fBsubst \fR?\fB\-nobackslashes\fR? ?\fB\-nocommands\fR? ?\fB\-novariables\fR? \fIstring\fR +.BE + +.SH DESCRIPTION +.PP +This command performs variable substitutions, command substitutions, +and backslash substitutions on its \fIstring\fR argument and +returns the fully-substituted result. +The substitutions are performed in exactly the same way as for +Tcl commands. +As a result, the \fIstring\fR argument is actually substituted twice, +once by the Tcl parser in the usual fashion for Tcl commands, and +again by the \fIsubst\fR command. +.PP +If any of the \fB\-nobackslashes\fR, \fB\-nocommands\fR, or +\fB\-novariables\fR are specified, then the corresponding substitutions +are not performed. +For example, if \fB\-nocommands\fR is specified, no command substitution +is performed: open and close brackets are treated as ordinary characters +with no special interpretation. +.PP +Note: when it performs its substitutions, \fIsubst\fR does not +give any special treatment to double quotes or curly braces. For +example, the script +.CS +\fBset a 44 +subst {xyz {$a}}\fR +.CE +returns ``\fBxyz {44}\fR'', not ``\fBxyz {$a}\fR''. + +.SH "SEE ALSO" +eval(n) + +.SH KEYWORDS +backslash substitution, command substitution, variable substitution diff --git a/mk4/modtcl/tcl8.3.4/doc/switch.n b/mk4/modtcl/tcl8.3.4/doc/switch.n new file mode 100644 index 0000000..a058a77 --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/switch.n @@ -0,0 +1,117 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1997 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: switch.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH switch n 7.0 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +switch \- Evaluate one of several scripts, depending on a given value +.SH SYNOPSIS +\fBswitch \fR?\fIoptions\fR?\fI string pattern body \fR?\fIpattern body \fR...? +.sp +\fBswitch \fR?\fIoptions\fR?\fI string \fR{\fIpattern body \fR?\fIpattern body \fR...?} +.BE + +.SH DESCRIPTION +.PP +The \fBswitch\fR command matches its \fIstring\fR argument against each of +the \fIpattern\fR arguments in order. +As soon as it finds a \fIpattern\fR that matches \fIstring\fR it +evaluates the following \fIbody\fR argument by passing it recursively +to the Tcl interpreter and returns the result of that evaluation. +If the last \fIpattern\fR argument is \fBdefault\fR then it matches +anything. +If no \fIpattern\fR argument +matches \fIstring\fR and no default is given, then the \fBswitch\fR +command returns an empty string. +.PP +If the initial arguments to \fBswitch\fR start with \fB\-\fR then +they are treated as options. The following options are +currently supported: +.TP 10 +\fB\-exact\fR +Use exact matching when comparing \fIstring\fR to a pattern. This +is the default. +.TP 10 +\fB\-glob\fR +When matching \fIstring\fR to the patterns, use glob-style matching +(i.e. the same as implemented by the \fBstring match\fR command). +.TP 10 +\fB\-regexp\fR +When matching \fIstring\fR to the patterns, use regular +expression matching +(as described in the \fBre_syntax\fR reference page). +.TP 10 +\fB\-\|\-\fR +Marks the end of options. The argument following this one will +be treated as \fIstring\fR even if it starts with a \fB\-\fR. +.PP +Two syntaxes are provided for the \fIpattern\fR and \fIbody\fR arguments. +The first uses a separate argument for each of the patterns and commands; +this form is convenient if substitutions are desired on some of the +patterns or commands. +The second form places all of the patterns and commands together into +a single argument; the argument must have proper list structure, with +the elements of the list being the patterns and commands. +The second form makes it easy to construct multi-line switch commands, +since the braces around the whole list make it unnecessary to include a +backslash at the end of each line. +Since the \fIpattern\fR arguments are in braces in the second form, +no command or variable substitutions are performed on them; this makes +the behavior of the second form different than the first form in some +cases. +.PP +If a \fIbody\fR is specified as ``\fB\-\fR'' it means that the \fIbody\fR +for the next pattern should also be used as the body for this +pattern (if the next pattern also has a body of ``\fB\-\fR'' +then the body after that is used, and so on). +This feature makes it possible to share a single \fIbody\fR among +several patterns. +.PP +Beware of how you place comments in \fBswitch\fR commands. Comments +should only be placed \fBinside\fR the execution body of one of the +patterns, and not intermingled with the patterns. +.PP +Below are some examples of \fBswitch\fR commands: +.CS +\fBswitch\0abc\0a\0\-\0b\0{format 1}\0abc\0{format 2}\0default\0{format 3}\fR +.CE +will return \fB2\fR, +.CS +\fBswitch\0\-regexp\0aaab { + ^a.*b$\0\- + b\0{format 1} + a*\0{format 2} + default\0{format 3} +}\fR +.CE +will return \fB1\fR, and +.CS +\fBswitch\0xyz { + a + \- + b + { + # Correct Comment Placement + format 1 + } + a* + {format 2} + default + {format 3} +}\fR +.CE +will return \fB3\fR. + +.SH "SEE ALSO" +for(n), if(n), regexp(n) + +.SH KEYWORDS +switch, match, regular expression diff --git a/mk4/modtcl/tcl8.3.4/doc/tclsh.1 b/mk4/modtcl/tcl8.3.4/doc/tclsh.1 new file mode 100644 index 0000000..0cb781d --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/tclsh.1 @@ -0,0 +1,127 @@ +'\" +'\" Copyright (c) 1993 The Regents of the University of California. +'\" Copyright (c) 1994-1996 Sun Microsystems, Inc. +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: tclsh.1,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH tclsh 1 "" Tcl "Tcl Applications" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +tclsh \- Simple shell containing Tcl interpreter +.SH SYNOPSIS +\fBtclsh\fR ?\fIfileName arg arg ...\fR? +.BE + +.SH DESCRIPTION +.PP +\fBTclsh\fR is a shell-like application that reads Tcl commands +from its standard input or from a file and evaluates them. +If invoked with no arguments then it runs interactively, reading +Tcl commands from standard input and printing command results and +error messages to standard output. +It runs until the \fBexit\fR command is invoked or until it +reaches end-of-file on its standard input. +If there exists a file \fB.tclshrc\fR (or \fBtclshrc.tcl\fR on +the Windows platforms) in the home directory of +the user, \fBtclsh\fR evaluates the file as a Tcl script +just before reading the first command from standard input. + +.SH "SCRIPT FILES" +.PP +If \fBtclsh\fR is invoked with arguments then the first argument +is the name of a script file and any additional arguments +are made available to the script as variables (see below). +Instead of reading commands from standard input \fBtclsh\fR will +read Tcl commands from the named file; \fBtclsh\fR will exit +when it reaches the end of the file. +There is no automatic evaluation of \fB.tclshrc\fR in this +case, but the script file can always \fBsource\fR it if desired. +.PP +If you create a Tcl script in a file whose first line is +.CS +\fB#!/usr/local/bin/tclsh\fR +.CE +then you can invoke the script file directly from your shell if +you mark the file as executable. +This assumes that \fBtclsh\fR has been installed in the default +location in /usr/local/bin; if it's installed somewhere else +then you'll have to modify the above line to match. +Many UNIX systems do not allow the \fB#!\fR line to exceed about +30 characters in length, so be sure that the \fBtclsh\fR +executable can be accessed with a short file name. +.PP +An even better approach is to start your script files with the +following three lines: +.CS +\fB#!/bin/sh +# the next line restarts using tclsh \e +exec tclsh "$0" "$@"\fR +.CE +This approach has three advantages over the approach in the previous +paragraph. First, the location of the \fBtclsh\fR binary doesn't have +to be hard-wired into the script: it can be anywhere in your shell +search path. Second, it gets around the 30-character file name limit +in the previous approach. +Third, this approach will work even if \fBtclsh\fR is +itself a shell script (this is done on some systems in order to +handle multiple architectures or operating systems: the \fBtclsh\fR +script selects one of several binaries to run). The three lines +cause both \fBsh\fR and \fBtclsh\fR to process the script, but the +\fBexec\fR is only executed by \fBsh\fR. +\fBsh\fR processes the script first; it treats the second +line as a comment and executes the third line. +The \fBexec\fR statement cause the shell to stop processing and +instead to start up \fBtclsh\fR to reprocess the entire script. +When \fBtclsh\fR starts up, it treats all three lines as comments, +since the backslash at the end of the second line causes the third +line to be treated as part of the comment on the second line. +.PP +.VS +You should note that it is also common practise to install tclsh with +its version number as part of the name. This has the advantage of +allowing multiple versions of Tcl to exist on the same system at once, +but also the disadvantage of making it harder to write scripts that +start up uniformly across different versions of Tcl. +.VE + +.SH "VARIABLES" +.PP +\fBTclsh\fR sets the following Tcl variables: +.TP 15 +\fBargc\fR +Contains a count of the number of \fIarg\fR arguments (0 if none), +not including the name of the script file. +.TP 15 +\fBargv\fR +Contains a Tcl list whose elements are the \fIarg\fR arguments, +in order, or an empty string if there are no \fIarg\fR arguments. +.TP 15 +\fBargv0\fR +Contains \fIfileName\fR if it was specified. +Otherwise, contains the name by which \fBtclsh\fR was invoked. +.TP 15 +\fBtcl_interactive\fR +Contains 1 if \fBtclsh\fR is running interactively (no +\fIfileName\fR was specified and standard input is a terminal-like +device), 0 otherwise. + +.SH PROMPTS +.PP +When \fBtclsh\fR is invoked interactively it normally prompts for each +command with ``\fB% \fR''. You can change the prompt by setting the +variables \fBtcl_prompt1\fR and \fBtcl_prompt2\fR. If variable +\fBtcl_prompt1\fR exists then it must consist of a Tcl script +to output a prompt; instead of outputting a prompt \fBtclsh\fR +will evaluate the script in \fBtcl_prompt1\fR. +The variable \fBtcl_prompt2\fR is used in a similar way when +a newline is typed but the current command isn't yet complete; +if \fBtcl_prompt2\fR isn't set then no prompt is output for +incomplete commands. + +.SH KEYWORDS +argument, interpreter, prompt, script file, shell diff --git a/mk4/modtcl/tcl8.3.4/doc/tcltest.n b/mk4/modtcl/tcl8.3.4/doc/tcltest.n new file mode 100644 index 0000000..02fef8e --- /dev/null +++ b/mk4/modtcl/tcl8.3.4/doc/tcltest.n @@ -0,0 +1,759 @@ +'\" +'\" Copyright (c) 1990-1994 The Regents of the University of California +'\" Copyright (c) 1994-1997 Sun Microsystems, Inc. +'\" Copyright (c) 1998-1999 Scriptics Corporation +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +'\" RCS: @(#) $Id: tcltest.n,v 1.1.1.1 2003/10/29 20:29:11 aleigh Exp $ +'\" +.so man.macros +.TH "Tcltest" n 8.2 Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +Tcltest \- Test harness support code and utilities +.SH SYNOPSIS +\fBpackage require tcltest ?1.0?\fP +.sp +\fB::tcltest::test \fIname desc ?constraint? script expectedAnswer\fR +.sp +\fB::tcltest::cleanupTests \fI?runningMultipleTests?\fR +.sp +\fB::tcltest::getMatchingTestFiles\fR +.sp +\fB::tcltest::loadTestedCommands\fR +.sp +\fB::tcltest::makeFile \fIcontents name\fR +.sp +\fB::tcltest::removeFile \fIname\fR +.sp +\fB::tcltest::makeDirectory \fIname\fR +.sp +\fB::tcltest::removeDirectory \fIname\fR +.sp +\fB::tcltest::viewFile \fIname\fR +.sp +\fB::tcltest::normalizeMsg \fImsg\fR +.sp +\fB::tcltest::bytestring \fIstring\fR +.sp +\fB::tcltest::saveState\fR +.sp +\fB::tcltest::restoreState\fR +.sp +\fB::tcltest::threadReap\fR +.BE +.SH DESCRIPTION +.PP +The \fBtcltest\fR package provides the user with utility tools for +writing and running tests in the Tcl test suite. It can also be used +to create a customized test harness for an extension. +.PP +The Tcl test suite consists of multiple .test files, each of which +contains multiple test cases. Each test case consists of a call to +the test command, which specifies the name of test, a short +description, any constraints that apply to the test case, the script +to be run, and expected results. See the sections \fI"Tests,"\fR +\fI"Test Constraints,"\fR and \fI"Test Files and How to Run Them"\fR +for more details. +.PP +It is also possible to add to this test harness to create your own +customized test harness implementation. For more defails, see the +section \fI"How to Customize the Test Harness"\fR. +.PP +This approach to testing was designed and initially implemented by +Mary Ann May-Pumphrey of Sun Microsystems in the early 1990's. Many +thanks to her for donating her work back to the public Tcl release. +.SH COMMANDS +.TP +\fB::tcltest::test\fP \fIname desc ?constraints? script expectedAnswer\fR +The \fB::tcltest::test\fR command runs\fIscript\fR and compares +its result to \fIexpectedAnswer\fR. It prints an error message if the two do +not match. If \fB::tcltest::verbose\fR contains "p" or "s", it also prints +out a message if the test passed or was skipped. The test will be +skipped if it doesn't match the \fB::tcltest::match\fR variable, if it +matches an element in \fB::tcltest::skip\fR, or if one of the elements +of \fIconstraint\fR turns out not to be true. The +\fB::tcltest::test\fR command has no defined return values. See the +\fI"Writing a new test"\fR section for more details on this command. +.TP +\fB::tcltest::cleanupTests\fP \fI?runningMultipleTests?\fR +This command should be called at the end of a test file. It prints +statistics about the tests run and removes files that were created by +\fB::tcltest::makeDirectory\fR and \fB::tcltest::makeFile\fR. Names +of files and directories created outside of +\fB::tcltest::makeFile\fR and \fB::tcltest::makeDirectory\fR and +never deleted are printed to \fB::tcltest::outputChannel\fR. This command +also restores the original shell environment, as described by the ::env +array. \fIcalledFromAll\fR should be specified when +\fB::tcltest::cleanupTests\fR is called from an "all.tcl" file. Tcl files +files are generally used to run multiple tests. For more details on how to +run multiple tests, please see the section \fI"Running test files"\fR. +This proc has no defined return value. +.TP +\fB::tcltest::getMatchingTestFiles\fP +This command is used when you want to run multiple test files. It returns +the list of tests that should be sourced in an 'all.tcl' file. See the +section \fI"Running test files"\fR for more information. +.TP +\fB::tcltest::loadTestedCommands\fP +This command uses the script specified via the \fI-load\fR or +\fI-loadfile\fR to load the commands checked by the test suite. +Allowed to be empty, as the tested commands could have been compiled +into the interpreter running the test suite. +.TP +\fB::tcltest::makeFile\fP \fIcontents name\fR +Create a file that will be automatically be removed by +\fB::tcltest::cleanupTests\fR at the end of a test file. +This proc has no defined return value. +.TP +\fB::tcltest::removeFile\fP \fIname\fR +Force the file referenced by \fIname\fR to be removed. This file name +should be relative to \fI::tcltest::temporaryDirectory\fR. This proc has no +defined return values. +.TP +\fB::tcltest::makeDirectory\fP \fIname\fR +Create a directory named \fIname\fR that will automatically be removed +by \fB::tcltest::cleanupTests\fR at the end of a test file. This proc +has no defined return value. +.TP +\fB::tcltest::removeDirectory\fP \fIname\fR +Force the directory referenced by \fIname\fR to be removed. This proc +has no defined return value. +.TP +\fB::tcltest::viewFile\fP \fIfile\fR +Returns the contents of \fIfile\fR. +.TP +\fB::tcltest::normalizeMsg\fP \fImsg\fR +Remove extra newlines from \fImsg\fR. +.TP +\fB::tcltest::bytestring\fP \fIstring\fR +Construct a string that consists of the requested sequence of bytes, +as opposed to a string of properly formed UTF-8 characters using the +value supplied in \fIstring\fR. This allows the tester to create +denormalized or improperly formed strings to pass to C procedures that +are supposed to accept strings with embedded NULL types and confirm +that a string result has a certain pattern of bytes. +.TP +\fB::tcltest::saveState\fP +\fB::tcltest::restoreState\fP +Save and restore the procedure and global variable names. +A test file might contain calls to \fB::tcltest::saveState\fR and +\fB::tcltest:restoreState\fR if it creates or deletes global variables +or procs. +.TP +\fB::tcltest::threadReap\fP +\fB::tcltest::threadReap\fR only works if \fItestthread\fR is +defined, generally by compiling tcltest. If \fItestthread\fR is +defined, \fB::tcltest::threadReap\fR kills all threads except for the +main thread. It gets the ID of the main thread by calling +\fItestthread names\fR during initialization. This value is stored in +\fI::tcltest::mainThread\fR. \fB::tcltest::threadReap\fR returns the +number of existing threads at completion. +.SH TESTS +The \fBtest\fR procedure runs a test script and prints an error +message if the script's result does not match the expected result. +The following is the spec for the \fBtest\fR command: +.DS +test ??